From 8b04b2d11798dee4f3e1358e4f43e97a6df851f6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20CHAZALLET?= Date: Mon, 29 Oct 2012 10:03:45 +0100 Subject: [PATCH] Rajout de doctrine/orm --- composer.json | 3 +- vendor/bin/doctrine | 1 + vendor/bin/doctrine.php | 1 + vendor/doctrine/common/.gitignore | 4 + vendor/doctrine/common/.gitmodules | 3 + vendor/doctrine/common/.travis.yml | 10 + vendor/doctrine/common/LICENSE | 19 + vendor/doctrine/common/README.md | 12 + vendor/doctrine/common/UPGRADE_TO_2_1 | 39 + vendor/doctrine/common/UPGRADE_TO_2_2 | 61 + vendor/doctrine/common/bin/travis-setup.php | 141 + vendor/doctrine/common/build.properties | 6 + vendor/doctrine/common/build.xml | 59 + vendor/doctrine/common/composer.json | 26 + .../lib/Doctrine/Common/Annotations/Annotation.php | 79 + .../Common/Annotations/Annotation/Attribute.php | 47 + .../Common/Annotations/Annotation/Attributes.php | 37 + .../Annotations/Annotation/IgnoreAnnotation.php | 54 + .../Common/Annotations/Annotation/Required.php | 33 + .../Common/Annotations/Annotation/Target.php | 107 + .../Common/Annotations/AnnotationException.php | 127 + .../Common/Annotations/AnnotationReader.php | 310 ++ .../Common/Annotations/AnnotationRegistry.php | 139 + .../Doctrine/Common/Annotations/CachedReader.php | 250 ++ .../lib/Doctrine/Common/Annotations/DocLexer.php | 132 + .../lib/Doctrine/Common/Annotations/DocParser.php | 988 ++++++ .../Common/Annotations/FileCacheReader.php | 258 ++ .../Doctrine/Common/Annotations/IndexedReader.php | 141 + .../lib/Doctrine/Common/Annotations/PhpParser.php | 80 + .../lib/Doctrine/Common/Annotations/Reader.php | 67 + .../Common/Annotations/SimpleAnnotationReader.php | 157 + .../Doctrine/Common/Annotations/TokenParser.php | 175 ++ .../common/lib/Doctrine/Common/Cache/ApcCache.php | 93 + .../lib/Doctrine/Common/Cache/ArrayCache.php | 96 + .../common/lib/Doctrine/Common/Cache/Cache.php | 102 + .../lib/Doctrine/Common/Cache/CacheProvider.php | 231 ++ .../common/lib/Doctrine/Common/Cache/FileCache.php | 132 + .../lib/Doctrine/Common/Cache/FilesystemCache.php | 114 + .../lib/Doctrine/Common/Cache/MemcacheCache.php | 121 + .../lib/Doctrine/Common/Cache/MemcachedCache.php | 124 + .../lib/Doctrine/Common/Cache/PhpFileCache.php | 108 + .../lib/Doctrine/Common/Cache/RedisCache.php | 119 + .../lib/Doctrine/Common/Cache/WinCacheCache.php | 93 + .../lib/Doctrine/Common/Cache/XcacheCache.php | 110 + .../lib/Doctrine/Common/Cache/ZendDataCache.php | 84 + .../common/lib/Doctrine/Common/ClassLoader.php | 263 ++ .../Common/Collections/ArrayCollection.php | 500 ++++ .../lib/Doctrine/Common/Collections/Collection.php | 243 ++ .../lib/Doctrine/Common/Collections/Criteria.php | 240 ++ .../Collections/Expr/ClosureExpressionVisitor.php | 195 ++ .../Common/Collections/Expr/Comparison.php | 75 + .../Collections/Expr/CompositeExpression.php | 72 + .../Common/Collections/Expr/Expression.php | 31 + .../Common/Collections/Expr/ExpressionVisitor.php | 81 + .../lib/Doctrine/Common/Collections/Expr/Value.php | 41 + .../Common/Collections/ExpressionBuilder.php | 149 + .../lib/Doctrine/Common/Collections/Selectable.php | 48 + .../common/lib/Doctrine/Common/CommonException.php | 28 + .../common/lib/Doctrine/Common/Comparable.php | 49 + .../common/lib/Doctrine/Common/EventArgs.php | 67 + .../common/lib/Doctrine/Common/EventManager.php | 147 + .../common/lib/Doctrine/Common/EventSubscriber.php | 45 + .../doctrine/common/lib/Doctrine/Common/Lexer.php | 266 ++ .../lib/Doctrine/Common/NotifyPropertyChanged.php | 45 + .../Common/Persistence/AbstractManagerRegistry.php | 259 ++ .../Common/Persistence/ConnectionRegistry.php | 63 + .../Persistence/Event/LifecycleEventArgs.php | 77 + .../Event/LoadClassMetadataEventArgs.php | 76 + .../Common/Persistence/Event/ManagerEventArgs.php | 59 + .../Common/Persistence/Event/OnClearEventArgs.php | 84 + .../Persistence/Event/PreUpdateEventArgs.php | 133 + .../Common/Persistence/ManagerRegistry.php | 112 + .../Mapping/AbstractClassMetadataFactory.php | 383 +++ .../Common/Persistence/Mapping/ClassMetadata.php | 165 ++ .../Persistence/Mapping/ClassMetadataFactory.php | 74 + .../Mapping/Driver/AnnotationDriver.php | 214 ++ .../Mapping/Driver/DefaultFileLocator.php | 170 ++ .../Persistence/Mapping/Driver/FileDriver.php | 214 ++ .../Persistence/Mapping/Driver/FileLocator.php | 71 + .../Persistence/Mapping/Driver/MappingDriver.php | 56 + .../Mapping/Driver/MappingDriverChain.php | 168 ++ .../Persistence/Mapping/Driver/PHPDriver.php | 72 + .../Persistence/Mapping/Driver/StaticPHPDriver.php | 141 + .../Mapping/Driver/SymfonyFileLocator.php | 214 ++ .../Persistence/Mapping/MappingException.php | 86 + .../Persistence/Mapping/ReflectionService.php | 80 + .../Mapping/RuntimeReflectionService.php | 102 + .../Mapping/StaticReflectionService.php | 107 + .../Doctrine/Common/Persistence/ObjectManager.php | 152 + .../Common/Persistence/ObjectManagerAware.php | 49 + .../Common/Persistence/ObjectRepository.php | 78 + .../Common/Persistence/PersistentObject.php | 244 ++ .../lib/Doctrine/Common/Persistence/Proxy.php | 60 + .../Doctrine/Common/PropertyChangedListener.php | 48 + .../Common/Reflection/ClassFinderInterface.php | 38 + .../Doctrine/Common/Reflection/Psr0FindFile.php | 83 + .../Reflection/ReflectionProviderInterface.php | 45 + .../Common/Reflection/StaticReflectionClass.php | 112 + .../Common/Reflection/StaticReflectionMethod.php | 103 + .../Common/Reflection/StaticReflectionParser.php | 282 ++ .../Common/Reflection/StaticReflectionProperty.php | 77 + .../common/lib/Doctrine/Common/Util/ClassUtils.php | 103 + .../common/lib/Doctrine/Common/Util/Debug.php | 135 + .../common/lib/Doctrine/Common/Util/Inflector.php | 72 + .../common/lib/Doctrine/Common/Version.php | 55 + vendor/doctrine/common/phpunit.xml.dist | 31 + vendor/doctrine/common/tests/.gitignore | 3 + .../Common/Annotations/AbstractReaderTest.php | 517 ++++ .../Common/Annotations/AnnotationReaderTest.php | 13 + .../Tests/Common/Annotations/CachedReaderTest.php | 56 + .../Tests/Common/Annotations/DocLexerTest.php | 137 + .../Tests/Common/Annotations/DocParserTest.php | 1208 ++++++++ .../Tests/Common/Annotations/DummyClass.php | 48 + .../Common/Annotations/FileCacheReaderTest.php | 40 + .../Fixtures/Annotation/AnnotWithDefaultValue.php | 10 + .../Annotations/Fixtures/Annotation/Autoload.php | 10 + .../Annotations/Fixtures/Annotation/Route.php | 11 + .../Annotations/Fixtures/Annotation/Secure.php | 18 + .../Annotations/Fixtures/Annotation/Template.php | 14 + .../Annotations/Fixtures/Annotation/Version.php | 11 + .../Annotations/Fixtures/AnnotationTargetAll.php | 14 + .../Fixtures/AnnotationTargetAnnotation.php | 14 + .../Annotations/Fixtures/AnnotationTargetClass.php | 15 + .../Fixtures/AnnotationTargetMethod.php | 15 + .../Fixtures/AnnotationTargetPropertyMethod.php | 14 + .../Fixtures/AnnotationWithAttributes.php | 119 + .../Fixtures/AnnotationWithConstants.php | 20 + .../Fixtures/AnnotationWithRequiredAttributes.php | 50 + ...tionWithRequiredAttributesWithoutContructor.php | 24 + .../Fixtures/AnnotationWithTargetSyntaxError.php | 11 + .../Annotations/Fixtures/AnnotationWithVarType.php | 62 + .../Common/Annotations/Fixtures/ClassDDC1660.php | 30 + .../ClassWithAnnotationWithTargetSyntaxError.php | 21 + .../Fixtures/ClassWithAnnotationWithVarType.php | 31 + .../Annotations/Fixtures/ClassWithClosure.php | 52 + .../Annotations/Fixtures/ClassWithConstants.php | 10 + .../ClassWithFullyQualifiedUseStatements.php | 11 + .../ClassWithInvalidAnnotationTargetAtClass.php | 17 + .../ClassWithInvalidAnnotationTargetAtMethod.php | 20 + .../ClassWithInvalidAnnotationTargetAtProperty.php | 24 + .../Fixtures/ClassWithValidAnnotationTarget.php | 41 + .../Common/Annotations/Fixtures/Controller.php | 300 ++ .../DifferentNamespacesPerFileWithClassAsFirst.php | 15 + .../DifferentNamespacesPerFileWithClassAsLast.php | 15 + .../EqualNamespacesPerFileWithClassAsFirst.php | 13 + .../EqualNamespacesPerFileWithClassAsLast.php | 12 + .../GlobalNamespacesPerFileWithClassAsFirst.php | 12 + .../GlobalNamespacesPerFileWithClassAsLast.php | 12 + .../Annotations/Fixtures/IntefaceWithConstants.php | 10 + .../InvalidAnnotationUsageButIgnoredClass.php | 14 + .../Fixtures/InvalidAnnotationUsageClass.php | 10 + .../Annotations/Fixtures/MultipleClassesInFile.php | 9 + .../Fixtures/MultipleImportsInUseStatement.php | 10 + .../Fixtures/NamespaceAndClassCommentedOut.php | 20 + .../Fixtures/NamespaceWithClosureDeclaration.php | 15 + .../Fixtures/NamespacedSingleClassLOC1000.php | 1009 +++++++ .../Common/Annotations/Fixtures/NoAnnotation.php | 5 + .../Annotations/Fixtures/NonNamespacedClass.php | 10 + .../Annotations/Fixtures/SingleClassLOC1000.php | 1006 +++++++ .../Common/Annotations/Fixtures/TestInterface.php | 13 + .../Tests/Common/Annotations/PerformanceTest.php | 194 ++ .../Tests/Common/Annotations/PhpParserTest.php | 194 ++ .../Annotations/SimpleAnnotationReaderTest.php | 97 + .../Tests/Common/Annotations/Ticket/DCOM55Test.php | 65 + .../Common/Annotations/Ticket/DCOM58Entity.php | 8 + .../Tests/Common/Annotations/Ticket/DCOM58Test.php | 112 + .../Common/Annotations/TopLevelAnnotation.php | 8 + .../Doctrine/Tests/Common/Cache/ApcCacheTest.php | 20 + .../Doctrine/Tests/Common/Cache/ArrayCacheTest.php | 21 + .../Doctrine/Tests/Common/Cache/CacheTest.php | 91 + .../Tests/Common/Cache/FilesystemCacheTest.php | 97 + .../Tests/Common/Cache/MemcacheCacheTest.php | 45 + .../Tests/Common/Cache/MemcachedCacheTest.php | 48 + .../Tests/Common/Cache/PhpFileCacheTest.php | 149 + .../Doctrine/Tests/Common/Cache/RedisCacheTest.php | 30 + .../Tests/Common/Cache/WinCacheCacheTest.php | 20 + .../Tests/Common/Cache/XcacheCacheTest.php | 20 + .../Tests/Common/Cache/ZendDataCacheTest.php | 28 + .../Doctrine/Tests/Common/ClassLoaderTest.php | 45 + .../Tests/Common/ClassLoaderTest/ClassA.class.php | 6 + .../Tests/Common/ClassLoaderTest/ClassB.class.php | 6 + .../Tests/Common/ClassLoaderTest/ClassC.class.php | 6 + .../Tests/Common/ClassLoaderTest/ClassD.php | 5 + .../Collections/ClosureExpressionVisitorTest.php | 198 ++ .../Tests/Common/Collections/CollectionTest.php | 251 ++ .../Tests/Common/Collections/CriteriaTest.php | 82 + .../Common/Collections/ExpressionBuilderTest.php | 114 + .../Doctrine/Tests/Common/EventManagerTest.php | 88 + .../Common/Persistence/Mapping/ChainDriverTest.php | 130 + .../Mapping/ClassMetadataFactoryTest.php | 139 + .../Persistence/Mapping/DefaultFileLocatorTest.php | 90 + .../Common/Persistence/Mapping/FileDriverTest.php | 142 + .../Common/Persistence/Mapping/PHPDriverTest.php | 18 + .../Mapping/RuntimeReflectionServiceTest.php | 70 + .../Persistence/Mapping/StaticPHPDriverTest.php | 35 + .../Mapping/StaticReflectionServiceTest.php | 70 + .../Persistence/Mapping/SymfonyFileLocatorTest.php | 88 + .../Persistence/Mapping/_files/TestEntity.php | 3 + .../Common/Persistence/Mapping/_files/global.yml | 1 + .../Common/Persistence/Mapping/_files/stdClass.yml | 1 + .../Common/Persistence/PersistentObjectTest.php | 247 ++ .../Common/Reflection/DeeperNamespaceParent.php | 7 + .../Tests/Common/Reflection/Dummies/NoParent.php | 8 + .../Common/Reflection/FullyClassifiedParent.php | 7 + .../Doctrine/Tests/Common/Reflection/NoParent.php | 8 + .../Common/Reflection/SameNamespaceParent.php | 7 + .../Reflection/StaticReflectionParserTest.php | 45 + .../Doctrine/Tests/Common/Reflection/UseParent.php | 9 + .../Doctrine/Tests/Common/Util/ClassUtilsTest.php | 100 + .../tests/Doctrine/Tests/Common/Util/DebugTest.php | 27 + .../tests/Doctrine/Tests/DoctrineTestCase.php | 10 + .../common/tests/Doctrine/Tests/TestInit.php | 31 + vendor/doctrine/common/tests/NativePhpunitTask.php | 246 ++ vendor/doctrine/common/tests/README.markdown | 27 + vendor/doctrine/dbal/.gitignore | 6 + vendor/doctrine/dbal/.gitmodules | 9 + vendor/doctrine/dbal/.travis.yml | 22 + vendor/doctrine/dbal/LICENSE | 19 + vendor/doctrine/dbal/README.md | 14 + vendor/doctrine/dbal/UPGRADE | 148 + vendor/doctrine/dbal/bin/doctrine-dbal | 4 + vendor/doctrine/dbal/bin/doctrine-dbal.php | 43 + vendor/doctrine/dbal/bin/doctrine.php | 42 + vendor/doctrine/dbal/build.properties | 10 + vendor/doctrine/dbal/build.xml | 91 + vendor/doctrine/dbal/composer.json | 26 + .../doctrine/dbal/docs/design/AZURE_FEDERATIONS.md | 94 + vendor/doctrine/dbal/docs/design/SHARDING.md | 74 + .../doctrine/dbal/docs/examples/sharding/README.md | 26 + .../dbal/docs/examples/sharding/bootstrap.php | 26 + .../dbal/docs/examples/sharding/composer.json | 6 + .../dbal/docs/examples/sharding/create_schema.php | 51 + .../dbal/docs/examples/sharding/insert_data.php | 132 + .../examples/sharding/insert_data_aftersplit.php | 27 + .../docs/examples/sharding/query_filtering_off.php | 8 + .../docs/examples/sharding/query_filtering_on.php | 9 + .../docs/examples/sharding/split_federation.php | 5 + .../examples/sharding/view_federation_members.php | 8 + .../lib/Doctrine/DBAL/Cache/ArrayStatement.php | 103 + .../lib/Doctrine/DBAL/Cache/CacheException.php | 37 + .../lib/Doctrine/DBAL/Cache/QueryCacheProfile.php | 131 + .../Doctrine/DBAL/Cache/ResultCacheStatement.php | 239 ++ .../dbal/lib/Doctrine/DBAL/Configuration.php | 113 + .../doctrine/dbal/lib/Doctrine/DBAL/Connection.php | 1308 ++++++++ .../dbal/lib/Doctrine/DBAL/ConnectionException.php | 54 + .../DBAL/Connections/MasterSlaveConnection.php | 353 +++ .../dbal/lib/Doctrine/DBAL/DBALException.php | 106 + vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver.php | 72 + .../dbal/lib/Doctrine/DBAL/Driver/Connection.php | 42 + .../DBAL/Driver/DrizzlePDOMySql/Connection.php | 41 + .../DBAL/Driver/DrizzlePDOMySql/Driver.php | 99 + .../Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php | 115 + .../lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php | 111 + .../Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php | 27 + .../Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php | 214 ++ .../lib/Doctrine/DBAL/Driver/Mysqli/Driver.php | 69 + .../DBAL/Driver/Mysqli/MysqliConnection.php | 146 + .../DBAL/Driver/Mysqli/MysqliException.php | 26 + .../DBAL/Driver/Mysqli/MysqliStatement.php | 342 +++ .../dbal/lib/Doctrine/DBAL/Driver/OCI8/Driver.php | 99 + .../Doctrine/DBAL/Driver/OCI8/OCI8Connection.php | 200 ++ .../Doctrine/DBAL/Driver/OCI8/OCI8Exception.php | 30 + .../Doctrine/DBAL/Driver/OCI8/OCI8Statement.php | 268 ++ .../lib/Doctrine/DBAL/Driver/PDOConnection.php | 40 + .../lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php | 126 + .../lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php | 102 + .../lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php | 98 + .../lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php | 70 + .../lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php | 116 + .../Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php | 45 + .../lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php | 87 + .../dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php | 50 + .../lib/Doctrine/DBAL/Driver/ResultStatement.php | 93 + .../lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php | 72 + .../Doctrine/DBAL/Driver/SQLSrv/LastInsertId.php | 42 + .../DBAL/Driver/SQLSrv/SQLSrvConnection.php | 161 + .../DBAL/Driver/SQLSrv/SQLSrvException.php | 43 + .../DBAL/Driver/SQLSrv/SQLSrvStatement.php | 251 ++ .../dbal/lib/Doctrine/DBAL/Driver/Statement.php | 125 + .../dbal/lib/Doctrine/DBAL/DriverManager.php | 176 ++ .../Doctrine/DBAL/Event/ConnectionEventArgs.php | 79 + .../DBAL/Event/Listeners/MysqlSessionInit.php | 74 + .../DBAL/Event/Listeners/OracleSessionInit.php | 80 + .../DBAL/Event/Listeners/SQLSessionInit.php | 63 + .../Event/SchemaAlterTableAddColumnEventArgs.php | 114 + .../SchemaAlterTableChangeColumnEventArgs.php | 114 + .../DBAL/Event/SchemaAlterTableEventArgs.php | 99 + .../SchemaAlterTableRemoveColumnEventArgs.php | 114 + .../SchemaAlterTableRenameColumnEventArgs.php | 129 + .../DBAL/Event/SchemaColumnDefinitionEventArgs.php | 137 + .../Event/SchemaCreateTableColumnEventArgs.php | 114 + .../DBAL/Event/SchemaCreateTableEventArgs.php | 128 + .../DBAL/Event/SchemaDropTableEventArgs.php | 98 + .../lib/Doctrine/DBAL/Event/SchemaEventArgs.php | 56 + .../DBAL/Event/SchemaIndexDefinitionEventArgs.php | 122 + vendor/doctrine/dbal/lib/Doctrine/DBAL/Events.php | 48 + .../dbal/lib/Doctrine/DBAL/Id/TableGenerator.php | 160 + .../DBAL/Id/TableGeneratorSchemaVisitor.php | 90 + .../doctrine/dbal/lib/Doctrine/DBAL/LockMode.php | 42 + .../dbal/lib/Doctrine/DBAL/Logging/DebugStack.php | 69 + .../lib/Doctrine/DBAL/Logging/EchoSQLLogger.php | 61 + .../dbal/lib/Doctrine/DBAL/Logging/LoggerChain.php | 64 + .../dbal/lib/Doctrine/DBAL/Logging/SQLLogger.php | 54 + .../Doctrine/DBAL/Platforms/AbstractPlatform.php | 2854 ++++++++++++++++++ .../lib/Doctrine/DBAL/Platforms/DB2Platform.php | 545 ++++ .../Doctrine/DBAL/Platforms/DrizzlePlatform.php | 495 ++++ .../DBAL/Platforms/Keywords/DB2Keywords.php | 438 +++ .../DBAL/Platforms/Keywords/DrizzleKeywords.php | 340 +++ .../DBAL/Platforms/Keywords/KeywordList.php | 63 + .../DBAL/Platforms/Keywords/MsSQLKeywords.php | 243 ++ .../DBAL/Platforms/Keywords/MySQLKeywords.php | 268 ++ .../DBAL/Platforms/Keywords/OracleKeywords.php | 156 + .../DBAL/Platforms/Keywords/PostgreSQLKeywords.php | 131 + .../Keywords/ReservedKeywordsValidator.php | 116 + .../DBAL/Platforms/Keywords/SQLiteKeywords.php | 164 + .../lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 720 +++++ .../lib/Doctrine/DBAL/Platforms/OraclePlatform.php | 822 +++++ .../Doctrine/DBAL/Platforms/PostgreSqlPlatform.php | 762 +++++ .../Doctrine/DBAL/Platforms/SQLAzurePlatform.php | 51 + .../DBAL/Platforms/SQLServer2005Platform.php | 54 + .../DBAL/Platforms/SQLServer2008Platform.php | 100 + .../Doctrine/DBAL/Platforms/SQLServerPlatform.php | 905 ++++++ .../lib/Doctrine/DBAL/Platforms/SqlitePlatform.php | 529 ++++ .../lib/Doctrine/DBAL/Portability/Connection.php | 119 + .../lib/Doctrine/DBAL/Portability/Statement.php | 195 ++ .../DBAL/Query/Expression/CompositeExpression.php | 130 + .../DBAL/Query/Expression/ExpressionBuilder.php | 264 ++ .../dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php | 1087 +++++++ .../lib/Doctrine/DBAL/Query/QueryException.php | 40 + .../dbal/lib/Doctrine/DBAL/SQLParserUtils.php | 183 ++ .../lib/Doctrine/DBAL/Schema/AbstractAsset.php | 214 ++ .../Doctrine/DBAL/Schema/AbstractSchemaManager.php | 896 ++++++ .../dbal/lib/Doctrine/DBAL/Schema/Column.php | 423 +++ .../dbal/lib/Doctrine/DBAL/Schema/ColumnDiff.php | 58 + .../dbal/lib/Doctrine/DBAL/Schema/Comparator.php | 415 +++ .../dbal/lib/Doctrine/DBAL/Schema/Constraint.php | 42 + .../lib/Doctrine/DBAL/Schema/DB2SchemaManager.php | 214 ++ .../Doctrine/DBAL/Schema/DrizzleSchemaManager.php | 96 + .../Doctrine/DBAL/Schema/ForeignKeyConstraint.php | 193 ++ .../dbal/lib/Doctrine/DBAL/Schema/Index.php | 242 ++ .../Doctrine/DBAL/Schema/MySqlSchemaManager.php | 208 ++ .../Doctrine/DBAL/Schema/OracleSchemaManager.php | 286 ++ .../DBAL/Schema/PostgreSqlSchemaManager.php | 359 +++ .../DBAL/Schema/SQLServerSchemaManager.php | 263 ++ .../dbal/lib/Doctrine/DBAL/Schema/Schema.php | 373 +++ .../dbal/lib/Doctrine/DBAL/Schema/SchemaConfig.php | 119 + .../dbal/lib/Doctrine/DBAL/Schema/SchemaDiff.php | 176 ++ .../lib/Doctrine/DBAL/Schema/SchemaException.php | 126 + .../dbal/lib/Doctrine/DBAL/Schema/Sequence.php | 120 + .../Doctrine/DBAL/Schema/SqliteSchemaManager.php | 190 ++ .../Synchronizer/AbstractSchemaSynchronizer.php | 58 + .../Schema/Synchronizer/SchemaSynchronizer.php | 96 + .../Synchronizer/SingleDatabaseSynchronizer.php | 197 ++ .../dbal/lib/Doctrine/DBAL/Schema/Table.php | 678 +++++ .../dbal/lib/Doctrine/DBAL/Schema/TableDiff.php | 136 + .../dbal/lib/Doctrine/DBAL/Schema/View.php | 53 + .../Schema/Visitor/CreateSchemaSqlCollector.php | 178 ++ .../DBAL/Schema/Visitor/DropSchemaSqlCollector.php | 160 + .../lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php | 151 + .../DBAL/Schema/Visitor/RemoveNamespacedAssets.php | 113 + .../lib/Doctrine/DBAL/Schema/Visitor/Visitor.php | 75 + .../DBAL/Sharding/PoolingShardConnection.php | 201 ++ .../Doctrine/DBAL/Sharding/PoolingShardManager.php | 98 + .../SQLAzure/SQLAzureFederationsSynchronizer.php | 296 ++ .../Sharding/SQLAzure/SQLAzureShardManager.php | 238 ++ .../SQLAzure/Schema/MultiTenantVisitor.php | 161 + .../ShardChoser/MultiTenantShardChoser.php | 37 + .../DBAL/Sharding/ShardChoser/ShardChoser.php | 41 + .../lib/Doctrine/DBAL/Sharding/ShardManager.php | 95 + .../Doctrine/DBAL/Sharding/ShardingException.php | 61 + .../doctrine/dbal/lib/Doctrine/DBAL/Statement.php | 264 ++ .../DBAL/Tools/Console/Command/ImportCommand.php | 124 + .../Tools/Console/Command/ReservedWordsCommand.php | 133 + .../DBAL/Tools/Console/Command/RunSqlCommand.php | 87 + .../DBAL/Tools/Console/Helper/ConnectionHelper.php | 74 + .../dbal/lib/Doctrine/DBAL/Types/ArrayType.php | 64 + .../dbal/lib/Doctrine/DBAL/Types/BigIntType.php | 56 + .../dbal/lib/Doctrine/DBAL/Types/BlobType.php | 67 + .../dbal/lib/Doctrine/DBAL/Types/BooleanType.php | 57 + .../Doctrine/DBAL/Types/ConversionException.php | 65 + .../dbal/lib/Doctrine/DBAL/Types/DateTimeType.php | 59 + .../lib/Doctrine/DBAL/Types/DateTimeTzType.php | 79 + .../dbal/lib/Doctrine/DBAL/Types/DateType.php | 59 + .../dbal/lib/Doctrine/DBAL/Types/DecimalType.php | 45 + .../dbal/lib/Doctrine/DBAL/Types/FloatType.php | 54 + .../dbal/lib/Doctrine/DBAL/Types/GuidType.php | 42 + .../dbal/lib/Doctrine/DBAL/Types/IntegerType.php | 53 + .../dbal/lib/Doctrine/DBAL/Types/JsonArrayType.php | 66 + .../dbal/lib/Doctrine/DBAL/Types/ObjectType.php | 64 + .../lib/Doctrine/DBAL/Types/SimpleArrayType.php | 69 + .../dbal/lib/Doctrine/DBAL/Types/SmallIntType.php | 52 + .../dbal/lib/Doctrine/DBAL/Types/StringType.php | 50 + .../dbal/lib/Doctrine/DBAL/Types/TextType.php | 56 + .../dbal/lib/Doctrine/DBAL/Types/TimeType.php | 68 + .../doctrine/dbal/lib/Doctrine/DBAL/Types/Type.php | 306 ++ .../lib/Doctrine/DBAL/Types/VarDateTimeType.php | 60 + vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php | 55 + vendor/doctrine/dbal/phpunit.xml.dist | 51 + vendor/doctrine/dbal/run-all.sh | 21 + vendor/doctrine/dbal/tests/.gitignore | 3 + .../tests/Doctrine/Tests/DBAL/ConnectionTest.php | 177 ++ .../Tests/DBAL/Driver/OCI8/OCI8StatementTest.php | 82 + .../Doctrine/Tests/DBAL/DriverManagerTest.php | 117 + .../Tests/DBAL/Events/MysqlSessionInitTest.php | 33 + .../Tests/DBAL/Events/OracleSessionInitTest.php | 33 + .../Tests/DBAL/Events/SQLSessionInitTest.php | 35 + .../Doctrine/Tests/DBAL/Functional/BlobTest.php | 83 + .../Tests/DBAL/Functional/ConnectionTest.php | 219 ++ .../Tests/DBAL/Functional/DataAccessTest.php | 543 ++++ .../Doctrine/Tests/DBAL/Functional/LoggingTest.php | 52 + .../DBAL/Functional/MasterSlaveConnectionTest.php | 102 + .../Tests/DBAL/Functional/ModifyLimitQueryTest.php | 114 + .../Tests/DBAL/Functional/NamedParametersTest.php | 166 ++ .../Tests/DBAL/Functional/PortabilityTest.php | 97 + .../Tests/DBAL/Functional/ResultCacheTest.php | 208 ++ .../Functional/Schema/Db2SchemaManagerTest.php | 12 + .../Functional/Schema/DrizzleSchemaManagerTest.php | 12 + .../Functional/Schema/MySqlSchemaManagerTest.php | 50 + .../Functional/Schema/OracleSchemaManagerTest.php | 39 + .../Schema/PostgreSqlSchemaManagerTest.php | 262 ++ .../Schema/SQLServerSchemaManagerTest.php | 37 + .../Schema/SchemaManagerFunctionalTestCase.php | 647 ++++ .../Functional/Schema/SqliteSchemaManagerTest.php | 46 + .../Tests/DBAL/Functional/TableGeneratorTest.php | 59 + .../Tests/DBAL/Functional/TemporaryTableTest.php | 102 + .../Tests/DBAL/Functional/Ticket/DBAL168Test.php | 27 + .../Tests/DBAL/Functional/Ticket/DBAL202Test.php | 48 + .../Tests/DBAL/Functional/TypeConversionTest.php | 101 + .../Doctrine/Tests/DBAL/Functional/WriteTest.php | 185 ++ .../Doctrine/Tests/DBAL/Logging/DebugStackTest.php | 47 + .../Doctrine/Tests/DBAL/Mocks/MockPlatform.php | 49 + .../DBAL/Platforms/AbstractPlatformTestCase.php | 388 +++ .../Tests/DBAL/Platforms/MySqlPlatformTest.php | 229 ++ .../Tests/DBAL/Platforms/OraclePlatformTest.php | 272 ++ .../DBAL/Platforms/PostgreSqlPlatformTest.php | 228 ++ .../Platforms/ReservedKeywordsValidatorTest.php | 47 + .../Tests/DBAL/Platforms/SQLAzurePlatformTest.php | 29 + .../Tests/DBAL/Platforms/SQLServerPlatformTest.php | 224 ++ .../Tests/DBAL/Platforms/SqlitePlatformTest.php | 155 + .../Query/Expression/CompositeExpressionTest.php | 82 + .../Query/Expression/ExpressionBuilderTest.php | 201 ++ .../Doctrine/Tests/DBAL/Query/QueryBuilderTest.php | 572 ++++ .../Doctrine/Tests/DBAL/SQLParserUtilsTest.php | 250 ++ .../Doctrine/Tests/DBAL/Schema/ColumnTest.php | 114 + .../Doctrine/Tests/DBAL/Schema/ComparatorTest.php | 809 +++++ .../tests/Doctrine/Tests/DBAL/Schema/IndexTest.php | 115 + .../Tests/DBAL/Schema/MySqlSchemaManagerTest.php | 74 + .../DBAL/Schema/Platforms/MySQLSchemaTest.php | 88 + .../Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php | 109 + .../Doctrine/Tests/DBAL/Schema/SchemaTest.php | 224 ++ .../Doctrine/Tests/DBAL/Schema/SequenceTest.php | 28 + .../SingleDatabaseSynchronizerTest.php | 88 + .../tests/Doctrine/Tests/DBAL/Schema/TableTest.php | 528 ++++ .../Schema/Visitor/RemoveNamespacedAssetsTest.php | 77 + .../DBAL/Schema/Visitor/SchemaSqlCollectorTest.php | 80 + .../DBAL/Sharding/PoolingShardConnectionTest.php | 182 ++ .../DBAL/Sharding/PoolingShardManagerTest.php | 108 + .../DBAL/Sharding/SQLAzure/AbstractTestCase.php | 82 + .../DBAL/Sharding/SQLAzure/FunctionalTest.php | 44 + .../Sharding/SQLAzure/MultiTenantVisitorTest.php | 65 + .../SQLAzureFederationsSynchronizerTest.php | 50 + .../Sharding/SQLAzure/SQLAzureShardManagerTest.php | 93 + .../ShardChoser/MultiTenantShardChoserTest.php | 40 + .../tests/Doctrine/Tests/DBAL/Types/ArrayTest.php | 61 + .../tests/Doctrine/Tests/DBAL/Types/BlobTest.php | 26 + .../Doctrine/Tests/DBAL/Types/BooleanTest.php | 36 + .../tests/Doctrine/Tests/DBAL/Types/DateTest.php | 81 + .../Doctrine/Tests/DBAL/Types/DateTimeTest.php | 56 + .../Doctrine/Tests/DBAL/Types/DateTimeTzTest.php | 56 + .../Doctrine/Tests/DBAL/Types/DecimalTest.php | 31 + .../tests/Doctrine/Tests/DBAL/Types/FloatTest.php | 39 + .../Doctrine/Tests/DBAL/Types/GuidTypeTest.php | 31 + .../Doctrine/Tests/DBAL/Types/IntegerTest.php | 32 + .../tests/Doctrine/Tests/DBAL/Types/ObjectTest.php | 56 + .../Doctrine/Tests/DBAL/Types/SmallIntTest.php | 32 + .../tests/Doctrine/Tests/DBAL/Types/StringTest.php | 49 + .../tests/Doctrine/Tests/DBAL/Types/TimeTest.php | 53 + .../Doctrine/Tests/DBAL/Types/VarDateTimeTest.php | 68 + .../dbal/tests/Doctrine/Tests/DBAL/UtilTest.php | 78 + .../Doctrine/Tests/DbalFunctionalTestCase.php | 77 + .../dbal/tests/Doctrine/Tests/DbalTestCase.php | 10 + .../dbal/tests/Doctrine/Tests/DoctrineTestCase.php | 10 + .../tests/Doctrine/Tests/Mocks/ConnectionMock.php | 92 + .../Doctrine/Tests/Mocks/DatabasePlatformMock.php | 98 + .../Doctrine/Tests/Mocks/DriverConnectionMock.php | 17 + .../dbal/tests/Doctrine/Tests/Mocks/DriverMock.php | 72 + .../Doctrine/Tests/Mocks/HydratorMockStatement.php | 101 + .../Doctrine/Tests/Mocks/SchemaManagerMock.php | 13 + .../dbal/tests/Doctrine/Tests/Mocks/TaskMock.php | 81 + .../dbal/tests/Doctrine/Tests/TestInit.php | 22 + .../dbal/tests/Doctrine/Tests/TestUtil.php | 130 + vendor/doctrine/dbal/tests/README.markdown | 25 + vendor/doctrine/dbal/tests/travis/mysql.travis.xml | 32 + .../doctrine/dbal/tests/travis/mysqli.travis.xml | 32 + vendor/doctrine/dbal/tests/travis/pgsql.travis.xml | 29 + .../doctrine/dbal/tests/travis/sqlite.travis.xml | 14 + vendor/doctrine/orm/.gitignore | 11 + vendor/doctrine/orm/.gitmodules | 15 + vendor/doctrine/orm/.travis.yml | 19 + vendor/doctrine/orm/LICENSE | 19 + vendor/doctrine/orm/README.markdown | 19 + vendor/doctrine/orm/UPGRADE.md | 467 +++ vendor/doctrine/orm/bin/doctrine | 4 + vendor/doctrine/orm/bin/doctrine-pear.php | 50 + vendor/doctrine/orm/bin/doctrine.bat | 9 + vendor/doctrine/orm/bin/doctrine.php | 43 + vendor/doctrine/orm/build.properties | 11 + vendor/doctrine/orm/build.properties.dev | 16 + vendor/doctrine/orm/build.xml | 114 + vendor/doctrine/orm/composer.json | 32 + vendor/doctrine/orm/doctrine-mapping.xsd | 519 ++++ .../orm/lib/Doctrine/ORM/AbstractQuery.php | 825 ++++++ .../orm/lib/Doctrine/ORM/Configuration.php | 683 +++++ .../orm/lib/Doctrine/ORM/EntityManager.php | 902 ++++++ .../lib/Doctrine/ORM/EntityNotFoundException.php | 34 + .../orm/lib/Doctrine/ORM/EntityRepository.php | 276 ++ .../lib/Doctrine/ORM/Event/LifecycleEventArgs.php | 77 + .../ORM/Event/LoadClassMetadataEventArgs.php | 76 + .../lib/Doctrine/ORM/Event/OnClearEventArgs.php | 84 + .../lib/Doctrine/ORM/Event/OnFlushEventArgs.php | 84 + .../lib/Doctrine/ORM/Event/PostFlushEventArgs.php | 58 + .../lib/Doctrine/ORM/Event/PreFlushEventArgs.php | 50 + .../lib/Doctrine/ORM/Event/PreUpdateEventArgs.php | 129 + vendor/doctrine/orm/lib/Doctrine/ORM/Events.php | 146 + .../lib/Doctrine/ORM/Id/AbstractIdGenerator.php | 48 + .../orm/lib/Doctrine/ORM/Id/AssignedGenerator.php | 70 + .../orm/lib/Doctrine/ORM/Id/IdentityGenerator.php | 59 + .../orm/lib/Doctrine/ORM/Id/SequenceGenerator.php | 106 + .../orm/lib/Doctrine/ORM/Id/TableGenerator.php | 81 + .../orm/lib/Doctrine/ORM/Id/UuidGenerator.php | 48 + .../ORM/Internal/CommitOrderCalculator.php | 118 + .../ORM/Internal/Hydration/AbstractHydrator.php | 390 +++ .../ORM/Internal/Hydration/ArrayHydrator.php | 289 ++ .../ORM/Internal/Hydration/HydrationException.php | 56 + .../ORM/Internal/Hydration/IterableResult.php | 104 + .../ORM/Internal/Hydration/ObjectHydrator.php | 551 ++++ .../ORM/Internal/Hydration/ScalarHydrator.php | 55 + .../Internal/Hydration/SimpleObjectHydrator.php | 187 ++ .../Internal/Hydration/SingleScalarHydrator.php | 56 + .../orm/lib/Doctrine/ORM/Mapping/Annotation.php | 24 + .../Doctrine/ORM/Mapping/AssociationOverride.php | 56 + .../Doctrine/ORM/Mapping/AssociationOverrides.php | 41 + .../lib/Doctrine/ORM/Mapping/AttributeOverride.php | 47 + .../Doctrine/ORM/Mapping/AttributeOverrides.php | 41 + .../ORM/Mapping/Builder/AssociationBuilder.php | 167 ++ .../ORM/Mapping/Builder/ClassMetadataBuilder.php | 470 +++ .../Doctrine/ORM/Mapping/Builder/FieldBuilder.php | 223 ++ .../Builder/ManyToManyAssociationBuilder.php | 86 + .../Builder/OneToManyAssociationBuilder.php | 62 + .../Doctrine/ORM/Mapping/ChangeTrackingPolicy.php | 30 + .../orm/lib/Doctrine/ORM/Mapping/ClassMetadata.php | 29 + .../Doctrine/ORM/Mapping/ClassMetadataFactory.php | 537 ++++ .../lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php | 2814 ++++++++++++++++++ .../orm/lib/Doctrine/ORM/Mapping/Column.php | 46 + .../orm/lib/Doctrine/ORM/Mapping/ColumnResult.php | 42 + .../lib/Doctrine/ORM/Mapping/CustomIdGenerator.php | 30 + .../Doctrine/ORM/Mapping/DefaultNamingStrategy.php | 86 + .../Doctrine/ORM/Mapping/DefaultQuoteStrategy.php | 140 + .../Doctrine/ORM/Mapping/DiscriminatorColumn.php | 38 + .../lib/Doctrine/ORM/Mapping/DiscriminatorMap.php | 30 + .../ORM/Mapping/Driver/AnnotationDriver.php | 555 ++++ .../Doctrine/ORM/Mapping/Driver/DatabaseDriver.php | 411 +++ .../ORM/Mapping/Driver/DoctrineAnnotations.php | 66 + .../Doctrine/ORM/Mapping/Driver/DriverChain.php | 31 + .../lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php | 31 + .../ORM/Mapping/Driver/SimplifiedXmlDriver.php | 43 + .../ORM/Mapping/Driver/SimplifiedYamlDriver.php | 43 + .../ORM/Mapping/Driver/StaticPHPDriver.php | 31 + .../lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php | 713 +++++ .../lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php | 681 +++++ .../lib/Doctrine/ORM/Mapping/ElementCollection.php | 31 + .../orm/lib/Doctrine/ORM/Mapping/Entity.php | 32 + .../orm/lib/Doctrine/ORM/Mapping/EntityResult.php | 58 + .../orm/lib/Doctrine/ORM/Mapping/FieldResult.php | 48 + .../lib/Doctrine/ORM/Mapping/GeneratedValue.php | 30 + .../Doctrine/ORM/Mapping/HasLifecycleCallbacks.php | 28 + .../doctrine/orm/lib/Doctrine/ORM/Mapping/Id.php | 28 + .../orm/lib/Doctrine/ORM/Mapping/Index.php | 32 + .../lib/Doctrine/ORM/Mapping/InheritanceType.php | 30 + .../orm/lib/Doctrine/ORM/Mapping/JoinColumn.php | 42 + .../orm/lib/Doctrine/ORM/Mapping/JoinColumns.php | 30 + .../orm/lib/Doctrine/ORM/Mapping/JoinTable.php | 36 + .../orm/lib/Doctrine/ORM/Mapping/ManyToMany.php | 42 + .../orm/lib/Doctrine/ORM/Mapping/ManyToOne.php | 36 + .../lib/Doctrine/ORM/Mapping/MappedSuperclass.php | 30 + .../lib/Doctrine/ORM/Mapping/MappingException.php | 441 +++ .../Doctrine/ORM/Mapping/NamedNativeQueries.php | 40 + .../lib/Doctrine/ORM/Mapping/NamedNativeQuery.php | 63 + .../orm/lib/Doctrine/ORM/Mapping/NamedQueries.php | 30 + .../orm/lib/Doctrine/ORM/Mapping/NamedQuery.php | 32 + .../lib/Doctrine/ORM/Mapping/NamingStrategy.php | 82 + .../orm/lib/Doctrine/ORM/Mapping/OneToMany.php | 40 + .../orm/lib/Doctrine/ORM/Mapping/OneToOne.php | 40 + .../orm/lib/Doctrine/ORM/Mapping/OrderBy.php | 30 + .../orm/lib/Doctrine/ORM/Mapping/PostLoad.php | 28 + .../orm/lib/Doctrine/ORM/Mapping/PostPersist.php | 28 + .../orm/lib/Doctrine/ORM/Mapping/PostRemove.php | 28 + .../orm/lib/Doctrine/ORM/Mapping/PostUpdate.php | 28 + .../orm/lib/Doctrine/ORM/Mapping/PreFlush.php | 28 + .../orm/lib/Doctrine/ORM/Mapping/PrePersist.php | 28 + .../orm/lib/Doctrine/ORM/Mapping/PreRemove.php | 28 + .../orm/lib/Doctrine/ORM/Mapping/PreUpdate.php | 28 + .../orm/lib/Doctrine/ORM/Mapping/QuoteStrategy.php | 112 + .../lib/Doctrine/ORM/Mapping/SequenceGenerator.php | 34 + .../Doctrine/ORM/Mapping/SqlResultSetMapping.php | 56 + .../Doctrine/ORM/Mapping/SqlResultSetMappings.php | 40 + .../orm/lib/Doctrine/ORM/Mapping/Table.php | 38 + .../ORM/Mapping/UnderscoreNamingStrategy.php | 135 + .../lib/Doctrine/ORM/Mapping/UniqueConstraint.php | 32 + .../orm/lib/Doctrine/ORM/Mapping/Version.php | 28 + .../doctrine/orm/lib/Doctrine/ORM/NativeQuery.php | 87 + .../orm/lib/Doctrine/ORM/NoResultException.php | 34 + .../lib/Doctrine/ORM/NonUniqueResultException.php | 31 + .../doctrine/orm/lib/Doctrine/ORM/ORMException.php | 167 ++ .../Doctrine/ORM/ORMInvalidArgumentException.php | 115 + .../lib/Doctrine/ORM/OptimisticLockException.php | 64 + .../orm/lib/Doctrine/ORM/PersistentCollection.php | 838 ++++++ .../ORM/Persisters/AbstractCollectionPersister.php | 223 ++ .../AbstractEntityInheritancePersister.php | 83 + .../ORM/Persisters/BasicEntityPersister.php | 1791 +++++++++++ .../ORM/Persisters/ElementCollectionPersister.php | 30 + .../ORM/Persisters/JoinedSubclassPersister.php | 492 +++ .../ORM/Persisters/ManyToManyPersister.php | 446 +++ .../Doctrine/ORM/Persisters/OneToManyPersister.php | 212 ++ .../ORM/Persisters/SingleTablePersister.php | 163 + .../ORM/Persisters/SqlExpressionVisitor.php | 102 + .../Doctrine/ORM/Persisters/SqlValueVisitor.php | 100 + .../ORM/Persisters/UnionSubclassPersister.php | 8 + .../lib/Doctrine/ORM/PessimisticLockException.php | 37 + .../orm/lib/Doctrine/ORM/Proxy/Autoloader.php | 78 + .../doctrine/orm/lib/Doctrine/ORM/Proxy/Proxy.php | 30 + .../orm/lib/Doctrine/ORM/Proxy/ProxyException.php | 52 + .../orm/lib/Doctrine/ORM/Proxy/ProxyFactory.php | 410 +++ vendor/doctrine/orm/lib/Doctrine/ORM/Query.php | 626 ++++ .../lib/Doctrine/ORM/Query/AST/ASTException.php | 33 + .../Doctrine/ORM/Query/AST/AggregateExpression.php | 49 + .../ORM/Query/AST/ArithmeticExpression.php | 51 + .../Doctrine/ORM/Query/AST/ArithmeticFactor.php | 64 + .../lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php | 45 + .../Doctrine/ORM/Query/AST/BetweenExpression.php | 51 + .../Doctrine/ORM/Query/AST/CoalesceExpression.php | 47 + .../ORM/Query/AST/CollectionMemberExpression.php | 49 + .../ORM/Query/AST/ComparisonExpression.php | 54 + .../ORM/Query/AST/ConditionalExpression.php | 45 + .../Doctrine/ORM/Query/AST/ConditionalFactor.php | 46 + .../Doctrine/ORM/Query/AST/ConditionalPrimary.php | 51 + .../lib/Doctrine/ORM/Query/AST/ConditionalTerm.php | 44 + .../lib/Doctrine/ORM/Query/AST/DeleteClause.php | 47 + .../lib/Doctrine/ORM/Query/AST/DeleteStatement.php | 46 + .../AST/EmptyCollectionComparisonExpression.php | 47 + .../Doctrine/ORM/Query/AST/ExistsExpression.php | 47 + .../orm/lib/Doctrine/ORM/Query/AST/FromClause.php | 45 + .../ORM/Query/AST/Functions/AbsFunction.php | 62 + .../ORM/Query/AST/Functions/BitAndFunction.php | 63 + .../ORM/Query/AST/Functions/BitOrFunction.php | 63 + .../ORM/Query/AST/Functions/ConcatFunction.php | 67 + .../Query/AST/Functions/CurrentDateFunction.php | 54 + .../Query/AST/Functions/CurrentTimeFunction.php | 54 + .../AST/Functions/CurrentTimestampFunction.php | 54 + .../ORM/Query/AST/Functions/DateAddFunction.php | 77 + .../ORM/Query/AST/Functions/DateDiffFunction.php | 58 + .../ORM/Query/AST/Functions/DateSubFunction.php | 57 + .../ORM/Query/AST/Functions/FunctionNode.php | 52 + .../ORM/Query/AST/Functions/IdentityFunction.php | 67 + .../ORM/Query/AST/Functions/LengthFunction.php | 62 + .../ORM/Query/AST/Functions/LocateFunction.php | 81 + .../ORM/Query/AST/Functions/LowerFunction.php | 62 + .../ORM/Query/AST/Functions/ModFunction.php | 68 + .../ORM/Query/AST/Functions/SizeFunction.php | 121 + .../ORM/Query/AST/Functions/SqrtFunction.php | 62 + .../ORM/Query/AST/Functions/SubstringFunction.php | 82 + .../ORM/Query/AST/Functions/TrimFunction.php | 100 + .../ORM/Query/AST/Functions/UpperFunction.php | 62 + .../ORM/Query/AST/GeneralCaseExpression.php | 48 + .../lib/Doctrine/ORM/Query/AST/GroupByClause.php | 45 + .../lib/Doctrine/ORM/Query/AST/HavingClause.php | 45 + .../AST/IdentificationVariableDeclaration.php | 49 + .../lib/Doctrine/ORM/Query/AST/InExpression.php | 48 + .../orm/lib/Doctrine/ORM/Query/AST/IndexBy.php | 45 + .../lib/Doctrine/ORM/Query/AST/InputParameter.php | 55 + .../ORM/Query/AST/InstanceOfExpression.php | 49 + .../orm/lib/Doctrine/ORM/Query/AST/Join.php | 52 + .../ORM/Query/AST/JoinAssociationDeclaration.php | 46 + .../Query/AST/JoinAssociationPathExpression.php | 46 + .../ORM/Query/AST/JoinClassPathExpression.php | 45 + .../lib/Doctrine/ORM/Query/AST/LikeExpression.php | 49 + .../orm/lib/Doctrine/ORM/Query/AST/Literal.php | 41 + .../orm/lib/Doctrine/ORM/Query/AST/Node.php | 95 + .../ORM/Query/AST/NullComparisonExpression.php | 47 + .../Doctrine/ORM/Query/AST/NullIfExpression.php | 49 + .../lib/Doctrine/ORM/Query/AST/OrderByClause.php | 45 + .../orm/lib/Doctrine/ORM/Query/AST/OrderByItem.php | 56 + .../ORM/Query/AST/PartialObjectExpression.php | 32 + .../lib/Doctrine/ORM/Query/AST/PathExpression.php | 58 + .../ORM/Query/AST/QuantifiedExpression.php | 64 + .../ORM/Query/AST/RangeVariableDeclaration.php | 47 + .../lib/Doctrine/ORM/Query/AST/SelectClause.php | 47 + .../Doctrine/ORM/Query/AST/SelectExpression.php | 50 + .../lib/Doctrine/ORM/Query/AST/SelectStatement.php | 50 + .../ORM/Query/AST/SimpleArithmeticExpression.php | 45 + .../ORM/Query/AST/SimpleCaseExpression.php | 50 + .../Doctrine/ORM/Query/AST/SimpleSelectClause.php | 47 + .../ORM/Query/AST/SimpleSelectExpression.php | 47 + .../Doctrine/ORM/Query/AST/SimpleWhenClause.php | 48 + .../orm/lib/Doctrine/ORM/Query/AST/Subselect.php | 51 + .../Doctrine/ORM/Query/AST/SubselectFromClause.php | 45 + .../lib/Doctrine/ORM/Query/AST/UpdateClause.php | 49 + .../orm/lib/Doctrine/ORM/Query/AST/UpdateItem.php | 50 + .../lib/Doctrine/ORM/Query/AST/UpdateStatement.php | 45 + .../orm/lib/Doctrine/ORM/Query/AST/WhenClause.php | 48 + .../orm/lib/Doctrine/ORM/Query/AST/WhereClause.php | 45 + .../ORM/Query/Exec/AbstractSqlExecutor.php | 70 + .../ORM/Query/Exec/MultiTableDeleteExecutor.php | 133 + .../ORM/Query/Exec/MultiTableUpdateExecutor.php | 195 ++ .../ORM/Query/Exec/SingleSelectExecutor.php | 48 + .../Query/Exec/SingleTableDeleteUpdateExecutor.php | 53 + .../doctrine/orm/lib/Doctrine/ORM/Query/Expr.php | 595 ++++ .../orm/lib/Doctrine/ORM/Query/Expr/Andx.php | 56 + .../orm/lib/Doctrine/ORM/Query/Expr/Base.php | 121 + .../orm/lib/Doctrine/ORM/Query/Expr/Comparison.php | 101 + .../orm/lib/Doctrine/ORM/Query/Expr/Composite.php | 72 + .../orm/lib/Doctrine/ORM/Query/Expr/From.php | 93 + .../orm/lib/Doctrine/ORM/Query/Expr/Func.php | 79 + .../orm/lib/Doctrine/ORM/Query/Expr/GroupBy.php | 51 + .../orm/lib/Doctrine/ORM/Query/Expr/Join.php | 147 + .../orm/lib/Doctrine/ORM/Query/Expr/Literal.php | 52 + .../orm/lib/Doctrine/ORM/Query/Expr/Math.php | 108 + .../orm/lib/Doctrine/ORM/Query/Expr/OrderBy.php | 103 + .../orm/lib/Doctrine/ORM/Query/Expr/Orx.php | 56 + .../orm/lib/Doctrine/ORM/Query/Expr/Select.php | 58 + .../lib/Doctrine/ORM/Query/Filter/SQLFilter.php | 122 + .../lib/Doctrine/ORM/Query/FilterCollection.php | 198 ++ .../doctrine/orm/lib/Doctrine/ORM/Query/Lexer.php | 206 ++ .../orm/lib/Doctrine/ORM/Query/Parameter.php | 101 + .../Doctrine/ORM/Query/ParameterTypeInferer.php | 65 + .../doctrine/orm/lib/Doctrine/ORM/Query/Parser.php | 3132 ++++++++++++++++++++ .../orm/lib/Doctrine/ORM/Query/ParserResult.php | 138 + .../orm/lib/Doctrine/ORM/Query/Printer.php | 92 + .../orm/lib/Doctrine/ORM/Query/QueryException.php | 156 + .../lib/Doctrine/ORM/Query/ResultSetMapping.php | 485 +++ .../Doctrine/ORM/Query/ResultSetMappingBuilder.php | 264 ++ .../orm/lib/Doctrine/ORM/Query/SqlWalker.php | 2202 ++++++++++++++ .../orm/lib/Doctrine/ORM/Query/TreeWalker.php | 409 +++ .../lib/Doctrine/ORM/Query/TreeWalkerAdapter.php | 443 +++ .../orm/lib/Doctrine/ORM/Query/TreeWalkerChain.php | 662 +++++ .../doctrine/orm/lib/Doctrine/ORM/QueryBuilder.php | 1181 ++++++++ .../Console/Command/ClearCache/MetadataCommand.php | 103 + .../Console/Command/ClearCache/QueryCommand.php | 103 + .../Console/Command/ClearCache/ResultCommand.php | 103 + .../Command/ConvertDoctrine1SchemaCommand.php | 220 ++ .../Console/Command/ConvertMappingCommand.php | 183 ++ .../Command/EnsureProductionSettingsCommand.php | 83 + .../Console/Command/GenerateEntitiesCommand.php | 160 + .../Console/Command/GenerateProxiesCommand.php | 112 + .../Command/GenerateRepositoriesCommand.php | 113 + .../ORM/Tools/Console/Command/InfoCommand.php | 79 + .../ORM/Tools/Console/Command/RunDqlCommand.php | 121 + .../Console/Command/SchemaTool/AbstractCommand.php | 58 + .../Console/Command/SchemaTool/CreateCommand.php | 76 + .../Console/Command/SchemaTool/DropCommand.php | 108 + .../Console/Command/SchemaTool/UpdateCommand.php | 131 + .../Console/Command/ValidateSchemaCommand.php | 86 + .../Doctrine/ORM/Tools/Console/ConsoleRunner.php | 72 + .../Tools/Console/Helper/EntityManagerHelper.php | 71 + .../Doctrine/ORM/Tools/Console/MetadataFilter.php | 77 + .../Doctrine/ORM/Tools/ConvertDoctrine1Schema.php | 271 ++ .../Doctrine/ORM/Tools/DebugUnitOfWorkListener.php | 151 + .../ORM/Tools/DisconnectedClassMetadataFactory.php | 45 + .../orm/lib/Doctrine/ORM/Tools/EntityGenerator.php | 1265 ++++++++ .../ORM/Tools/EntityRepositoryGenerator.php | 81 + .../ORM/Tools/Event/GenerateSchemaEventArgs.php | 62 + .../Tools/Event/GenerateSchemaTableEventArgs.php | 71 + .../ORM/Tools/Export/ClassMetadataExporter.php | 72 + .../ORM/Tools/Export/Driver/AbstractExporter.php | 213 ++ .../ORM/Tools/Export/Driver/AnnotationExporter.php | 67 + .../ORM/Tools/Export/Driver/PhpExporter.php | 165 ++ .../ORM/Tools/Export/Driver/XmlExporter.php | 335 +++ .../ORM/Tools/Export/Driver/YamlExporter.php | 205 ++ .../Doctrine/ORM/Tools/Export/ExportException.php | 23 + .../ORM/Tools/Pagination/CountOutputWalker.php | 130 + .../Doctrine/ORM/Tools/Pagination/CountWalker.php | 90 + .../Tools/Pagination/LimitSubqueryOutputWalker.php | 153 + .../ORM/Tools/Pagination/LimitSubqueryWalker.php | 119 + .../Doctrine/ORM/Tools/Pagination/Paginator.php | 239 ++ .../ORM/Tools/Pagination/WhereInWalker.php | 148 + .../ORM/Tools/ResolveTargetEntityListener.php | 94 + .../orm/lib/Doctrine/ORM/Tools/SchemaTool.php | 722 +++++ .../orm/lib/Doctrine/ORM/Tools/SchemaValidator.php | 289 ++ .../doctrine/orm/lib/Doctrine/ORM/Tools/Setup.php | 200 ++ .../orm/lib/Doctrine/ORM/Tools/ToolEvents.php | 42 + .../orm/lib/Doctrine/ORM/Tools/ToolsException.php | 40 + .../Doctrine/ORM/TransactionRequiredException.php | 37 + .../lib/Doctrine/ORM/UnexpectedResultException.php | 31 + .../doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php | 3046 +++++++++++++++++++ vendor/doctrine/orm/lib/Doctrine/ORM/Version.php | 55 + vendor/doctrine/orm/phpunit.xml.dist | 59 + vendor/doctrine/orm/run-all.sh | 21 + vendor/doctrine/orm/tests/.gitignore | 3 + .../Doctrine/Tests/DbalFunctionalTestCase.php | 32 + .../orm/tests/Doctrine/Tests/DbalTestCase.php | 10 + .../Tests/DbalTypes/NegativeToPositiveType.php | 34 + .../Tests/DbalTypes/UpperCaseStringType.php | 29 + .../orm/tests/Doctrine/Tests/DoctrineTestCase.php | 10 + .../Doctrine/Tests/Mocks/ClassMetadataMock.php | 14 + .../tests/Doctrine/Tests/Mocks/ConnectionMock.php | 106 + .../Doctrine/Tests/Mocks/DatabasePlatformMock.php | 97 + .../Doctrine/Tests/Mocks/DriverConnectionMock.php | 17 + .../orm/tests/Doctrine/Tests/Mocks/DriverMock.php | 72 + .../Doctrine/Tests/Mocks/EntityManagerMock.php | 106 + .../Doctrine/Tests/Mocks/EntityPersisterMock.php | 100 + .../Doctrine/Tests/Mocks/HydratorMockStatement.php | 111 + .../Tests/Mocks/IdentityIdGeneratorMock.php | 12 + .../Doctrine/Tests/Mocks/MetadataDriverMock.php | 21 + .../tests/Doctrine/Tests/Mocks/MockTreeWalker.php | 17 + .../Doctrine/Tests/Mocks/SchemaManagerMock.php | 13 + .../tests/Doctrine/Tests/Mocks/SequenceMock.php | 52 + .../tests/Doctrine/Tests/Mocks/StatementMock.php | 25 + .../orm/tests/Doctrine/Tests/Mocks/TaskMock.php | 81 + .../tests/Doctrine/Tests/Mocks/UnitOfWorkMock.php | 58 + .../tests/Doctrine/Tests/Models/CMS/CmsAddress.php | 191 ++ .../tests/Doctrine/Tests/Models/CMS/CmsArticle.php | 48 + .../tests/Doctrine/Tests/Models/CMS/CmsComment.php | 38 + .../tests/Doctrine/Tests/Models/CMS/CmsEmail.php | 48 + .../Doctrine/Tests/Models/CMS/CmsEmployee.php | 44 + .../tests/Doctrine/Tests/Models/CMS/CmsGroup.php | 49 + .../Doctrine/Tests/Models/CMS/CmsPhonenumber.php | 28 + .../tests/Doctrine/Tests/Models/CMS/CmsUser.php | 437 +++ .../Tests/Models/Company/CompanyAuction.php | 17 + .../Doctrine/Tests/Models/Company/CompanyCar.php | 33 + .../Tests/Models/Company/CompanyContract.php | 131 + .../Tests/Models/Company/CompanyEmployee.php | 59 + .../Doctrine/Tests/Models/Company/CompanyEvent.php | 36 + .../Tests/Models/Company/CompanyFixContract.php | 30 + .../Tests/Models/Company/CompanyFlexContract.php | 110 + .../Models/Company/CompanyFlexUltraContract.php | 30 + .../Tests/Models/Company/CompanyManager.php | 42 + .../Tests/Models/Company/CompanyOrganization.php | 44 + .../Tests/Models/Company/CompanyPerson.php | 160 + .../Tests/Models/Company/CompanyRaffle.php | 17 + .../Tests/Models/CustomType/CustomTypeChild.php | 21 + .../Tests/Models/CustomType/CustomTypeParent.php | 68 + .../Models/CustomType/CustomTypeUpperCase.php | 26 + .../Tests/Models/DDC117/DDC117ApproveChanges.php | 65 + .../Doctrine/Tests/Models/DDC117/DDC117Article.php | 87 + .../Tests/Models/DDC117/DDC117ArticleDetails.php | 39 + .../Doctrine/Tests/Models/DDC117/DDC117Editor.php | 54 + .../Doctrine/Tests/Models/DDC117/DDC117Link.php | 31 + .../Tests/Models/DDC117/DDC117Reference.php | 64 + .../Tests/Models/DDC117/DDC117Translation.php | 65 + .../DDC1476/DDC1476EntityWithDefaultFieldType.php | 76 + .../Tests/Models/DDC753/DDC753CustomRepository.php | 36 + .../Models/DDC753/DDC753DefaultRepository.php | 35 + .../DDC753/DDC753EntityWithCustomRepository.php | 39 + .../DDC753EntityWithDefaultCustomRepository.php | 39 + .../DDC753/DDC753EntityWithInvalidRepository.php | 39 + .../Models/DDC753/DDC753InvalidRepository.php | 28 + .../Tests/Models/DDC869/DDC869ChequePayment.php | 40 + .../Models/DDC869/DDC869CreditCardPayment.php | 40 + .../Doctrine/Tests/Models/DDC869/DDC869Payment.php | 57 + .../Models/DDC869/DDC869PaymentRepository.php | 37 + .../Doctrine/Tests/Models/DDC889/DDC889Class.php | 46 + .../Doctrine/Tests/Models/DDC889/DDC889Entity.php | 33 + .../Tests/Models/DDC889/DDC889SuperClass.php | 41 + .../Doctrine/Tests/Models/DDC964/DDC964Address.php | 123 + .../Doctrine/Tests/Models/DDC964/DDC964Admin.php | 47 + .../Doctrine/Tests/Models/DDC964/DDC964Group.php | 70 + .../Doctrine/Tests/Models/DDC964/DDC964Guest.php | 44 + .../Doctrine/Tests/Models/DDC964/DDC964User.php | 155 + .../Models/DirectoryTree/AbstractContentItem.php | 64 + .../Tests/Models/DirectoryTree/Directory.php | 41 + .../Doctrine/Tests/Models/DirectoryTree/File.php | 46 + .../Tests/Models/ECommerce/ECommerceCart.php | 91 + .../Tests/Models/ECommerce/ECommerceCategory.php | 126 + .../Tests/Models/ECommerce/ECommerceCustomer.php | 94 + .../Tests/Models/ECommerce/ECommerceFeature.php | 59 + .../Tests/Models/ECommerce/ECommerceProduct.php | 178 ++ .../Tests/Models/ECommerce/ECommerceShipping.php | 40 + .../Tests/Models/Forum/ForumAdministrator.php | 14 + .../Doctrine/Tests/Models/Forum/ForumAvatar.php | 17 + .../Doctrine/Tests/Models/Forum/ForumBoard.php | 28 + .../Doctrine/Tests/Models/Forum/ForumCategory.php | 32 + .../Doctrine/Tests/Models/Forum/ForumEntry.php | 26 + .../Doctrine/Tests/Models/Forum/ForumUser.php | 41 + .../Doctrine/Tests/Models/Generic/BooleanModel.php | 20 + .../Tests/Models/Generic/DateTimeModel.php | 28 + .../Doctrine/Tests/Models/Generic/DecimalModel.php | 25 + .../Tests/Models/Generic/SerializationModel.php | 25 + .../Tests/Models/Global/GlobalNamespaceModel.php | 68 + .../JoinedInheritanceType/AnotherChildClass.php | 10 + .../Models/JoinedInheritanceType/ChildClass.php | 10 + .../Models/JoinedInheritanceType/RootClass.php | 16 + .../Doctrine/Tests/Models/Legacy/LegacyArticle.php | 33 + .../Doctrine/Tests/Models/Legacy/LegacyCar.php | 41 + .../Doctrine/Tests/Models/Legacy/LegacyUser.php | 80 + .../Tests/Models/Legacy/LegacyUserReference.php | 65 + .../Tests/Models/Navigation/NavCountry.php | 39 + .../Doctrine/Tests/Models/Navigation/NavPhotos.php | 48 + .../Tests/Models/Navigation/NavPointOfInterest.php | 79 + .../Doctrine/Tests/Models/Navigation/NavTour.php | 61 + .../Doctrine/Tests/Models/Navigation/NavUser.php | 28 + .../tests/Doctrine/Tests/Models/Quote/Address.php | 54 + .../tests/Doctrine/Tests/Models/Quote/Group.php | 42 + .../tests/Doctrine/Tests/Models/Quote/Phone.php | 24 + .../Doctrine/Tests/Models/Quote/SimpleEntity.php | 32 + .../orm/tests/Doctrine/Tests/Models/Quote/User.php | 102 + .../Doctrine/Tests/Models/Routing/RoutingLeg.php | 37 + .../Tests/Models/Routing/RoutingLocation.php | 25 + .../Doctrine/Tests/Models/Routing/RoutingRoute.php | 39 + .../Tests/Models/Routing/RoutingRouteBooking.php | 32 + .../Doctrine/Tests/Models/StockExchange/Bond.php | 48 + .../Doctrine/Tests/Models/StockExchange/Market.php | 56 + .../Doctrine/Tests/Models/StockExchange/Stock.php | 49 + .../Tests/ORM/CommitOrderCalculatorTest.php | 56 + .../tests/Doctrine/Tests/ORM/ConfigurationTest.php | 276 ++ .../Tests/ORM/Criteria/DqlGenerationTest.php | 252 ++ .../Doctrine/Tests/ORM/Entity/ConstructorTest.php | 28 + .../tests/Doctrine/Tests/ORM/EntityManagerTest.php | 175 ++ .../AbstractManyToManyAssociationTestCase.php | 42 + .../ORM/Functional/AdvancedAssociationTest.php | 598 ++++ .../Tests/ORM/Functional/AdvancedDqlQueryTest.php | 183 ++ .../Tests/ORM/Functional/BasicFunctionalTest.php | 1290 ++++++++ .../ORM/Functional/ClassTableInheritanceTest.php | 497 ++++ .../ORM/Functional/ClassTableInheritanceTest2.php | 176 ++ .../Tests/ORM/Functional/ClearEventTest.php | 40 + .../ORM/Functional/CompositePrimaryKeyTest.php | 144 + .../Tests/ORM/Functional/CustomTreeWalkersTest.php | 157 + .../Tests/ORM/Functional/DatabaseDriverTest.php | 166 ++ .../Tests/ORM/Functional/DefaultValuesTest.php | 150 + .../Tests/ORM/Functional/DetachedEntityTest.php | 218 ++ .../Functional/EntityRepositoryCriteriaTest.php | 87 + .../Tests/ORM/Functional/EntityRepositoryTest.php | 696 +++++ .../ORM/Functional/ExtraLazyCollectionTest.php | 583 ++++ .../Tests/ORM/Functional/FlushEventTest.php | 94 + .../Tests/ORM/Functional/HydrationCacheTest.php | 88 + .../Tests/ORM/Functional/IdentityMapTest.php | 288 ++ .../ORM/Functional/IndexByAssociationTest.php | 105 + .../Tests/ORM/Functional/LifecycleCallbackTest.php | 311 ++ .../ORM/Functional/Locking/GearmanLockTest.php | 180 ++ .../ORM/Functional/Locking/LockAgentWorker.php | 112 + .../Tests/ORM/Functional/Locking/LockTest.php | 186 ++ .../ORM/Functional/Locking/OptimisticTest.php | 277 ++ .../Functional/ManyToManyBasicAssociationTest.php | 380 +++ .../ManyToManyBidirectionalAssociationTest.php | 202 ++ .../Tests/ORM/Functional/ManyToManyEventTest.php | 76 + .../ManyToManySelfReferentialAssociationTest.php | 124 + .../ManyToManyUnidirectionalAssociationTest.php | 108 + .../Tests/ORM/Functional/MappedSuperclassTest.php | 47 + .../Tests/ORM/Functional/NativeQueryTest.php | 712 +++++ .../Tests/ORM/Functional/NotifyPolicyTest.php | 173 ++ .../OneToManyBidirectionalAssociationTest.php | 218 ++ .../ORM/Functional/OneToManyOrphanRemovalTest.php | 75 + .../OneToManySelfReferentialAssociationTest.php | 123 + .../OneToManyUnidirectionalAssociationTest.php | 86 + .../OneToOneBidirectionalAssociationTest.php | 151 + .../ORM/Functional/OneToOneEagerLoadingTest.php | 343 +++ .../ORM/Functional/OneToOneOrphanRemovalTest.php | 94 + .../OneToOneSelfReferentialAssociationTest.php | 165 ++ .../OneToOneUnidirectionalAssociationTest.php | 125 + .../Tests/ORM/Functional/OrderedCollectionTest.php | 113 + ...OrderedJoinedTableInheritanceCollectionTest.php | 133 + .../Tests/ORM/Functional/PaginationTest.php | 168 ++ .../ORM/Functional/PersistentCollectionTest.php | 98 + .../Tests/ORM/Functional/PersistentObjectTest.php | 105 + .../Tests/ORM/Functional/PostFlushEventTest.php | 95 + .../Functional/PostgreSQLIdentityStrategyTest.php | 53 + .../ORM/Functional/ProxiesLikeEntitiesTest.php | 133 + .../Tests/ORM/Functional/QueryCacheTest.php | 153 + .../Tests/ORM/Functional/QueryDqlFunctionTest.php | 402 +++ .../Doctrine/Tests/ORM/Functional/QueryTest.php | 783 +++++ .../Doctrine/Tests/ORM/Functional/ReadOnlyTest.php | 94 + .../Tests/ORM/Functional/ReferenceProxyTest.php | 250 ++ .../Tests/ORM/Functional/ResultCacheTest.php | 254 ++ .../Tests/ORM/Functional/SQLFilterTest.php | 1121 +++++++ .../Functional/SchemaTool/CompanySchemaTest.php | 68 + .../Tests/ORM/Functional/SchemaTool/DDC214Test.php | 91 + .../Functional/SchemaTool/MySqlSchemaToolTest.php | 99 + .../SchemaTool/PostgreSqlSchemaToolTest.php | 198 ++ .../Tests/ORM/Functional/SchemaValidatorTest.php | 50 + .../Tests/ORM/Functional/SequenceGeneratorTest.php | 53 + .../ORM/Functional/SingleTableInheritanceTest.php | 389 +++ .../ORM/Functional/StandardEntityPersisterTest.php | 110 + .../Tests/ORM/Functional/Ticket/DDC1040Test.php | 81 + .../Tests/ORM/Functional/Ticket/DDC1041Test.php | 33 + .../Tests/ORM/Functional/Ticket/DDC1043Test.php | 36 + .../Tests/ORM/Functional/Ticket/DDC1050Test.php | 37 + .../Tests/ORM/Functional/Ticket/DDC1080Test.php | 317 ++ .../Tests/ORM/Functional/Ticket/DDC1113Test.php | 99 + .../Tests/ORM/Functional/Ticket/DDC1129Test.php | 46 + .../Tests/ORM/Functional/Ticket/DDC1151Test.php | 56 + .../Tests/ORM/Functional/Ticket/DDC1163Test.php | 215 ++ .../Tests/ORM/Functional/Ticket/DDC117Test.php | 464 +++ .../Tests/ORM/Functional/Ticket/DDC1181Test.php | 101 + .../Tests/ORM/Functional/Ticket/DDC1193Test.php | 93 + .../Tests/ORM/Functional/Ticket/DDC1209Test.php | 125 + .../Tests/ORM/Functional/Ticket/DDC1225Test.php | 85 + .../Tests/ORM/Functional/Ticket/DDC1228Test.php | 136 + .../Tests/ORM/Functional/Ticket/DDC1238Test.php | 100 + .../Tests/ORM/Functional/Ticket/DDC1250Test.php | 96 + .../Tests/ORM/Functional/Ticket/DDC1276Test.php | 50 + .../Tests/ORM/Functional/Ticket/DDC1300Test.php | 108 + .../Tests/ORM/Functional/Ticket/DDC1301Test.php | 148 + .../Tests/ORM/Functional/Ticket/DDC1306Test.php | 54 + .../Tests/ORM/Functional/Ticket/DDC1335Test.php | 218 ++ .../Tests/ORM/Functional/Ticket/DDC1360Test.php | 37 + .../Tests/ORM/Functional/Ticket/DDC1383Test.php | 99 + .../Tests/ORM/Functional/Ticket/DDC1392Test.php | 127 + .../Tests/ORM/Functional/Ticket/DDC1400Test.php | 131 + .../Tests/ORM/Functional/Ticket/DDC1404Test.php | 129 + .../Tests/ORM/Functional/Ticket/DDC142Test.php | 89 + .../Tests/ORM/Functional/Ticket/DDC1430Test.php | 297 ++ .../Tests/ORM/Functional/Ticket/DDC1436Test.php | 89 + .../Tests/ORM/Functional/Ticket/DDC144Test.php | 64 + .../Tests/ORM/Functional/Ticket/DDC1452Test.php | 127 + .../Tests/ORM/Functional/Ticket/DDC1454Test.php | 69 + .../Tests/ORM/Functional/Ticket/DDC1458Test.php | 131 + .../Tests/ORM/Functional/Ticket/DDC1461Test.php | 86 + .../Tests/ORM/Functional/Ticket/DDC1509Test.php | 146 + .../Tests/ORM/Functional/Ticket/DDC1514Test.php | 111 + .../Tests/ORM/Functional/Ticket/DDC1515Test.php | 64 + .../Tests/ORM/Functional/Ticket/DDC1526Test.php | 67 + .../Tests/ORM/Functional/Ticket/DDC1545Test.php | 201 ++ .../Tests/ORM/Functional/Ticket/DDC1548Test.php | 81 + .../Tests/ORM/Functional/Ticket/DDC1594Test.php | 45 + .../Tests/ORM/Functional/Ticket/DDC1595Test.php | 111 + .../Tests/ORM/Functional/Ticket/DDC163Test.php | 65 + .../Tests/ORM/Functional/Ticket/DDC1643Test.php | 121 + .../Tests/ORM/Functional/Ticket/DDC1654Test.php | 103 + .../Tests/ORM/Functional/Ticket/DDC1655Test.php | 144 + .../Tests/ORM/Functional/Ticket/DDC1685Test.php | 64 + .../Tests/ORM/Functional/Ticket/DDC168Test.php | 64 + .../Tests/ORM/Functional/Ticket/DDC1695Test.php | 158 + .../Tests/ORM/Functional/Ticket/DDC1707Test.php | 64 + .../Tests/ORM/Functional/Ticket/DDC1719Test.php | 88 + .../Tests/ORM/Functional/Ticket/DDC1757Test.php | 92 + .../Tests/ORM/Functional/Ticket/DDC1778Test.php | 74 + .../Tests/ORM/Functional/Ticket/DDC1843Test.php | 136 + .../Tests/ORM/Functional/Ticket/DDC1885Test.php | 171 ++ .../Tests/ORM/Functional/Ticket/DDC1918Test.php | 62 + .../Tests/ORM/Functional/Ticket/DDC192Test.php | 65 + .../Tests/ORM/Functional/Ticket/DDC199Test.php | 100 + .../Tests/ORM/Functional/Ticket/DDC211Test.php | 116 + .../Tests/ORM/Functional/Ticket/DDC237Test.php | 112 + .../Tests/ORM/Functional/Ticket/DDC258Test.php | 142 + .../Tests/ORM/Functional/Ticket/DDC279Test.php | 133 + .../Tests/ORM/Functional/Ticket/DDC309Test.php | 73 + .../Tests/ORM/Functional/Ticket/DDC331Test.php | 39 + .../Tests/ORM/Functional/Ticket/DDC345Test.php | 157 + .../Tests/ORM/Functional/Ticket/DDC353Test.php | 150 + .../Tests/ORM/Functional/Ticket/DDC371Test.php | 72 + .../Tests/ORM/Functional/Ticket/DDC381Test.php | 63 + .../Tests/ORM/Functional/Ticket/DDC422Test.php | 75 + .../Tests/ORM/Functional/Ticket/DDC425Test.php | 43 + .../Tests/ORM/Functional/Ticket/DDC440Test.php | 216 ++ .../Tests/ORM/Functional/Ticket/DDC444Test.php | 77 + .../Tests/ORM/Functional/Ticket/DDC448Test.php | 74 + .../Tests/ORM/Functional/Ticket/DDC493Test.php | 72 + .../Tests/ORM/Functional/Ticket/DDC501Test.php | 124 + .../Tests/ORM/Functional/Ticket/DDC512Test.php | 94 + .../Tests/ORM/Functional/Ticket/DDC513Test.php | 74 + .../Tests/ORM/Functional/Ticket/DDC518Test.php | 36 + .../Tests/ORM/Functional/Ticket/DDC522Test.php | 121 + .../Tests/ORM/Functional/Ticket/DDC531Test.php | 88 + .../Tests/ORM/Functional/Ticket/DDC588Test.php | 48 + .../Tests/ORM/Functional/Ticket/DDC599Test.php | 132 + .../Tests/ORM/Functional/Ticket/DDC618Test.php | 185 ++ .../Tests/ORM/Functional/Ticket/DDC633Test.php | 102 + .../Tests/ORM/Functional/Ticket/DDC656Test.php | 82 + .../Tests/ORM/Functional/Ticket/DDC657Test.php | 120 + .../Tests/ORM/Functional/Ticket/DDC698Test.php | 107 + .../Tests/ORM/Functional/Ticket/DDC719Test.php | 112 + .../Tests/ORM/Functional/Ticket/DDC729Test.php | 182 ++ .../Tests/ORM/Functional/Ticket/DDC735Test.php | 122 + .../Tests/ORM/Functional/Ticket/DDC736Test.php | 100 + .../Tests/ORM/Functional/Ticket/DDC742Test.php | 130 + .../Tests/ORM/Functional/Ticket/DDC748Test.php | 64 + .../Tests/ORM/Functional/Ticket/DDC758Test.php | 185 ++ .../Tests/ORM/Functional/Ticket/DDC767Test.php | 74 + .../Tests/ORM/Functional/Ticket/DDC809Test.php | 109 + .../Tests/ORM/Functional/Ticket/DDC812Test.php | 48 + .../Tests/ORM/Functional/Ticket/DDC832Test.php | 194 ++ .../Tests/ORM/Functional/Ticket/DDC837Test.php | 198 ++ .../Tests/ORM/Functional/Ticket/DDC849Test.php | 84 + .../Tests/ORM/Functional/Ticket/DDC881Test.php | 215 ++ .../Tests/ORM/Functional/Ticket/DDC933Test.php | 39 + .../Tests/ORM/Functional/Ticket/DDC949Test.php | 43 + .../Tests/ORM/Functional/Ticket/DDC960Test.php | 92 + .../Tests/ORM/Functional/Ticket/DDC992Test.php | 147 + .../Tests/ORM/Functional/Ticket/Ticket2481Test.php | 44 + .../Tests/ORM/Functional/Ticket/Ticket69.php | 427 +++ .../Doctrine/Tests/ORM/Functional/TypeTest.php | 182 ++ .../Tests/ORM/Functional/TypeValueSqlTest.php | 142 + .../Tests/ORM/Functional/UUIDGeneratorTest.php | 48 + .../ORM/Functional/UnitOfWorkLifecycleTest.php | 71 + .../Tests/ORM/Hydration/ArrayHydratorTest.php | 1147 +++++++ .../Tests/ORM/Hydration/CustomHydratorTest.php | 29 + .../Tests/ORM/Hydration/HydrationTestCase.php | 30 + .../Tests/ORM/Hydration/ObjectHydratorTest.php | 1931 ++++++++++++ .../Tests/ORM/Hydration/ResultSetMappingTest.php | 259 ++ .../Tests/ORM/Hydration/ScalarHydratorTest.php | 101 + .../ORM/Hydration/SimpleObjectHydratorTest.php | 37 + .../ORM/Hydration/SingleScalarHydratorTest.php | 78 + .../Tests/ORM/Id/AssignedGeneratorTest.php | 67 + .../Tests/ORM/Id/SequenceGeneratorTest.php | 40 + .../ORM/Mapping/AbstractMappingDriverTest.php | 1078 +++++++ .../Tests/ORM/Mapping/AnnotationDriverTest.php | 340 +++ .../ORM/Mapping/BasicInheritanceMappingTest.php | 319 ++ .../Tests/ORM/Mapping/ClassMetadataBuilderTest.php | 428 +++ .../Tests/ORM/Mapping/ClassMetadataFactoryTest.php | 368 +++ .../ORM/Mapping/ClassMetadataLoadEventTest.php | 56 + .../Tests/ORM/Mapping/ClassMetadataTest.php | 995 +++++++ .../Tests/ORM/Mapping/NamingStrategyTest.php | 298 ++ .../Tests/ORM/Mapping/PHPMappingDriverTest.php | 38 + .../Tests/ORM/Mapping/QuoteStrategyTest.php | 197 ++ .../ORM/Mapping/StaticPHPMappingDriverTest.php | 28 + .../ORM/Mapping/Symfony/AbstractDriverTest.php | 113 + .../Tests/ORM/Mapping/Symfony/XmlDriverTest.php | 40 + .../Tests/ORM/Mapping/Symfony/YamlDriverTest.php | 40 + .../Tests/ORM/Mapping/XmlMappingDriverTest.php | 106 + .../Tests/ORM/Mapping/YamlMappingDriverTest.php | 57 + .../php/Doctrine.Tests.Models.CMS.CmsAddress.php | 69 + .../php/Doctrine.Tests.Models.CMS.CmsUser.php | 186 ++ ...Doctrine.Tests.Models.Company.CompanyPerson.php | 39 + ...s.DDC1476.DDC1476EntityWithDefaultFieldType.php | 12 + ...ine.Tests.Models.DDC869.DDC869ChequePayment.php | 5 + ...Tests.Models.DDC869.DDC869CreditCardPayment.php | 5 + .../Doctrine.Tests.Models.DDC869.DDC869Payment.php | 17 + .../Doctrine.Tests.Models.DDC889.DDC889Class.php | 12 + .../Doctrine.Tests.Models.DDC889.DDC889Entity.php | 3 + ...ctrine.Tests.Models.DDC889.DDC889SuperClass.php | 11 + .../Doctrine.Tests.Models.DDC964.DDC964Admin.php | 21 + .../Doctrine.Tests.Models.DDC964.DDC964Guest.php | 13 + .../Doctrine.Tests.Models.DDC964.DDC964User.php | 46 + .../php/Doctrine.Tests.ORM.Mapping.Animal.php | 30 + .../Doctrine.Tests.ORM.Mapping.DDC1170Entity.php | 16 + .../Doctrine.Tests.ORM.Mapping.DDC807Entity.php | 15 + .../php/Doctrine.Tests.ORM.Mapping.User.php | 124 + .../Doctrine/Tests/ORM/Mapping/xml/CatNoId.dcm.xml | 8 + .../Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml | 55 + .../xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml | 139 + ...rine.Tests.Models.Company.CompanyPerson.dcm.xml | 57 + ...e.Tests.Models.DDC117.DDC117Translation.dcm.xml | 22 + ...C1476.DDC1476EntityWithDefaultFieldType.dcm.xml | 15 + ...Tests.Models.DDC869.DDC869ChequePayment.dcm.xml | 11 + ...s.Models.DDC869.DDC869CreditCardPayment.dcm.xml | 11 + ...trine.Tests.Models.DDC869.DDC869Payment.dcm.xml | 15 + ...octrine.Tests.Models.DDC889.DDC889Class.dcm.xml | 13 + ...ctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml | 10 + ...ne.Tests.Models.DDC889.DDC889SuperClass.dcm.xml | 11 + ...octrine.Tests.Models.DDC964.DDC964Admin.dcm.xml | 27 + ...octrine.Tests.Models.DDC964.DDC964Guest.dcm.xml | 18 + ...Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml | 39 + ...Tests.Models.Generic.SerializationModel.dcm.xml | 17 + .../xml/Doctrine.Tests.ORM.Mapping.Animal.dcm.xml | 17 + .../xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml | 17 + ...octrine.Tests.ORM.Mapping.DDC1170Entity.dcm.xml | 15 + ...Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.xml | 20 + .../xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml | 80 + .../Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml | 62 + .../yaml/Doctrine.Tests.Models.CMS.CmsUser.dcm.yml | 158 + ...rine.Tests.Models.Company.CompanyPerson.dcm.yml | 75 + ...C1476.DDC1476EntityWithDefaultFieldType.dcm.yml | 8 + ...Tests.Models.DDC869.DDC869ChequePayment.dcm.yml | 5 + ...s.Models.DDC869.DDC869CreditCardPayment.dcm.yml | 5 + ...trine.Tests.Models.DDC869.DDC869Payment.dcm.yml | 12 + ...octrine.Tests.Models.DDC889.DDC889Class.dcm.yml | 8 + ...ctrine.Tests.Models.DDC889.DDC889Entity.dcm.yml | 2 + ...ne.Tests.Models.DDC889.DDC889SuperClass.dcm.yml | 5 + ...octrine.Tests.Models.DDC964.DDC964Admin.dcm.yml | 17 + ...octrine.Tests.Models.DDC964.DDC964Guest.dcm.yml | 13 + ...Doctrine.Tests.Models.DDC964.DDC964User.dcm.yml | 35 + ...odels.DirectoryTree.AbstractContentItem.dcm.yml | 14 + ...ne.Tests.Models.DirectoryTree.Directory.dcm.yml | 6 + ...octrine.Tests.Models.DirectoryTree.File.dcm.yml | 6 + ...Tests.Models.Generic.SerializationModel.dcm.yml | 13 + .../yaml/Doctrine.Tests.ORM.Mapping.Animal.dcm.yml | 17 + ...octrine.Tests.ORM.Mapping.DDC1170Entity.dcm.yml | 10 + ...Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.yml | 13 + .../yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml | 76 + .../ORM/Performance/HydrationPerformanceTest.php | 461 +++ .../InheritancePersisterPerformanceTest.php | 66 + .../ORM/Performance/InsertPerformanceTest.php | 56 + .../ORM/Performance/PersisterPerformanceTest.php | 121 + .../ORM/Performance/UnitOfWorkPerformanceTest.php | 51 + .../Tests/ORM/PersistentCollectionTest.php | 37 + .../BasicEntityPersisterTypeValueSqlTest.php | 91 + .../Doctrine/Tests/ORM/Proxy/AutoloaderTest.php | 62 + .../Tests/ORM/Proxy/ProxyClassGeneratorTest.php | 204 ++ .../ORM/Proxy/fixtures/NonNamespacedProxies.php | 13 + .../Tests/ORM/Query/DeleteSqlGenerationTest.php | 287 ++ .../tests/Doctrine/Tests/ORM/Query/ExprTest.php | 412 +++ .../Tests/ORM/Query/LanguageRecognitionTest.php | 606 ++++ .../tests/Doctrine/Tests/ORM/Query/LexerTest.php | 234 ++ .../Tests/ORM/Query/ParameterTypeInfererTest.php | 53 + .../Doctrine/Tests/ORM/Query/ParserResultTest.php | 48 + .../tests/Doctrine/Tests/ORM/Query/QueryTest.php | 166 ++ .../Tests/ORM/Query/SelectSqlGenerationTest.php | 1794 +++++++++++ .../Tests/ORM/Query/UpdateSqlGenerationTest.php | 205 ++ .../tests/Doctrine/Tests/ORM/QueryBuilderTest.php | 784 +++++ .../Command/ConvertDoctrine1SchemaCommandTest.php | 23 + .../Tests/ORM/Tools/ConvertDoctrine1SchemaTest.php | 108 + .../Tests/ORM/Tools/EntityGeneratorTest.php | 444 +++ .../Export/AbstractClassMetadataExporterTest.php | 391 +++ .../Export/AnnotationClassMetadataExporterTest.php | 42 + .../Tools/Export/PhpClassMetadataExporterTest.php | 42 + .../Tools/Export/XmlClassMetadataExporterTest.php | 42 + .../Tools/Export/YamlClassMetadataExporterTest.php | 46 + .../Doctrine.Tests.ORM.Tools.Export.User.php | 73 + .../php/Doctrine.Tests.ORM.Tools.Export.User.php | 109 + .../Doctrine.Tests.ORM.Tools.Export.User.dcm.xml | 66 + .../Doctrine.Tests.ORM.Tools.Export.User.dcm.yml | 63 + .../ORM/Tools/Pagination/CountOutputWalkerTest.php | 45 + .../Tests/ORM/Tools/Pagination/CountWalkerTest.php | 94 + .../Pagination/LimitSubqueryOutputWalkerTest.php | 33 + .../Tools/Pagination/LimitSubqueryWalkerTest.php | 36 + .../ORM/Tools/Pagination/PaginationTestCase.php | 142 + .../ORM/Tools/Pagination/WhereInWalkerTest.php | 125 + .../ORM/Tools/ResolveTargetEntityListenerTest.php | 129 + .../Doctrine/Tests/ORM/Tools/SchemaToolTest.php | 135 + .../Tests/ORM/Tools/SchemaValidatorTest.php | 267 ++ .../tests/Doctrine/Tests/ORM/Tools/SetupTest.php | 110 + .../Tests/ORM/Tools/doctrine1schema/schema.yml | 28 + .../tests/Doctrine/Tests/ORM/UnitOfWorkTest.php | 312 ++ .../tests/Doctrine/Tests/OrmFunctionalTestCase.php | 416 +++ .../Doctrine/Tests/OrmPerformanceTestCase.php | 60 + .../orm/tests/Doctrine/Tests/OrmTestCase.php | 117 + .../doctrine/orm/tests/Doctrine/Tests/TestInit.php | 43 + .../doctrine/orm/tests/Doctrine/Tests/TestUtil.php | 119 + vendor/doctrine/orm/tests/NativePhpunitTask.php | 249 ++ vendor/doctrine/orm/tests/README.markdown | 25 + vendor/doctrine/orm/tests/dbproperties.xml.dev | 33 + vendor/doctrine/orm/tests/travis/mysql.travis.xml | 32 + vendor/doctrine/orm/tests/travis/pgsql.travis.xml | 34 + vendor/doctrine/orm/tests/travis/sqlite.travis.xml | 15 + .../orm/tools/sandbox/Entities/Address.php | 45 + .../doctrine/orm/tools/sandbox/Entities/User.php | 48 + vendor/doctrine/orm/tools/sandbox/cli-config.php | 36 + vendor/doctrine/orm/tools/sandbox/doctrine | 4 + vendor/doctrine/orm/tools/sandbox/doctrine.php | 49 + vendor/doctrine/orm/tools/sandbox/index.php | 62 + .../orm/tools/sandbox/xml/Entities.Address.dcm.xml | 15 + .../orm/tools/sandbox/xml/Entities.User.dcm.xml | 17 + .../tools/sandbox/yaml/Entities.Address.dcm.yml | 16 + .../orm/tools/sandbox/yaml/Entities.User.dcm.yml | 18 + .../Symfony/Component/Console/Application.php | 1089 +++++++ .../console/Symfony/Component/Console/CHANGELOG.md | 19 + .../Symfony/Component/Console/Command/Command.php | 614 ++++ .../Component/Console/Command/HelpCommand.php | 84 + .../Component/Console/Command/ListCommand.php | 87 + .../Console/Formatter/OutputFormatter.php | 248 ++ .../Console/Formatter/OutputFormatterInterface.php | 83 + .../Console/Formatter/OutputFormatterStyle.php | 222 ++ .../Formatter/OutputFormatterStyleInterface.php | 72 + .../Formatter/OutputFormatterStyleStack.php | 121 + .../Component/Console/Helper/DialogHelper.php | 141 + .../Component/Console/Helper/FormatterHelper.php | 102 + .../Symfony/Component/Console/Helper/Helper.php | 42 + .../Component/Console/Helper/HelperInterface.php | 49 + .../Symfony/Component/Console/Helper/HelperSet.php | 104 + .../Symfony/Component/Console/Input/ArgvInput.php | 313 ++ .../Symfony/Component/Console/Input/ArrayInput.php | 190 ++ .../Symfony/Component/Console/Input/Input.php | 211 ++ .../Component/Console/Input/InputArgument.php | 132 + .../Component/Console/Input/InputDefinition.php | 531 ++++ .../Component/Console/Input/InputInterface.php | 152 + .../Component/Console/Input/InputOption.php | 209 ++ .../Component/Console/Input/StringInput.php | 81 + .../console/Symfony/Component/Console/LICENSE | 19 + .../Component/Console/Output/ConsoleOutput.php | 104 + .../Console/Output/ConsoleOutputInterface.php | 30 + .../Component/Console/Output/NullOutput.php | 34 + .../Symfony/Component/Console/Output/Output.php | 180 ++ .../Component/Console/Output/OutputInterface.php | 109 + .../Component/Console/Output/StreamOutput.php | 113 + .../console/Symfony/Component/Console/README.md | 55 + .../console/Symfony/Component/Console/Shell.php | 207 ++ .../Component/Console/Tester/ApplicationTester.php | 104 + .../Component/Console/Tester/CommandTester.php | 102 + .../Component/Console/Tests/ApplicationTest.php | 516 ++++ .../Console/Tests/Command/CommandTest.php | 253 ++ .../Console/Tests/Command/HelpCommandTest.php | 42 + .../Console/Tests/Command/ListCommandTest.php | 38 + .../Console/Tests/Fixtures/Foo1Command.php | 26 + .../Console/Tests/Fixtures/Foo2Command.php | 21 + .../Console/Tests/Fixtures/Foo3Command.php | 25 + .../Console/Tests/Fixtures/FooCommand.php | 33 + .../Console/Tests/Fixtures/TestCommand.php | 28 + .../Console/Tests/Fixtures/application_astext1.txt | 20 + .../Console/Tests/Fixtures/application_astext2.txt | 16 + .../Console/Tests/Fixtures/application_asxml1.txt | 83 + .../Console/Tests/Fixtures/application_asxml2.txt | 15 + .../Console/Tests/Fixtures/application_gethelp.txt | 13 + .../Fixtures/application_renderexception1.txt | 8 + .../Fixtures/application_renderexception2.txt | 11 + .../Fixtures/application_renderexception3.txt | 19 + .../Fixtures/application_renderexception4.txt | 9 + .../Console/Tests/Fixtures/application_run1.txt | 17 + .../Console/Tests/Fixtures/application_run2.txt | 26 + .../Console/Tests/Fixtures/application_run3.txt | 27 + .../Console/Tests/Fixtures/application_run4.txt | 1 + .../Console/Tests/Fixtures/command_astext.txt | 18 + .../Console/Tests/Fixtures/command_asxml.txt | 38 + .../Console/Tests/Fixtures/definition_astext.txt | 11 + .../Console/Tests/Fixtures/definition_asxml.txt | 39 + .../Formatter/OutputFormatterStyleStackTest.php | 70 + .../Tests/Formatter/OutputFormatterStyleTest.php | 77 + .../Tests/Formatter/OutputFormatterTest.php | 212 ++ .../Console/Tests/Helper/DialogHelperTest.php | 93 + .../Console/Tests/Helper/FormatterHelperTest.php | 84 + .../Console/Tests/Input/ArgvInputTest.php | 217 ++ .../Console/Tests/Input/ArrayInputTest.php | 90 + .../Console/Tests/Input/InputArgumentTest.php | 104 + .../Console/Tests/Input/InputDefinitionTest.php | 363 +++ .../Console/Tests/Input/InputOptionTest.php | 192 ++ .../Component/Console/Tests/Input/InputTest.php | 117 + .../Console/Tests/Input/StringInputTest.php | 58 + .../Console/Tests/Output/ConsoleOutputTest.php | 24 + .../Console/Tests/Output/NullOutputTest.php | 24 + .../Component/Console/Tests/Output/OutputTest.php | 101 + .../Console/Tests/Output/StreamOutputTest.php | 59 + .../Console/Tests/Tester/ApplicationTesterTest.php | 64 + .../Console/Tests/Tester/CommandTesterTest.php | 62 + .../Symfony/Component/Console/Tests/bootstrap.php | 18 + .../Symfony/Component/Console/composer.json | 31 + .../Symfony/Component/Console/phpunit.xml.dist | 30 + 1324 files changed, 177529 insertions(+), 1 deletion(-) create mode 120000 vendor/bin/doctrine create mode 120000 vendor/bin/doctrine.php create mode 100644 vendor/doctrine/common/.gitignore create mode 100644 vendor/doctrine/common/.gitmodules create mode 100644 vendor/doctrine/common/.travis.yml create mode 100644 vendor/doctrine/common/LICENSE create mode 100644 vendor/doctrine/common/README.md create mode 100644 vendor/doctrine/common/UPGRADE_TO_2_1 create mode 100644 vendor/doctrine/common/UPGRADE_TO_2_2 create mode 100644 vendor/doctrine/common/bin/travis-setup.php create mode 100644 vendor/doctrine/common/build.properties create mode 100644 vendor/doctrine/common/build.xml create mode 100644 vendor/doctrine/common/composer.json create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Attribute.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Attributes.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Required.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Target.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationException.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationReader.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationRegistry.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/CachedReader.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/DocLexer.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/DocParser.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/FileCacheReader.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/IndexedReader.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/PhpParser.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/Reader.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Annotations/TokenParser.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/ApcCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/ArrayCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/Cache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/CacheProvider.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/FileCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/FilesystemCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/MemcacheCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/MemcachedCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/PhpFileCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/RedisCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/WinCacheCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/XcacheCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Cache/ZendDataCache.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/ArrayCollection.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/Collection.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/Criteria.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Comparison.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Expression.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Value.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/ExpressionBuilder.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Collections/Selectable.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/CommonException.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Comparable.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/EventArgs.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/EventManager.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/EventSubscriber.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Lexer.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/NotifyPropertyChanged.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/AbstractManagerRegistry.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/ConnectionRegistry.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LifecycleEventArgs.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LoadClassMetadataEventArgs.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/ManagerEventArgs.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/OnClearEventArgs.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/PreUpdateEventArgs.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/ManagerRegistry.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadata.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadataFactory.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/AnnotationDriver.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/DefaultFileLocator.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileDriver.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileLocator.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriver.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriverChain.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/PHPDriver.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/StaticPHPDriver.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/SymfonyFileLocator.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/MappingException.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ReflectionService.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/StaticReflectionService.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManager.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManagerAware.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectRepository.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/PersistentObject.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Persistence/Proxy.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/PropertyChangedListener.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Reflection/ClassFinderInterface.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Reflection/Psr0FindFile.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Reflection/ReflectionProviderInterface.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionClass.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionMethod.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionProperty.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Util/Inflector.php create mode 100644 vendor/doctrine/common/lib/Doctrine/Common/Version.php create mode 100644 vendor/doctrine/common/phpunit.xml.dist create mode 100644 vendor/doctrine/common/tests/.gitignore create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/AbstractReaderTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/CachedReaderTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DocLexerTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DocParserTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DummyClass.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/FileCacheReaderTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/AnnotWithDefaultValue.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Autoload.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Route.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Secure.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Template.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Version.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationTargetAll.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationTargetAnnotation.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationTargetClass.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationTargetMethod.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationTargetPropertyMethod.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithAttributes.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithConstants.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithRequiredAttributes.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithRequiredAttributesWithoutContructor.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithTargetSyntaxError.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithVarType.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassDDC1660.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithAnnotationWithTargetSyntaxError.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithAnnotationWithVarType.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithClosure.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithConstants.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithFullyQualifiedUseStatements.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithInvalidAnnotationTargetAtClass.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithInvalidAnnotationTargetAtMethod.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithInvalidAnnotationTargetAtProperty.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithValidAnnotationTarget.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Controller.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/DifferentNamespacesPerFileWithClassAsFirst.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/DifferentNamespacesPerFileWithClassAsLast.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/EqualNamespacesPerFileWithClassAsFirst.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/EqualNamespacesPerFileWithClassAsLast.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/GlobalNamespacesPerFileWithClassAsFirst.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/GlobalNamespacesPerFileWithClassAsLast.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/IntefaceWithConstants.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/InvalidAnnotationUsageButIgnoredClass.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/InvalidAnnotationUsageClass.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/MultipleClassesInFile.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/MultipleImportsInUseStatement.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NamespaceAndClassCommentedOut.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NamespaceWithClosureDeclaration.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NamespacedSingleClassLOC1000.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NoAnnotation.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NonNamespacedClass.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/SingleClassLOC1000.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/TestInterface.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/PerformanceTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/PhpParserTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/SimpleAnnotationReaderTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM55Test.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM58Entity.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM58Test.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/TopLevelAnnotation.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/ApcCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/CacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/XcacheCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/ZendDataCacheTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest/ClassA.class.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest/ClassB.class.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest/ClassC.class.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest/ClassD.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/ClosureExpressionVisitorTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/CollectionTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/CriteriaTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/ExpressionBuilderTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/DoctrineExceptionTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/EventManagerTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/ChainDriverTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/DefaultFileLocatorTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/FileDriverTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/PHPDriverTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/RuntimeReflectionServiceTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticPHPDriverTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticReflectionServiceTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/SymfonyFileLocatorTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/TestEntity.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/global.yml create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/stdClass.yml create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/PersistentObjectTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/DeeperNamespaceParent.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/Dummies/NoParent.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/FullyClassifiedParent.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/NoParent.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/SameNamespaceParent.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/StaticReflectionParserTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/UseParent.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Util/ClassUtilsTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/Common/Util/DebugTest.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/DoctrineTestCase.php create mode 100644 vendor/doctrine/common/tests/Doctrine/Tests/TestInit.php create mode 100644 vendor/doctrine/common/tests/NativePhpunitTask.php create mode 100644 vendor/doctrine/common/tests/README.markdown create mode 100644 vendor/doctrine/dbal/.gitignore create mode 100644 vendor/doctrine/dbal/.gitmodules create mode 100644 vendor/doctrine/dbal/.travis.yml create mode 100644 vendor/doctrine/dbal/LICENSE create mode 100644 vendor/doctrine/dbal/README.md create mode 100644 vendor/doctrine/dbal/UPGRADE create mode 100644 vendor/doctrine/dbal/bin/doctrine-dbal create mode 100644 vendor/doctrine/dbal/bin/doctrine-dbal.php create mode 100644 vendor/doctrine/dbal/bin/doctrine.php create mode 100644 vendor/doctrine/dbal/build.properties create mode 100644 vendor/doctrine/dbal/build.xml create mode 100644 vendor/doctrine/dbal/composer.json create mode 100644 vendor/doctrine/dbal/docs/design/AZURE_FEDERATIONS.md create mode 100644 vendor/doctrine/dbal/docs/design/SHARDING.md create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/README.md create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/bootstrap.php create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/composer.json create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/create_schema.php create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/insert_data.php create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/insert_data_aftersplit.php create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/query_filtering_off.php create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/query_filtering_on.php create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/split_federation.php create mode 100644 vendor/doctrine/dbal/docs/examples/sharding/view_federation_members.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ArrayStatement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/CacheException.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/QueryCacheProfile.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Configuration.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Connection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Connection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ResultStatement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/LastInsertId.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Statement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/DriverManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Events.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGenerator.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/LockMode.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/LoggerChain.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/SQLLogger.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DrizzleKeywords.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/KeywordList.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQLKeywords.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQLKeywords.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/ReservedKeywordsValidator.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLiteKeywords.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2008Platform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Connection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Statement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryException.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/README.markdown create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractAsset.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Column.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ColumnDiff.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Comparator.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Constraint.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Index.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Schema.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaConfig.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaDiff.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaException.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Sequence.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizer.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Table.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/TableDiff.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/View.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/CreateSchemaSqlCollector.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/RemoveNamespacedAssets.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Visitor.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/ShardChoser.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardManager.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardingException.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ArrayType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BlobType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BooleanType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DecimalType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/FloatType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/GuidType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/IntegerType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/JsonArrayType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SimpleArrayType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SmallIntType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/StringType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TextType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Type.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php create mode 100644 vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php create mode 100644 vendor/doctrine/dbal/phpunit.xml.dist create mode 100644 vendor/doctrine/dbal/run-all.sh create mode 100644 vendor/doctrine/dbal/tests/.gitignore create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/ConnectionTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/DriverManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/MysqlSessionInitTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/OracleSessionInitTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/SQLSessionInitTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/BlobTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/LoggingTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/MasterSlaveConnectionTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/NamedParametersTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/PortabilityTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ResultCacheTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/Db2SchemaManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/MySqlSchemaManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLServerSchemaManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TemporaryTableTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL168Test.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL202Test.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TypeConversionTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Mocks/MockPlatform.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/ReservedKeywordsValidatorTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/ColumnTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/IndexTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Platforms/MySQLSchemaTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SequenceTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/TableTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Visitor/RemoveNamespacedAssetsTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Visitor/SchemaSqlCollectorTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/FunctionalTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/MultiTenantVisitorTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureShardManagerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/ShardChoser/MultiTenantShardChoserTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/ArrayTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/BlobTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/BooleanTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DecimalTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/FloatTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/GuidTypeTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/IntegerTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/ObjectTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/SmallIntTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/StringTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/TimeTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/VarDateTimeTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/UtilTest.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DbalFunctionalTestCase.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DbalTestCase.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/DoctrineTestCase.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/ConnectionMock.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/DriverMock.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/HydratorMockStatement.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/SchemaManagerMock.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/TaskMock.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/TestInit.php create mode 100644 vendor/doctrine/dbal/tests/Doctrine/Tests/TestUtil.php create mode 100644 vendor/doctrine/dbal/tests/README.markdown create mode 100644 vendor/doctrine/dbal/tests/travis/mysql.travis.xml create mode 100644 vendor/doctrine/dbal/tests/travis/mysqli.travis.xml create mode 100644 vendor/doctrine/dbal/tests/travis/pgsql.travis.xml create mode 100644 vendor/doctrine/dbal/tests/travis/sqlite.travis.xml create mode 100644 vendor/doctrine/orm/.gitignore create mode 100644 vendor/doctrine/orm/.gitmodules create mode 100644 vendor/doctrine/orm/.travis.yml create mode 100644 vendor/doctrine/orm/LICENSE create mode 100644 vendor/doctrine/orm/README.markdown create mode 100644 vendor/doctrine/orm/UPGRADE.md create mode 100755 vendor/doctrine/orm/bin/doctrine create mode 100644 vendor/doctrine/orm/bin/doctrine-pear.php create mode 100644 vendor/doctrine/orm/bin/doctrine.bat create mode 100755 vendor/doctrine/orm/bin/doctrine.php create mode 100644 vendor/doctrine/orm/build.properties create mode 100644 vendor/doctrine/orm/build.properties.dev create mode 100644 vendor/doctrine/orm/build.xml create mode 100644 vendor/doctrine/orm/composer.json create mode 100644 vendor/doctrine/orm/doctrine-mapping.xsd create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Configuration.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/EntityNotFoundException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Event/LifecycleEventArgs.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Event/OnClearEventArgs.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Event/OnFlushEventArgs.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Event/PostFlushEventArgs.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Event/PreFlushEventArgs.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Events.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Id/AbstractIdGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Id/AssignedGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Id/IdentityGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Id/SequenceGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Id/TableGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Id/UuidGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Internal/CommitOrderCalculator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/HydrationException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/IterableResult.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ScalarHydrator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Annotation.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AssociationOverride.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AssociationOverrides.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AttributeOverride.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AttributeOverrides.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/ManyToManyAssociationBuilder.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/OneToManyAssociationBuilder.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadata.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Column.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ColumnResult.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultNamingStrategy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DriverChain.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ElementCollection.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Entity.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/EntityResult.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/FieldResult.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/GeneratedValue.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Id.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Index.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/InheritanceType.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinColumn.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinColumns.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinTable.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ManyToMany.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ManyToOne.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappedSuperclass.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappingException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedNativeQueries.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedNativeQuery.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedQueries.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedQuery.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamingStrategy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OneToMany.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OneToOne.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OrderBy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostLoad.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostPersist.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostRemove.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostUpdate.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreFlush.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PrePersist.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreRemove.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreUpdate.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/QuoteStrategy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SequenceGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SqlResultSetMapping.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SqlResultSetMappings.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Table.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/UnderscoreNamingStrategy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/UniqueConstraint.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Version.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/NativeQuery.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/NoResultException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/NonUniqueResultException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/ORMException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/ORMInvalidArgumentException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/OptimisticLockException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/AbstractCollectionPersister.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/ElementCollectionPersister.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/OneToManyPersister.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SingleTablePersister.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SqlExpressionVisitor.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SqlValueVisitor.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/UnionSubclassPersister.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/PessimisticLockException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Autoloader.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Proxy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyFactory.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ASTException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/AggregateExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/BetweenExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/CoalesceExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/CollectionMemberExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ComparisonExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalFactor.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalTerm.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/DeleteClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/DeleteStatement.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/EmptyCollectionComparisonExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ExistsExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/FromClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/ConcatFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimestampFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateDiffFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/FunctionNode.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LengthFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LocateFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LowerFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/TrimFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/UpperFunction.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/GeneralCaseExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/GroupByClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/HavingClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/IndexBy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InputParameter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Join.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinAssociationDeclaration.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinAssociationPathExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinClassPathExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/LikeExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Literal.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Node.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/NullComparisonExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/NullIfExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/OrderByClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/OrderByItem.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/PartialObjectExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/PathExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/QuantifiedExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectStatement.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleArithmeticExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleCaseExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleWhenClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Subselect.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SubselectFromClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateItem.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateStatement.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/WhenClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/WhereClause.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/SingleSelectExecutor.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/SingleTableDeleteUpdateExecutor.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Andx.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Base.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Comparison.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Composite.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/From.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Func.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/GroupBy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Join.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Literal.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Math.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/OrderBy.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Orx.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Select.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Filter/SQLFilter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/FilterCollection.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Lexer.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parameter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/ParameterTypeInferer.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/ParserResult.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/Printer.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/ResultSetMapping.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalker.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalkerAdapter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalkerChain.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/QueryBuilder.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/README.markdown create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/EnsureProductionSettingsCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/InfoCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/AbstractCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/MetadataFilter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/DebugUnitOfWorkListener.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/DisconnectedClassMetadataFactory.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/EntityGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/EntityRepositoryGenerator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Event/GenerateSchemaEventArgs.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Event/GenerateSchemaTableEventArgs.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/ExportException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/CountOutputWalker.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/CountWalker.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/Paginator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/SchemaTool.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/SchemaValidator.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Setup.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ToolEvents.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ToolsException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/TransactionRequiredException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/UnexpectedResultException.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php create mode 100644 vendor/doctrine/orm/lib/Doctrine/ORM/Version.php create mode 100644 vendor/doctrine/orm/phpunit.xml.dist create mode 100644 vendor/doctrine/orm/run-all.sh create mode 100644 vendor/doctrine/orm/tests/.gitignore create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/DbalFunctionalTestCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/DbalTestCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/DoctrineTestCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/ClassMetadataMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/ConnectionMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/DriverMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/EntityManagerMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/EntityPersisterMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/HydratorMockStatement.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/IdentityIdGeneratorMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/MetadataDriverMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/MockTreeWalker.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/SchemaManagerMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/SequenceMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/StatementMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/TaskMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/UnitOfWorkMock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsAddress.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsArticle.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsComment.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsEmail.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsEmployee.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsGroup.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsPhonenumber.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsUser.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyAuction.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyCar.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyContract.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyEmployee.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyEvent.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFixContract.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContract.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyManager.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyOrganization.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyPerson.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyRaffle.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CustomType/CustomTypeParent.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/CustomType/CustomTypeUpperCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117ApproveChanges.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Article.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117ArticleDetails.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Editor.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Link.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Reference.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Translation.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC1476/DDC1476EntityWithDefaultFieldType.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753CustomRepository.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753DefaultRepository.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithCustomRepository.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithDefaultCustomRepository.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithInvalidRepository.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753InvalidRepository.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869CreditCardPayment.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869PaymentRepository.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889Class.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889Entity.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889SuperClass.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Address.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Admin.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Group.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Guest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964User.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/AbstractContentItem.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/Directory.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/File.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCart.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCategory.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCustomer.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceFeature.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceProduct.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceShipping.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumAdministrator.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumAvatar.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumBoard.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumCategory.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumEntry.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumUser.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Generic/BooleanModel.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Generic/DateTimeModel.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Generic/DecimalModel.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Generic/SerializationModel.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Global/GlobalNamespaceModel.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/JoinedInheritanceType/AnotherChildClass.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/JoinedInheritanceType/ChildClass.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/JoinedInheritanceType/RootClass.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyArticle.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyCar.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyUser.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyUserReference.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavCountry.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavPhotos.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavPointOfInterest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavTour.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavUser.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Address.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Group.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Phone.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/SimpleEntity.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/User.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingLeg.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingLocation.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingRoute.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingRouteBooking.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Bond.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Market.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Stock.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/ConfigurationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Criteria/DqlGenerationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Entity/ConstructorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/EntityManagerTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AbstractManyToManyAssociationTestCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AdvancedAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AdvancedDqlQueryTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest2.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClearEventTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/CompositePrimaryKeyTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/CustomTreeWalkersTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DefaultValuesTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryCriteriaTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/FlushEventTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/HydrationCacheTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/IdentityMapTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/IndexByAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/LifecycleCallbackTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/GearmanLockTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/LockAgentWorker.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/LockTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/OptimisticTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyBasicAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyBidirectionalAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyEventTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManySelfReferentialAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyUnidirectionalAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/MappedSuperclassTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/NotifyPolicyTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyBidirectionalAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyOrphanRemovalTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManySelfReferentialAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyUnidirectionalAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneBidirectionalAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneEagerLoadingTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneOrphanRemovalTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneSelfReferentialAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneUnidirectionalAssociationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OrderedJoinedTableInheritanceCollectionTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PersistentCollectionTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PersistentObjectTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PostFlushEventTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryCacheTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ReadOnlyTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ResultCacheTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/CompanySchemaTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/DDC214Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/MySqlSchemaToolTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/PostgreSqlSchemaToolTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SequenceGeneratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1040Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1041Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1043Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1050Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1080Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1113Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1129Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1151Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC117Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1181Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1193Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1209Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1225Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1228Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1238Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1250Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1276Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1300Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1301Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1306Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1335Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1360Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1383Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1392Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1404Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC142Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1430Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1436Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC144Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1452Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1454Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1458Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1461Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1509Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1514Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1515Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1526Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1545Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1548Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1594Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1595Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC163Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1643Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1655Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1685Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC168Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1695Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1707Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1719Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1757Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1778Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1843Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1885Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1918Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC192Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC199Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC211Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC237Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC258Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC279Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC309Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC331Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC345Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC353Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC371Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC381Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC422Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC425Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC440Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC444Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC448Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC493Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC501Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC512Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC513Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC518Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC522Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC531Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC588Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC599Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC618Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC633Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC656Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC657Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC698Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC729Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC735Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC736Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC742Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC748Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC758Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC767Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC809Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC812Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC832Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC837Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC849Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC881Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC933Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC949Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC960Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC992Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket2481Test.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket69.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/TypeTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/UUIDGeneratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/UnitOfWorkLifecycleTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ArrayHydratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/CustomHydratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/HydrationTestCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ScalarHydratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/SimpleObjectHydratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/SingleScalarHydratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Id/AssignedGeneratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Id/SequenceGeneratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/BasicInheritanceMappingTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataLoadEventTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/NamingStrategyTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/PHPMappingDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/QuoteStrategyTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/StaticPHPMappingDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/XmlDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/YamlDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/YamlMappingDriverTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsUser.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Company.CompanyPerson.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869Payment.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC889.DDC889Class.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC889.DDC889Entity.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC889.DDC889SuperClass.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964Admin.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964Guest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964User.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.Animal.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.DDC1170Entity.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.DDC807Entity.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.User.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/CatNoId.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC117.DDC117Translation.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Animal.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsUser.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.AbstractContentItem.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.Directory.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.File.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.Animal.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/HydrationPerformanceTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/InheritancePersisterPerformanceTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/InsertPerformanceTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/PersisterPerformanceTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/UnitOfWorkPerformanceTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/AutoloaderTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/ProxyClassGeneratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/fixtures/NonNamespacedProxies.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/DeleteSqlGenerationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ExprTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/LexerTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ParameterTypeInfererTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ParserResultTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/QueryTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/QueryBuilderTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommandTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/ConvertDoctrine1SchemaTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/AbstractClassMetadataExporterTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/AnnotationClassMetadataExporterTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/ClassMetadataExporterTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/PhpClassMetadataExporterTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/XmlClassMetadataExporterTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/YamlClassMetadataExporterTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/annotation/Doctrine.Tests.ORM.Tools.Export.User.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/php/Doctrine.Tests.ORM.Tools.Export.User.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/yaml/Doctrine.Tests.ORM.Tools.Export.User.dcm.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/CountOutputWalkerTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/CountWalkerTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryWalkerTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/PaginationTestCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/WhereInWalkerTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/ResolveTargetEntityListenerTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SchemaToolTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SetupTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/doctrine1schema/schema.yml create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/OrmFunctionalTestCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/OrmPerformanceTestCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/OrmTestCase.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/TestInit.php create mode 100644 vendor/doctrine/orm/tests/Doctrine/Tests/TestUtil.php create mode 100644 vendor/doctrine/orm/tests/NativePhpunitTask.php create mode 100644 vendor/doctrine/orm/tests/README.markdown create mode 100644 vendor/doctrine/orm/tests/dbproperties.xml.dev create mode 100644 vendor/doctrine/orm/tests/travis/mysql.travis.xml create mode 100644 vendor/doctrine/orm/tests/travis/pgsql.travis.xml create mode 100644 vendor/doctrine/orm/tests/travis/sqlite.travis.xml create mode 100644 vendor/doctrine/orm/tools/sandbox/Entities/Address.php create mode 100644 vendor/doctrine/orm/tools/sandbox/Entities/User.php create mode 100644 vendor/doctrine/orm/tools/sandbox/cli-config.php create mode 100644 vendor/doctrine/orm/tools/sandbox/doctrine create mode 100644 vendor/doctrine/orm/tools/sandbox/doctrine.php create mode 100644 vendor/doctrine/orm/tools/sandbox/index.php create mode 100644 vendor/doctrine/orm/tools/sandbox/xml/Entities.Address.dcm.xml create mode 100644 vendor/doctrine/orm/tools/sandbox/xml/Entities.User.dcm.xml create mode 100644 vendor/doctrine/orm/tools/sandbox/yaml/Entities.Address.dcm.yml create mode 100644 vendor/doctrine/orm/tools/sandbox/yaml/Entities.User.dcm.yml create mode 100644 vendor/symfony/console/Symfony/Component/Console/Application.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/CHANGELOG.md create mode 100644 vendor/symfony/console/Symfony/Component/Console/Command/Command.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Command/HelpCommand.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Command/ListCommand.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatter.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterInterface.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyle.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Helper/DialogHelper.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Helper/FormatterHelper.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Helper/Helper.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Helper/HelperInterface.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Helper/HelperSet.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Input/ArgvInput.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Input/ArrayInput.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Input/Input.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Input/InputArgument.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Input/InputDefinition.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Input/InputInterface.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Input/InputOption.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Input/StringInput.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/LICENSE create mode 100644 vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutput.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutputInterface.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Output/NullOutput.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Output/Output.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Output/OutputInterface.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Output/StreamOutput.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/README.md create mode 100644 vendor/symfony/console/Symfony/Component/Console/Shell.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tester/ApplicationTester.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tester/CommandTester.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/ApplicationTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Command/CommandTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Command/HelpCommandTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Command/ListCommandTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo1Command.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo2Command.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo3Command.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/FooCommand.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/TestCommand.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_astext1.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_astext2.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_asxml1.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_asxml2.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_gethelp.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception1.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception2.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception4.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run1.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run2.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run3.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run4.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/command_astext.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/command_asxml.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/definition_astext.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/definition_asxml.txt create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleStackTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Helper/DialogHelperTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Helper/FormatterHelperTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Input/ArgvInputTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Input/ArrayInputTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputArgumentTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputDefinitionTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputOptionTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Input/StringInputTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Output/ConsoleOutputTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Output/NullOutputTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Output/OutputTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Output/StreamOutputTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Tester/ApplicationTesterTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/Tests/bootstrap.php create mode 100644 vendor/symfony/console/Symfony/Component/Console/composer.json create mode 100644 vendor/symfony/console/Symfony/Component/Console/phpunit.xml.dist diff --git a/composer.json b/composer.json index bf20819..f534441 100644 --- a/composer.json +++ b/composer.json @@ -9,6 +9,7 @@ "homepage": "http://zf2.biz/", "require": { "php": ">=5.3.3", - "zendframework/zendframework": "2.*" + "zendframework/zendframework": "2.*", + "doctrine/orm": "2.3" } } diff --git a/vendor/bin/doctrine b/vendor/bin/doctrine new file mode 120000 index 0000000..bb22173 --- /dev/null +++ b/vendor/bin/doctrine @@ -0,0 +1 @@ +../doctrine/orm/bin/doctrine \ No newline at end of file diff --git a/vendor/bin/doctrine.php b/vendor/bin/doctrine.php new file mode 120000 index 0000000..267c853 --- /dev/null +++ b/vendor/bin/doctrine.php @@ -0,0 +1 @@ +../doctrine/orm/bin/doctrine.php \ No newline at end of file diff --git a/vendor/doctrine/common/.gitignore b/vendor/doctrine/common/.gitignore new file mode 100644 index 0000000..fb5e79d --- /dev/null +++ b/vendor/doctrine/common/.gitignore @@ -0,0 +1,4 @@ +build/ +logs/ +reports/ +dist/ diff --git a/vendor/doctrine/common/.gitmodules b/vendor/doctrine/common/.gitmodules new file mode 100644 index 0000000..51f0843 --- /dev/null +++ b/vendor/doctrine/common/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/vendor/doctrine-build-common"] + path = lib/vendor/doctrine-build-common + url = git://github.com/doctrine/doctrine-build-common.git diff --git a/vendor/doctrine/common/.travis.yml b/vendor/doctrine/common/.travis.yml new file mode 100644 index 0000000..fc05056 --- /dev/null +++ b/vendor/doctrine/common/.travis.yml @@ -0,0 +1,10 @@ +language: php + +env: + - OPCODE_CACHE=apc + +php: + - 5.3 + - 5.4 + +before_script: php ./bin/travis-setup.php $OPCODE_CACHE \ No newline at end of file diff --git a/vendor/doctrine/common/LICENSE b/vendor/doctrine/common/LICENSE new file mode 100644 index 0000000..4a91f0b --- /dev/null +++ b/vendor/doctrine/common/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2012 Doctrine Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/doctrine/common/README.md b/vendor/doctrine/common/README.md new file mode 100644 index 0000000..c63f762 --- /dev/null +++ b/vendor/doctrine/common/README.md @@ -0,0 +1,12 @@ +# Doctrine Common + +[![Build Status](https://secure.travis-ci.org/doctrine/common.png)](http://travis-ci.org/doctrine/common) + +The Doctrine Common project is a library that provides extensions to core PHP functionality. + +## More resources: + +* [Website](http://www.doctrine-project.org) +* [Documentation](http://www.doctrine-project.org/projects/common/current/docs/en) +* [Issue Tracker](http://www.doctrine-project.org/jira/browse/DCOM) +* [Downloads](http://github.com/doctrine/common/downloads) diff --git a/vendor/doctrine/common/UPGRADE_TO_2_1 b/vendor/doctrine/common/UPGRADE_TO_2_1 new file mode 100644 index 0000000..891a2e5 --- /dev/null +++ b/vendor/doctrine/common/UPGRADE_TO_2_1 @@ -0,0 +1,39 @@ +This document details all the possible changes that you should investigate when updating +your project from Doctrine Common 2.0.x to 2.1 + +## AnnotationReader changes + +The annotation reader was heavily refactored between 2.0 and 2.1-RC1. In theory the operation of the new reader should be backwards compatible, but it has to be setup differently to work that way: + + $reader = new \Doctrine\Common\Annotations\AnnotationReader(); + $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); + // new code necessary starting here + $reader->setIgnoreNotImportedAnnotations(true); + $reader->setEnableParsePhpImports(false); + $reader = new \Doctrine\Common\Annotations\CachedReader( + new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache() + ); + +## Annotation Base class or @Annotation + +Beginning after 2.1-RC2 you have to either extend ``Doctrine\Common\Annotations\Annotation`` or add @Annotation to your annotations class-level docblock, otherwise the class will simply be ignored. + +## Removed methods on AnnotationReader + +* AnnotationReader::setAutoloadAnnotations() +* AnnotationReader::getAutoloadAnnotations() +* AnnotationReader::isAutoloadAnnotations() + +## AnnotationRegistry + +Autoloading through the PHP autoloader is removed from the 2.1 AnnotationReader. Instead you have to use the global AnnotationRegistry for loading purposes: + + \Doctrine\Common\Annotations\AnnotationRegistry::registerFile($fileWithAnnotations); + \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace($namespace, $dirs = null); + \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespaces($namespaces); + \Doctrine\Common\Annotations\AnnotationRegistry::registerLoader($callable); + +The $callable for registering a loader accepts a class as first and only parameter and must try to silently autoload it. On success true has to be returned. +The registerAutoloadNamespace function registers a PSR-0 compatible silent autoloader for all classes with the given namespace in the given directories. +If null is passed as directory the include path will be used. + diff --git a/vendor/doctrine/common/UPGRADE_TO_2_2 b/vendor/doctrine/common/UPGRADE_TO_2_2 new file mode 100644 index 0000000..1d93a13 --- /dev/null +++ b/vendor/doctrine/common/UPGRADE_TO_2_2 @@ -0,0 +1,61 @@ +This document details all the possible changes that you should investigate when +updating your project from Doctrine Common 2.1 to 2.2: + +## Annotation Changes + +- AnnotationReader::setIgnoreNotImportedAnnotations has been removed, you need to + add ignore annotation names which are supposed to be ignored via + AnnotationReader::addGlobalIgnoredName + +- AnnotationReader::setAutoloadAnnotations was deprecated by the AnnotationRegistry + in 2.1 and has been removed in 2.2 + +- AnnotationReader::setEnableParsePhpImports was added to ease transition to the new + annotation mechanism in 2.1 and is removed in 2.2 + +- AnnotationReader::isParsePhpImportsEnabled is removed (see above) + +- AnnotationReader::setDefaultAnnotationNamespace was deprecated in favor of explicit + configuration in 2.1 and will be removed in 2.2 (for isolated projects where you + have full-control over _all_ available annotations, we offer a dedicated reader + class ``SimpleAnnotationReader``) + +- AnnotationReader::setAnnotationCreationFunction was deprecated in 2.1 and will be + removed in 2.2. We only offer two creation mechanisms which cannot be changed + anymore to allow the same reader instance to work with all annotations regardless + of which library they are coming from. + +- AnnotationReader::setAnnotationNamespaceAlias was deprecated in 2.1 and will be + removed in 2.2 (see setDefaultAnnotationNamespace) + +- If you use a class as annotation which has not the @Annotation marker in it's + class block, we will now throw an exception instead of silently ignoring it. You + can however still achieve the previous behavior using the @IgnoreAnnotation, or + AnnotationReader::addGlobalIgnoredName (the exception message will contain detailed + instructions when you run into this problem). + +## Cache Changes + +- Renamed old AbstractCache to CacheProvider + +- Dropped the support to the following functions of all cache providers: + + - CacheProvider::deleteByWildcard + + - CacheProvider::deleteByRegEx + + - CacheProvider::deleteByPrefix + + - CacheProvider::deleteBySuffix + +- CacheProvider::deleteAll will not remove ALL entries, it will only mark them as invalid + +- CacheProvider::flushAll will remove ALL entries, namespaced or not + +- Added support to MemcachedCache + +- Added support to WincacheCache + +## ClassLoader Changes + +- ClassLoader::fileExistsInIncludePath() no longer exists. Use the native stream_resolve_include_path() PHP function \ No newline at end of file diff --git a/vendor/doctrine/common/bin/travis-setup.php b/vendor/doctrine/common/bin/travis-setup.php new file mode 100644 index 0000000..e9c355a --- /dev/null +++ b/vendor/doctrine/common/bin/travis-setup.php @@ -0,0 +1,141 @@ +. + */ + +/** + * Install PHP extensions required for testing by Travis CI. + * + * @author Victor Berchet + * @since 2.2 + */ +$installer = new PhpExtensions(); + +if (isset($argv[1]) && 'APC' === strtoupper($argv[1])) { + $installer->install('apc'); +} else { + $installer->install('xcache'); +} + +$installer->install('memcache'); +$installer->install('memcached'); + +class PhpExtensions +{ + protected $extensions; + protected $phpVersion; + protected $iniPath; + + public function __construct() + { + $this->phpVersion = phpversion(); + $this->iniPath = php_ini_loaded_file(); + $this->extensions = array( + 'memcache' => array( + 'url' => 'http://pecl.php.net/get/memcache-2.2.6.tgz', + 'php_version' => array(), + 'cfg' => array('--enable-memcache'), + 'ini' => array('extension=memcache.so'), + ), + 'memcached' => array( + 'url' => 'http://pecl.php.net/get/memcached-1.0.2.tgz', + 'php_version' => array( + // memcached 1.0.2 does not build on PHP 5.4 + array('<', '5.4'), + ), + 'cfg' => array(), + 'ini' => array('extension=memcached.so'), + ), + 'apc' => array( + 'url' => 'http://pecl.php.net/get/APC-3.1.9.tgz', + 'php_version' => array( + // apc 3.1.9 causes a segfault on PHP 5.4 + array('<', '5.4'), + ), + 'cfg' => array(), + 'ini' => array( + 'extension=apc.so', + 'apc.enabled=1', + 'apc.enable_cli=1' + ), + ), + 'xcache' => array( + 'url' => 'http://xcache.lighttpd.net/pub/Releases/1.2.2/xcache-1.2.2.tar.gz', + 'php_version' => array( + // xcache does not build with Travis CI (as of 2012-01-09) + array('<', '5'), + ), + 'cfg' => array('--enable-xcache'), + 'ini' => array( + 'extension=xcache.so', + 'xcache.cacher=false', + 'xcache.admin.enable_auth=0', + 'xcache.var_size=1M', + ), + ), + ); + } + + public function install($name) + { + if (array_key_exists($name, $this->extensions)) { + $extension = $this->extensions[$name]; + + + echo "== extension: $name ==\n"; + + foreach ($extension['php_version'] as $version) { + if (!version_compare($this->phpVersion, $version[1], $version[0])) { + printf( + "=> not installed, requires a PHP version %s %s (%s installed)\n", + $version[0], + $version[1], + $this->phpVersion + ); + + return; + } + } + + $this->system(sprintf("wget %s > /dev/null 2>&1", $extension['url'])); + $file = basename($extension['url']); + $this->system(sprintf("tar -xzf %s > /dev/null 2>&1", $file)); + $folder = basename($file, ".tgz"); + $folder = basename($folder, ".tar.gz"); + $this->system(sprintf( + 'sh -c "cd %s && phpize && ./configure %s && make && sudo make install" > /dev/null 2>&1', + $folder, + implode(' ', $extension['cfg']) + )); + foreach ($extension['ini'] as $ini) { + $this->system(sprintf("echo %s >> %s", $ini, $this->iniPath)); + } + printf("=> installed (%s)\n", $folder); + } + } + + private function system($cmd) + { + $ret = 0; + system($cmd, $ret); + if (0 !== $ret) { + printf("=> Command '%s' failed !", $cmd); + + exit($ret); + } + } +} diff --git a/vendor/doctrine/common/build.properties b/vendor/doctrine/common/build.properties new file mode 100644 index 0000000..ff311a4 --- /dev/null +++ b/vendor/doctrine/common/build.properties @@ -0,0 +1,6 @@ +# Project Name +project.name=DoctrineCommon + +# Version class and file +project.version_class = Doctrine\Common\Version +project.version_file = lib/Doctrine/Common/Version.php diff --git a/vendor/doctrine/common/build.xml b/vendor/doctrine/common/build.xml new file mode 100644 index 0000000..71a9a50 --- /dev/null +++ b/vendor/doctrine/common/build.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DoctrineCommon + Doctrine Common PHP Extensions + pear.doctrine-project.org + The Doctrine Common package contains shared code between the other packages. + + + + + LGPL + + + - + + + + + + + diff --git a/vendor/doctrine/common/composer.json b/vendor/doctrine/common/composer.json new file mode 100644 index 0000000..c87258d --- /dev/null +++ b/vendor/doctrine/common/composer.json @@ -0,0 +1,26 @@ +{ + "name": "doctrine/common", + "type": "library", + "description": "Common Library for Doctrine projects", + "keywords": ["collections", "spl", "eventmanager", "annotations", "persistence"], + "homepage": "http://www.doctrine-project.org", + "license": "MIT", + "authors": [ + {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, + {"name": "Roman Borschel", "email": "roman@code-factory.org"}, + {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, + {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, + {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} + ], + "require": { + "php": ">=5.3.2" + }, + "autoload": { + "psr-0": { "Doctrine\\Common": "lib/" } + }, + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation.php new file mode 100644 index 0000000..6a1390a --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation.php @@ -0,0 +1,79 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +/** + * Annotations class + * + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Annotation +{ + /** + * Value property. Common among all derived classes. + * + * @var string + */ + public $value; + + /** + * Constructor + * + * @param array $data Key-value for properties to be defined in this class + */ + public final function __construct(array $data) + { + foreach ($data as $key => $value) { + $this->$key = $value; + } + } + + /** + * Error handler for unknown property accessor in Annotation class. + * + * @param string $name Unknown property name + * + * @throws \BadMethodCallException + */ + public function __get($name) + { + throw new \BadMethodCallException( + sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this)) + ); + } + + /** + * Error handler for unknown property mutator in Annotation class. + * + * @param string $name Unkown property name + * @param mixed $value Property value + * + * @throws \BadMethodCallException + */ + public function __set($name, $value) + { + throw new \BadMethodCallException( + sprintf("Unknown property '%s' on annotation '%s'.", $name, get_class($this)) + ); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Attribute.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Attribute.php new file mode 100644 index 0000000..dbef6df --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Attribute.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\Common\Annotations\Annotation; + +/** + * Annotation that can be used to signal to the parser + * to check the attribute type during the parsing process. + * + * @author Fabio B. Silva + * + * @Annotation + */ +final class Attribute +{ + /** + * @var string + */ + public $name; + + /** + * @var string + */ + public $type; + + /** + * @var boolean + */ + public $required = false; +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Attributes.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Attributes.php new file mode 100644 index 0000000..53134e3 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Attributes.php @@ -0,0 +1,37 @@ +. + */ + +namespace Doctrine\Common\Annotations\Annotation; + +/** + * Annotation that can be used to signal to the parser + * to check the types of all declared attributes during the parsing process. + * + * @author Fabio B. Silva + * + * @Annotation + */ +final class Attributes +{ + /** + * @var array + */ + public $value; +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php new file mode 100644 index 0000000..a84a4f5 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php @@ -0,0 +1,54 @@ +. + */ + +namespace Doctrine\Common\Annotations\Annotation; + +/** + * Annotation that can be used to signal to the parser to ignore specific + * annotations during the parsing process. + * + * @Annotation + * @author Johannes M. Schmitt + */ +final class IgnoreAnnotation +{ + /** + * @var array + */ + public $names; + + /** + * Constructor + * + * @param array $values + * + * @throws \RuntimeException + */ + public function __construct(array $values) + { + if (is_string($values['value'])) { + $values['value'] = array($values['value']); + } + if (!is_array($values['value'])) { + throw new \RuntimeException(sprintf('@IgnoreAnnotation expects either a string name, or an array of strings, but got %s.', json_encode($values['value']))); + } + + $this->names = $values['value']; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Required.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Required.php new file mode 100644 index 0000000..d67f960 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Required.php @@ -0,0 +1,33 @@ +. + */ + +namespace Doctrine\Common\Annotations\Annotation; + +/** + * Annotation that can be used to signal to the parser + * to check if that attribute is required during the parsing process. + * + * @author Fabio B. Silva + * + * @Annotation + */ +final class Required +{ +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Target.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Target.php new file mode 100644 index 0000000..64655ef --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Annotation/Target.php @@ -0,0 +1,107 @@ +. + */ + +namespace Doctrine\Common\Annotations\Annotation; + +/** + * Annotation that can be used to signal to the parser + * to check the annotation target during the parsing process. + * + * @author Fabio B. Silva + * + * @Annotation + */ +final class Target +{ + const TARGET_CLASS = 1; + const TARGET_METHOD = 2; + const TARGET_PROPERTY = 4; + const TARGET_ANNOTATION = 8; + const TARGET_ALL = 15; + + /** + * @var array + */ + private static $map = array( + 'ALL' => self::TARGET_ALL, + 'CLASS' => self::TARGET_CLASS, + 'METHOD' => self::TARGET_METHOD, + 'PROPERTY' => self::TARGET_PROPERTY, + 'ANNOTATION' => self::TARGET_ANNOTATION, + ); + + /** + * @var array + */ + public $value; + + /** + * Targets as bitmask. + * + * @var integer + */ + public $targets; + + /** + * Literal target declaration. + * + * @var integer + */ + public $literal; + + /** + * Annotation construct + * + * @param array $values + * + * @throws \InvalidArgumentException + */ + public function __construct(array $values) + { + if (!isset($values['value'])){ + $values['value'] = null; + } + if (is_string($values['value'])){ + $values['value'] = array($values['value']); + } + if (!is_array($values['value'])){ + throw new \InvalidArgumentException( + sprintf('@Target expects either a string value, or an array of strings, "%s" given.', + is_object($values['value']) ? get_class($values['value']) : gettype($values['value']) + ) + ); + } + + $bitmask = 0; + foreach ($values['value'] as $literal) { + if(!isset(self::$map[$literal])){ + throw new \InvalidArgumentException( + sprintf('Invalid Target "%s". Available targets: [%s]', + $literal, implode(', ', array_keys(self::$map))) + ); + } + $bitmask += self::$map[$literal]; + } + + $this->targets = $bitmask; + $this->value = $values['value']; + $this->literal = implode(', ', $this->value); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationException.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationException.php new file mode 100644 index 0000000..109beeb --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationException.php @@ -0,0 +1,127 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +/** + * Description of AnnotationException + * + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class AnnotationException extends \Exception +{ + /** + * Creates a new AnnotationException describing a Syntax error. + * + * @param string $message Exception message + * @return AnnotationException + */ + public static function syntaxError($message) + { + return new self('[Syntax Error] ' . $message); + } + + /** + * Creates a new AnnotationException describing a Semantical error. + * + * @param string $message Exception message + * @return AnnotationException + */ + public static function semanticalError($message) + { + return new self('[Semantical Error] ' . $message); + } + + /** + * Creates a new AnnotationException describing a constant semantical error. + * + * @since 2.3 + * @param string $identifier + * @param string $context + * @return AnnotationException + */ + public static function semanticalErrorConstants($identifier, $context = null) + { + return self::semanticalError(sprintf( + "Couldn't find constant %s%s", $identifier, + $context ? ", $context." : "." + )); + } + + /** + * Creates a new AnnotationException describing an error which occurred during + * the creation of the annotation. + * + * @since 2.2 + * @param string $message + * @return AnnotationException + */ + public static function creationError($message) + { + return new self('[Creation Error] ' . $message); + } + + /** + * Creates a new AnnotationException describing an type error of an attribute. + * + * @since 2.2 + * @param string $attributeName + * @param string $annotationName + * @param string $context + * @param string $expected + * @param mixed $actual + * @return AnnotationException + */ + public static function typeError($attributeName, $annotationName, $context, $expected, $actual) + { + return new self(sprintf( + '[Type Error] Attribute "%s" of @%s declared on %s expects %s, but got %s.', + $attributeName, + $annotationName, + $context, + $expected, + is_object($actual) ? 'an instance of '.get_class($actual) : gettype($actual) + )); + } + + /** + * Creates a new AnnotationException describing an required error of an attribute. + * + * @since 2.2 + * @param string $attributeName + * @param string $annotationName + * @param string $context + * @param string $expected + * @return AnnotationException + */ + public static function requiredError($attributeName, $annotationName, $context, $expected) + { + return new self(sprintf( + '[Type Error] Attribute "%s" of @%s declared on %s expects %s. This value should not be null.', + $attributeName, + $annotationName, + $context, + $expected + )); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationReader.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationReader.php new file mode 100644 index 0000000..286e7d0 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationReader.php @@ -0,0 +1,310 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +use Doctrine\Common\Annotations\Annotation\IgnoreAnnotation; +use Doctrine\Common\Annotations\Annotation\Target; +use Closure; +use ReflectionClass; +use ReflectionMethod; +use ReflectionProperty; + +/** + * A reader for docblock annotations. + * + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Johannes M. Schmitt + */ +class AnnotationReader implements Reader +{ + /** + * Global map for imports. + * + * @var array + */ + private static $globalImports = array( + 'ignoreannotation' => 'Doctrine\Common\Annotations\Annotation\IgnoreAnnotation', + ); + + /** + * A list with annotations that are not causing exceptions when not resolved to an annotation class. + * + * The names are case sensitive. + * + * @var array + */ + private static $globalIgnoredNames = array( + 'access'=> true, 'author'=> true, 'copyright'=> true, 'deprecated'=> true, + 'example'=> true, 'ignore'=> true, 'internal'=> true, 'link'=> true, 'see'=> true, + 'since'=> true, 'tutorial'=> true, 'version'=> true, 'package'=> true, + 'subpackage'=> true, 'name'=> true, 'global'=> true, 'param'=> true, + 'return'=> true, 'staticvar'=> true, 'category'=> true, 'staticVar'=> true, + 'static'=> true, 'var'=> true, 'throws'=> true, 'inheritdoc'=> true, + 'inheritDoc'=> true, 'license'=> true, 'todo'=> true, + 'deprec'=> true, 'property' => true, 'method' => true, + 'abstract'=> true, 'exception'=> true, 'magic' => true, 'api' => true, + 'final'=> true, 'filesource'=> true, 'throw' => true, 'uses' => true, + 'usedby'=> true, 'private' => true, 'Annotation' => true, 'override' => true, + 'codeCoverageIgnore' => true, 'codeCoverageIgnoreStart' => true, 'codeCoverageIgnoreEnd' => true, + 'Required' => true, 'Attribute' => true, 'Attributes' => true, + 'Target' => true, 'SuppressWarnings' => true, + 'ingroup' => true, 'code' => true, 'endcode' => true, + 'package_version' => true, + ); + + /** + * Add a new annotation to the globally ignored annotation names with regard to exception handling. + * + * @param string $name + */ + static public function addGlobalIgnoredName($name) + { + self::$globalIgnoredNames[$name] = true; + } + + /** + * Annotations Parser + * + * @var \Doctrine\Common\Annotations\DocParser + */ + private $parser; + + /** + * Annotations Parser used to collect parsing metadata + * + * @var \Doctrine\Common\Annotations\DocParser + */ + private $preParser; + + /** + * PHP Parser used to collect imports. + * + * @var \Doctrine\Common\Annotations\PhpParser + */ + private $phpParser; + + /** + * In-memory cache mechanism to store imported annotations per class. + * + * @var array + */ + private $imports = array(); + + /** + * In-memory cache mechanism to store ignored annotations per class. + * + * @var array + */ + private $ignoredAnnotationNames = array(); + + /** + * Constructor. + * + * Initializes a new AnnotationReader. + */ + public function __construct() + { + AnnotationRegistry::registerFile(__DIR__ . '/Annotation/IgnoreAnnotation.php'); + + $this->parser = new DocParser; + + $this->preParser = new DocParser; + $this->preParser->setImports(self::$globalImports); + $this->preParser->setIgnoreNotImportedAnnotations(true); + + $this->phpParser = new PhpParser; + } + + /** + * Gets the annotations applied to a class. + * + * @param ReflectionClass $class The ReflectionClass of the class from which + * the class annotations should be read. + * @return array An array of Annotations. + */ + public function getClassAnnotations(ReflectionClass $class) + { + $this->parser->setTarget(Target::TARGET_CLASS); + $this->parser->setImports($this->getImports($class)); + $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class)); + + return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName()); + } + + /** + * Gets a class annotation. + * + * @param ReflectionClass $class The ReflectionClass of the class from which + * the class annotations should be read. + * @param string $annotationName The name of the annotation. + * @return mixed The Annotation or NULL, if the requested annotation does not exist. + */ + public function getClassAnnotation(ReflectionClass $class, $annotationName) + { + $annotations = $this->getClassAnnotations($class); + + foreach ($annotations as $annotation) { + if ($annotation instanceof $annotationName) { + return $annotation; + } + } + + return null; + } + + /** + * Gets the annotations applied to a property. + * + * @param ReflectionProperty $property The ReflectionProperty of the property + * from which the annotations should be read. + * @return array An array of Annotations. + */ + public function getPropertyAnnotations(ReflectionProperty $property) + { + $class = $property->getDeclaringClass(); + $context = 'property ' . $class->getName() . "::\$" . $property->getName(); + $this->parser->setTarget(Target::TARGET_PROPERTY); + $this->parser->setImports($this->getImports($class)); + $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class)); + + return $this->parser->parse($property->getDocComment(), $context); + } + + /** + * Gets a property annotation. + * + * @param ReflectionProperty $property + * @param string $annotationName The name of the annotation. + * @return mixed The Annotation or NULL, if the requested annotation does not exist. + */ + public function getPropertyAnnotation(ReflectionProperty $property, $annotationName) + { + $annotations = $this->getPropertyAnnotations($property); + + foreach ($annotations as $annotation) { + if ($annotation instanceof $annotationName) { + return $annotation; + } + } + + return null; + } + + /** + * Gets the annotations applied to a method. + * + * @param \ReflectionMethod $method The ReflectionMethod of the method from which + * the annotations should be read. + * + * @return array An array of Annotations. + */ + public function getMethodAnnotations(ReflectionMethod $method) + { + $class = $method->getDeclaringClass(); + $context = 'method ' . $class->getName() . '::' . $method->getName() . '()'; + $this->parser->setTarget(Target::TARGET_METHOD); + $this->parser->setImports($this->getImports($class)); + $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class)); + + return $this->parser->parse($method->getDocComment(), $context); + } + + /** + * Gets a method annotation. + * + * @param ReflectionMethod $method + * @param string $annotationName The name of the annotation. + * @return mixed The Annotation or NULL, if the requested annotation does not exist. + */ + public function getMethodAnnotation(ReflectionMethod $method, $annotationName) + { + $annotations = $this->getMethodAnnotations($method); + + foreach ($annotations as $annotation) { + if ($annotation instanceof $annotationName) { + return $annotation; + } + } + + return null; + } + + /** + * Returns the ignored annotations for the given class. + * + * @param ReflectionClass $class + * @return array + */ + private function getIgnoredAnnotationNames(ReflectionClass $class) + { + if (isset($this->ignoredAnnotationNames[$name = $class->getName()])) { + return $this->ignoredAnnotationNames[$name]; + } + $this->collectParsingMetadata($class); + + return $this->ignoredAnnotationNames[$name]; + } + + /** + * Retrieve imports + * + * @param \ReflectionClass $class + * @return array + */ + private function getImports(ReflectionClass $class) + { + if (isset($this->imports[$name = $class->getName()])) { + return $this->imports[$name]; + } + $this->collectParsingMetadata($class); + + return $this->imports[$name]; + } + + /** + * Collects parsing metadata for a given class + * + * @param ReflectionClass $class + */ + private function collectParsingMetadata(ReflectionClass $class) + { + $ignoredAnnotationNames = self::$globalIgnoredNames; + + $annotations = $this->preParser->parse($class->getDocComment(), 'class '.$class->name); + foreach ($annotations as $annotation) { + if ($annotation instanceof IgnoreAnnotation) { + foreach ($annotation->names AS $annot) { + $ignoredAnnotationNames[$annot] = true; + } + } + } + + $name = $class->getName(); + $this->imports[$name] = array_merge( + self::$globalImports, + $this->phpParser->parseClass($class), + array('__NAMESPACE__' => $class->getNamespaceName()) + ); + $this->ignoredAnnotationNames[$name] = $ignoredAnnotationNames; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationRegistry.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationRegistry.php new file mode 100644 index 0000000..dfa846a --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/AnnotationRegistry.php @@ -0,0 +1,139 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +/** + * AnnotationRegistry + */ +final class AnnotationRegistry +{ + /** + * A map of namespaces to use for autoloading purposes based on a PSR-0 convention. + * + * Contains the namespace as key and an array of directories as value. If the value is NULL + * the include path is used for checking for the corresponding file. + * + * This autoloading mechanism does not utilize the PHP autoloading but implements autoloading on its own. + * + * @var array + */ + static private $autoloadNamespaces = array(); + + /** + * A map of autoloader callables. + * + * @var array + */ + static private $loaders = array(); + + static public function reset() + { + self::$autoloadNamespaces = array(); + self::$loaders = array(); + } + + /** + * Register file + * + * @param string $file + */ + static public function registerFile($file) + { + require_once $file; + } + + /** + * Add a namespace with one or many directories to look for files or null for the include path. + * + * Loading of this namespaces will be done with a PSR-0 namespace loading algorithm. + * + * @param string $namespace + * @param string|array|null $dirs + */ + static public function registerAutoloadNamespace($namespace, $dirs = null) + { + self::$autoloadNamespaces[$namespace] = $dirs; + } + + /** + * Register multiple namespaces + * + * Loading of this namespaces will be done with a PSR-0 namespace loading algorithm. + * + * @param array $namespaces + */ + static public function registerAutoloadNamespaces(array $namespaces) + { + self::$autoloadNamespaces = array_merge(self::$autoloadNamespaces, $namespaces); + } + + /** + * Register an autoloading callable for annotations, much like spl_autoload_register(). + * + * NOTE: These class loaders HAVE to be silent when a class was not found! + * IMPORTANT: Loaders have to return true if they loaded a class that could contain the searched annotation class. + * + * @param callable $callable + * + * @throws \InvalidArgumentException + */ + static public function registerLoader($callable) + { + if (!is_callable($callable)) { + throw new \InvalidArgumentException("A callable is expected in AnnotationRegistry::registerLoader()."); + } + self::$loaders[] = $callable; + } + + /** + * Autoload an annotation class silently. + * + * @param string $class + * @return boolean + */ + static public function loadAnnotationClass($class) + { + foreach (self::$autoloadNamespaces AS $namespace => $dirs) { + if (strpos($class, $namespace) === 0) { + $file = str_replace("\\", DIRECTORY_SEPARATOR, $class) . ".php"; + if ($dirs === null) { + if ($path = stream_resolve_include_path($file)) { + require $path; + return true; + } + } else { + foreach((array)$dirs AS $dir) { + if (file_exists($dir . DIRECTORY_SEPARATOR . $file)) { + require $dir . DIRECTORY_SEPARATOR . $file; + return true; + } + } + } + } + } + + foreach (self::$loaders AS $loader) { + if (call_user_func($loader, $class) === true) { + return true; + } + } + return false; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/CachedReader.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/CachedReader.php new file mode 100644 index 0000000..e377e3b --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/CachedReader.php @@ -0,0 +1,250 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +use Doctrine\Common\Cache\Cache; + +/** + * A cache aware annotation reader. + * + * @author Johannes M. Schmitt + * @author Benjamin Eberlei + */ +final class CachedReader implements Reader +{ + /** + * @var string + */ + private static $CACHE_SALT = '@[Annot]'; + + /** + * @var Reader + */ + private $delegate; + + /** + * @var Cache + */ + private $cache; + + /** + * @var boolean + */ + private $debug; + + /** + * @var array + */ + private $loadedAnnotations; + + /** + * Constructor + * + * @param Reader $reader + * @param Cache $cache + * @param bool $debug + */ + public function __construct(Reader $reader, Cache $cache, $debug = false) + { + $this->delegate = $reader; + $this->cache = $cache; + $this->debug = (Boolean) $debug; + } + + /** + * Get annotations for class + * + * @param \ReflectionClass $class + * @return array + */ + public function getClassAnnotations(\ReflectionClass $class) + { + $cacheKey = $class->getName(); + + if (isset($this->loadedAnnotations[$cacheKey])) { + return $this->loadedAnnotations[$cacheKey]; + } + + if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) { + $annots = $this->delegate->getClassAnnotations($class); + $this->saveToCache($cacheKey, $annots); + } + + return $this->loadedAnnotations[$cacheKey] = $annots; + } + + /** + * Get selected annotation for class + * + * @param \ReflectionClass $class + * @param string $annotationName + * @return null + */ + public function getClassAnnotation(\ReflectionClass $class, $annotationName) + { + foreach ($this->getClassAnnotations($class) as $annot) { + if ($annot instanceof $annotationName) { + return $annot; + } + } + + return null; + } + + /** + * Get annotations for property + * + * @param \ReflectionProperty $property + * @return array + */ + public function getPropertyAnnotations(\ReflectionProperty $property) + { + $class = $property->getDeclaringClass(); + $cacheKey = $class->getName().'$'.$property->getName(); + + if (isset($this->loadedAnnotations[$cacheKey])) { + return $this->loadedAnnotations[$cacheKey]; + } + + if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) { + $annots = $this->delegate->getPropertyAnnotations($property); + $this->saveToCache($cacheKey, $annots); + } + + return $this->loadedAnnotations[$cacheKey] = $annots; + } + + /** + * Get selected annotation for property + * + * @param \ReflectionProperty $property + * @param string $annotationName + * @return null + */ + public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) + { + foreach ($this->getPropertyAnnotations($property) as $annot) { + if ($annot instanceof $annotationName) { + return $annot; + } + } + + return null; + } + + /** + * Get method annotations + * + * @param \ReflectionMethod $method + * @return array + */ + public function getMethodAnnotations(\ReflectionMethod $method) + { + $class = $method->getDeclaringClass(); + $cacheKey = $class->getName().'#'.$method->getName(); + + if (isset($this->loadedAnnotations[$cacheKey])) { + return $this->loadedAnnotations[$cacheKey]; + } + + if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) { + $annots = $this->delegate->getMethodAnnotations($method); + $this->saveToCache($cacheKey, $annots); + } + + return $this->loadedAnnotations[$cacheKey] = $annots; + } + + /** + * Get selected method annotation + * + * @param \ReflectionMethod $method + * @param string $annotationName + * @return null + */ + public function getMethodAnnotation(\ReflectionMethod $method, $annotationName) + { + foreach ($this->getMethodAnnotations($method) as $annot) { + if ($annot instanceof $annotationName) { + return $annot; + } + } + + return null; + } + + /** + * Clear loaded annotations + */ + public function clearLoadedAnnotations() + { + $this->loadedAnnotations = array(); + } + + /** + * Fetches a value from the cache. + * + * @param string $rawCacheKey The cache key. + * @param \ReflectionClass $class The related class. + * @return mixed|boolean The cached value or false when the value is not in cache. + */ + private function fetchFromCache($rawCacheKey, \ReflectionClass $class) + { + $cacheKey = $rawCacheKey . self::$CACHE_SALT; + if (($data = $this->cache->fetch($cacheKey)) !== false) { + if (!$this->debug || $this->isCacheFresh($cacheKey, $class)) { + return $data; + } + } + + return false; + } + + /** + * Saves a value to the cache + * + * @param string $rawCacheKey The cache key. + * @param mixed $value The value. + */ + private function saveToCache($rawCacheKey, $value) + { + $cacheKey = $rawCacheKey . self::$CACHE_SALT; + $this->cache->save($cacheKey, $value); + if ($this->debug) { + $this->cache->save('[C]'.$cacheKey, time()); + } + } + + /** + * Check if cache is fresh + * + * @param string $cacheKey + * @param \ReflectionClass $class + * @return bool + */ + private function isCacheFresh($cacheKey, \ReflectionClass $class) + { + if (false === $filename = $class->getFilename()) { + return true; + } + + return $this->cache->fetch('[C]'.$cacheKey) >= filemtime($filename); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/DocLexer.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/DocLexer.php new file mode 100644 index 0000000..c9a6f7a --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/DocLexer.php @@ -0,0 +1,132 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +use Doctrine\Common\Lexer; + +/** + * Simple lexer for docblock annotations. + * + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Johannes M. Schmitt + */ +final class DocLexer extends Lexer +{ + const T_NONE = 1; + const T_INTEGER = 2; + const T_STRING = 3; + const T_FLOAT = 4; + + // All tokens that are also identifiers should be >= 100 + const T_IDENTIFIER = 100; + const T_AT = 101; + const T_CLOSE_CURLY_BRACES = 102; + const T_CLOSE_PARENTHESIS = 103; + const T_COMMA = 104; + const T_EQUALS = 105; + const T_FALSE = 106; + const T_NAMESPACE_SEPARATOR = 107; + const T_OPEN_CURLY_BRACES = 108; + const T_OPEN_PARENTHESIS = 109; + const T_TRUE = 110; + const T_NULL = 111; + const T_COLON = 112; + + protected $noCase = array( + '@' => self::T_AT, + ',' => self::T_COMMA, + '(' => self::T_OPEN_PARENTHESIS, + ')' => self::T_CLOSE_PARENTHESIS, + '{' => self::T_OPEN_CURLY_BRACES, + '}' => self::T_CLOSE_CURLY_BRACES, + '=' => self::T_EQUALS, + ':' => self::T_COLON, + '\\' => self::T_NAMESPACE_SEPARATOR + ); + + protected $withCase = array( + 'true' => self::T_TRUE, + 'false' => self::T_FALSE, + 'null' => self::T_NULL + ); + + /** + * {@inheritdoc} + */ + protected function getCatchablePatterns() + { + return array( + '[a-z_\\\][a-z0-9_\:\\\]*[a-z]{1}', + '(?:[+-]?[0-9]+(?:[\.][0-9]+)*)(?:[eE][+-]?[0-9]+)?', + '"(?:[^"]|"")*"', + ); + } + + /** + * {@inheritdoc} + */ + protected function getNonCatchablePatterns() + { + return array('\s+', '\*+', '(.)'); + } + + /** + * {@inheritdoc} + * + * @param string $value + * + * @return int + */ + protected function getType(&$value) + { + $type = self::T_NONE; + + if ($value[0] === '"') { + $value = str_replace('""', '"', substr($value, 1, strlen($value) - 2)); + + return self::T_STRING; + } + + if (isset($this->noCase[$value])) { + return $this->noCase[$value]; + } + + if ($value[0] === '_' || $value[0] === '\\' || ctype_alpha($value[0])) { + return self::T_IDENTIFIER; + } + + $lowerValue = strtolower($value); + + if (isset($this->withCase[$lowerValue])) { + return $this->withCase[$lowerValue]; + } + + // Checking numeric value + if (is_numeric($value)) { + return (strpos($value, '.') !== false || stripos($value, 'e') !== false) + ? self::T_FLOAT : self::T_INTEGER; + } + + return $type; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/DocParser.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/DocParser.php new file mode 100644 index 0000000..de31e0b --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/DocParser.php @@ -0,0 +1,988 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +use Closure; +use ReflectionClass; +use Doctrine\Common\Annotations\Annotation\Target; +use Doctrine\Common\Annotations\Annotation\Attribute; +use Doctrine\Common\Annotations\Annotation\Attributes; + +/** + * A parser for docblock annotations. + * + * It is strongly discouraged to change the default annotation parsing process. + * + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Johannes M. Schmitt + * @author Fabio B. Silva + */ +final class DocParser +{ + /** + * An array of all valid tokens for a class name. + * + * @var array + */ + private static $classIdentifiers = array(DocLexer::T_IDENTIFIER, DocLexer::T_TRUE, DocLexer::T_FALSE, DocLexer::T_NULL); + + /** + * The lexer. + * + * @var \Doctrine\Common\Annotations\DocLexer + */ + private $lexer; + + /** + * Current target context + * + * @var string + */ + private $target; + + /** + * Doc Parser used to collect annotation target + * + * @var \Doctrine\Common\Annotations\DocParser + */ + private static $metadataParser; + + /** + * Flag to control if the current annotation is nested or not. + * + * @var boolean + */ + private $isNestedAnnotation = false; + + /** + * Hashmap containing all use-statements that are to be used when parsing + * the given doc block. + * + * @var array + */ + private $imports = array(); + + /** + * This hashmap is used internally to cache results of class_exists() + * look-ups. + * + * @var array + */ + private $classExists = array(); + + /** + * Whether annotations that have not been imported should be ignored. + * + * @var boolean + */ + private $ignoreNotImportedAnnotations = false; + + /** + * An array of default namespaces if operating in simple mode. + * + * @var array + */ + private $namespaces = array(); + + /** + * A list with annotations that are not causing exceptions when not resolved to an annotation class. + * + * The names must be the raw names as used in the class, not the fully qualified + * class names. + * + * @var array + */ + private $ignoredAnnotationNames = array(); + + /** + * @var string + */ + private $context = ''; + + /** + * Hash-map for caching annotation metadata + * @var array + */ + private static $annotationMetadata = array( + 'Doctrine\Common\Annotations\Annotation\Target' => array( + 'is_annotation' => true, + 'has_constructor' => true, + 'properties' => array(), + 'targets_literal' => 'ANNOTATION_CLASS', + 'targets' => Target::TARGET_CLASS, + 'default_property' => 'value', + 'attribute_types' => array( + 'value' => array( + 'required' => false, + 'type' =>'array', + 'array_type'=>'string', + 'value' =>'array' + ) + ), + ), + 'Doctrine\Common\Annotations\Annotation\Attribute' => array( + 'is_annotation' => true, + 'has_constructor' => false, + 'targets_literal' => 'ANNOTATION_ANNOTATION', + 'targets' => Target::TARGET_ANNOTATION, + 'default_property' => 'name', + 'properties' => array( + 'name' => 'name', + 'type' => 'type', + 'required' => 'required' + ), + 'attribute_types' => array( + 'value' => array( + 'required' => true, + 'type' =>'string', + 'value' =>'string' + ), + 'type' => array( + 'required' =>true, + 'type' =>'string', + 'value' =>'string' + ), + 'required' => array( + 'required' =>false, + 'type' =>'boolean', + 'value' =>'boolean' + ) + ), + ), + 'Doctrine\Common\Annotations\Annotation\Attributes' => array( + 'is_annotation' => true, + 'has_constructor' => false, + 'targets_literal' => 'ANNOTATION_CLASS', + 'targets' => Target::TARGET_CLASS, + 'default_property' => 'value', + 'properties' => array( + 'value' => 'value' + ), + 'attribute_types' => array( + 'value' => array( + 'type' =>'array', + 'required' =>true, + 'array_type'=>'Doctrine\Common\Annotations\Annotation\Attribute', + 'value' =>'array' + ) + ), + ), + ); + + /** + * Hash-map for handle types declaration + * + * @var array + */ + private static $typeMap = array( + 'float' => 'double', + 'bool' => 'boolean', + // allow uppercase Boolean in honor of George Boole + 'Boolean' => 'boolean', + 'int' => 'integer', + ); + + /** + * Constructs a new DocParser. + */ + public function __construct() + { + $this->lexer = new DocLexer; + } + + /** + * Sets the annotation names that are ignored during the parsing process. + * + * The names are supposed to be the raw names as used in the class, not the + * fully qualified class names. + * + * @param array $names + */ + public function setIgnoredAnnotationNames(array $names) + { + $this->ignoredAnnotationNames = $names; + } + + /** + * Sets ignore on not-imported annotations + * + * @param $bool + */ + public function setIgnoreNotImportedAnnotations($bool) + { + $this->ignoreNotImportedAnnotations = (Boolean) $bool; + } + + /** + * Sets the default namespaces. + * + * @param array $namespace + * + * @throws \RuntimeException + */ + public function addNamespace($namespace) + { + if ($this->imports) { + throw new \RuntimeException('You must either use addNamespace(), or setImports(), but not both.'); + } + $this->namespaces[] = $namespace; + } + + /** + * Sets the imports + * + * @param array $imports + * @throws \RuntimeException + */ + public function setImports(array $imports) + { + if ($this->namespaces) { + throw new \RuntimeException('You must either use addNamespace(), or setImports(), but not both.'); + } + $this->imports = $imports; + } + + /** + * Sets current target context as bitmask. + * + * @param integer $target + */ + public function setTarget($target) + { + $this->target = $target; + } + + /** + * Parses the given docblock string for annotations. + * + * @param string $input The docblock string to parse. + * @param string $context The parsing context. + * @return array Array of annotations. If no annotations are found, an empty array is returned. + */ + public function parse($input, $context = '') + { + if (false === $pos = strpos($input, '@')) { + return array(); + } + + // also parse whatever character is before the @ + if ($pos > 0) { + $pos -= 1; + } + + $this->context = $context; + $this->lexer->setInput(trim(substr($input, $pos), '* /')); + $this->lexer->moveNext(); + + return $this->Annotations(); + } + + /** + * Attempts to match the given token with the current lookahead token. + * If they match, updates the lookahead token; otherwise raises a syntax error. + * + * @param int $token type of Token. + * @return bool True if tokens match; false otherwise. + */ + private function match($token) + { + if ( ! $this->lexer->isNextToken($token) ) { + $this->syntaxError($this->lexer->getLiteral($token)); + } + + return $this->lexer->moveNext(); + } + + /** + * Attempts to match the current lookahead token with any of the given tokens. + * + * If any of them matches, this method updates the lookahead token; otherwise + * a syntax error is raised. + * + * @param array $tokens + * @return bool + */ + private function matchAny(array $tokens) + { + if ( ! $this->lexer->isNextTokenAny($tokens)) { + $this->syntaxError(implode(' or ', array_map(array($this->lexer, 'getLiteral'), $tokens))); + } + + return $this->lexer->moveNext(); + } + + /** + * Generates a new syntax error. + * + * @param string $expected Expected string. + * @param array $token Optional token. + * + * @throws AnnotationException + */ + private function syntaxError($expected, $token = null) + { + if ($token === null) { + $token = $this->lexer->lookahead; + } + + $message = "Expected {$expected}, got "; + + if ($this->lexer->lookahead === null) { + $message .= 'end of string'; + } else { + $message .= "'{$token['value']}' at position {$token['position']}"; + } + + if (strlen($this->context)) { + $message .= ' in ' . $this->context; + } + + $message .= '.'; + + throw AnnotationException::syntaxError($message); + } + + /** + * Attempt to check if a class exists or not. This never goes through the PHP autoloading mechanism + * but uses the {@link AnnotationRegistry} to load classes. + * + * @param string $fqcn + * @return boolean + */ + private function classExists($fqcn) + { + if (isset($this->classExists[$fqcn])) { + return $this->classExists[$fqcn]; + } + + // first check if the class already exists, maybe loaded through another AnnotationReader + if (class_exists($fqcn, false)) { + return $this->classExists[$fqcn] = true; + } + + // final check, does this class exist? + return $this->classExists[$fqcn] = AnnotationRegistry::loadAnnotationClass($fqcn); + } + + /** + * Collects parsing metadata for a given annotation class + * + * @param string $name The annotation name + */ + private function collectAnnotationMetadata($name) + { + if (self::$metadataParser == null){ + self::$metadataParser = new self(); + self::$metadataParser->setTarget(Target::TARGET_CLASS); + self::$metadataParser->setIgnoreNotImportedAnnotations(true); + self::$metadataParser->setImports(array( + 'target' => 'Doctrine\Common\Annotations\Annotation\Target', + 'attribute' => 'Doctrine\Common\Annotations\Annotation\Attribute', + 'attributes' => 'Doctrine\Common\Annotations\Annotation\Attributes' + )); + AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Target.php'); + AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Attribute.php'); + AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Attributes.php'); + } + + $class = new \ReflectionClass($name); + $docComment = $class->getDocComment(); + + // Sets default values for annotation metadata + $metadata = array( + 'default_property' => null, + 'has_constructor' => (null !== $constructor = $class->getConstructor()) && $constructor->getNumberOfParameters() > 0, + 'properties' => array(), + 'property_types' => array(), + 'attribute_types' => array(), + 'targets_literal' => null, + 'targets' => Target::TARGET_ALL, + 'is_annotation' => false !== strpos($docComment, '@Annotation'), + ); + + // verify that the class is really meant to be an annotation + if ($metadata['is_annotation']) { + foreach (self::$metadataParser->parse($docComment, 'class @' . $name) as $annotation) { + if ($annotation instanceof Target) { + $metadata['targets'] = $annotation->targets; + $metadata['targets_literal'] = $annotation->literal; + + } elseif ($annotation instanceof Attributes) { + foreach ($annotation->value as $attrib) { + // handle internal type declaration + $type = isset(self::$typeMap[$attrib->type]) ? self::$typeMap[$attrib->type] : $attrib->type; + + // handle the case if the property type is mixed + if ('mixed' !== $type) { + // Checks if the property has array + if (false !== $pos = strpos($type, '<')) { + $arrayType = substr($type, $pos+1, -1); + $type = 'array'; + + if (isset(self::$typeMap[$arrayType])) { + $arrayType = self::$typeMap[$arrayType]; + } + + $metadata['attribute_types'][$attrib->name]['array_type'] = $arrayType; + } + + $metadata['attribute_types'][$attrib->name]['type'] = $type; + $metadata['attribute_types'][$attrib->name]['value'] = $attrib->type; + $metadata['attribute_types'][$attrib->name]['required'] = $attrib->required; + } + } + } + } + + // if not has a constructor will inject values into public properties + if (false === $metadata['has_constructor']) { + // collect all public properties + foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) { + $metadata['properties'][$property->name] = $property->name; + + // checks if the property has @var annotation + if ((false !== $propertyComment = $property->getDocComment()) + && false !== strpos($propertyComment, '@var') + && preg_match('/@var\s+([^\s]+)/',$propertyComment, $matches)) { + // literal type declaration + $value = $matches[1]; + + // handle internal type declaration + $type = isset(self::$typeMap[$value]) ? self::$typeMap[$value] : $value; + + // handle the case if the property type is mixed + if ('mixed' !== $type) { + // Checks if the property has @var array annotation + if (false !== $pos = strpos($type, '<')) { + $arrayType = substr($type, $pos+1, -1); + $type = 'array'; + + if (isset(self::$typeMap[$arrayType])) { + $arrayType = self::$typeMap[$arrayType]; + } + + $metadata['attribute_types'][$property->name]['array_type'] = $arrayType; + } + + $metadata['attribute_types'][$property->name]['type'] = $type; + $metadata['attribute_types'][$property->name]['value'] = $value; + $metadata['attribute_types'][$property->name]['required'] = false !== strpos($propertyComment, '@Required'); + } + } + } + + // choose the first property as default property + $metadata['default_property'] = reset($metadata['properties']); + } + } + + self::$annotationMetadata[$name] = $metadata; + } + + /** + * Annotations ::= Annotation {[ "*" ]* [Annotation]}* + * + * @return array + */ + private function Annotations() + { + $annotations = array(); + + while (null !== $this->lexer->lookahead) { + if (DocLexer::T_AT !== $this->lexer->lookahead['type']) { + $this->lexer->moveNext(); + continue; + } + + // make sure the @ is preceded by non-catchable pattern + if (null !== $this->lexer->token && $this->lexer->lookahead['position'] === $this->lexer->token['position'] + strlen($this->lexer->token['value'])) { + $this->lexer->moveNext(); + continue; + } + + // make sure the @ is followed by either a namespace separator, or + // an identifier token + if ((null === $peek = $this->lexer->glimpse()) + || (DocLexer::T_NAMESPACE_SEPARATOR !== $peek['type'] && !in_array($peek['type'], self::$classIdentifiers, true)) + || $peek['position'] !== $this->lexer->lookahead['position'] + 1) { + $this->lexer->moveNext(); + continue; + } + + $this->isNestedAnnotation = false; + if (false !== $annot = $this->Annotation()) { + $annotations[] = $annot; + } + } + + return $annotations; + } + + /** + * Annotation ::= "@" AnnotationName ["(" [Values] ")"] + * AnnotationName ::= QualifiedName | SimpleName + * QualifiedName ::= NameSpacePart "\" {NameSpacePart "\"}* SimpleName + * NameSpacePart ::= identifier | null | false | true + * SimpleName ::= identifier | null | false | true + * + * @throws AnnotationException + * @return mixed False if it is not a valid annotation. + */ + private function Annotation() + { + $this->match(DocLexer::T_AT); + + // check if we have an annotation + $name = $this->Identifier(); + + // only process names which are not fully qualified, yet + // fully qualified names must start with a \ + $originalName = $name; + if ('\\' !== $name[0]) { + $alias = (false === $pos = strpos($name, '\\'))? $name : substr($name, 0, $pos); + + $found = false; + if ($this->namespaces) { + foreach ($this->namespaces as $namespace) { + if ($this->classExists($namespace.'\\'.$name)) { + $name = $namespace.'\\'.$name; + $found = true; + break; + } + } + } elseif (isset($this->imports[$loweredAlias = strtolower($alias)])) { + if (false !== $pos) { + $name = $this->imports[$loweredAlias].substr($name, $pos); + } else { + $name = $this->imports[$loweredAlias]; + } + $found = true; + } elseif (isset($this->imports['__NAMESPACE__']) && $this->classExists($this->imports['__NAMESPACE__'].'\\'.$name)) { + $name = $this->imports['__NAMESPACE__'].'\\'.$name; + $found = true; + } elseif ($this->classExists($name)) { + $found = true; + } + + if (!$found) { + if ($this->ignoreNotImportedAnnotations || isset($this->ignoredAnnotationNames[$name])) { + return false; + } + + throw AnnotationException::semanticalError(sprintf('The annotation "@%s" in %s was never imported. Did you maybe forget to add a "use" statement for this annotation?', $name, $this->context)); + } + } + + if (!$this->classExists($name)) { + throw AnnotationException::semanticalError(sprintf('The annotation "@%s" in %s does not exist, or could not be auto-loaded.', $name, $this->context)); + } + + // at this point, $name contains the fully qualified class name of the + // annotation, and it is also guaranteed that this class exists, and + // that it is loaded + + + // collects the metadata annotation only if there is not yet + if (!isset(self::$annotationMetadata[$name])) { + $this->collectAnnotationMetadata($name); + } + + // verify that the class is really meant to be an annotation and not just any ordinary class + if (self::$annotationMetadata[$name]['is_annotation'] === false) { + if (isset($this->ignoredAnnotationNames[$originalName])) { + return false; + } + + throw AnnotationException::semanticalError(sprintf('The class "%s" is not annotated with @Annotation. Are you sure this class can be used as annotation? If so, then you need to add @Annotation to the _class_ doc comment of "%s". If it is indeed no annotation, then you need to add @IgnoreAnnotation("%s") to the _class_ doc comment of %s.', $name, $name, $originalName, $this->context)); + } + + //if target is nested annotation + $target = $this->isNestedAnnotation ? Target::TARGET_ANNOTATION : $this->target; + + // Next will be nested + $this->isNestedAnnotation = true; + + //if annotation does not support current target + if (0 === (self::$annotationMetadata[$name]['targets'] & $target) && $target) { + throw AnnotationException::semanticalError( + sprintf('Annotation @%s is not allowed to be declared on %s. You may only use this annotation on these code elements: %s.', + $originalName, $this->context, self::$annotationMetadata[$name]['targets_literal']) + ); + } + + $values = array(); + if ($this->lexer->isNextToken(DocLexer::T_OPEN_PARENTHESIS)) { + $this->match(DocLexer::T_OPEN_PARENTHESIS); + + if ( ! $this->lexer->isNextToken(DocLexer::T_CLOSE_PARENTHESIS)) { + $values = $this->Values(); + } + + $this->match(DocLexer::T_CLOSE_PARENTHESIS); + } + + // checks all declared attributes + foreach (self::$annotationMetadata[$name]['attribute_types'] as $property => $type) { + if ($property === self::$annotationMetadata[$name]['default_property'] + && !isset($values[$property]) && isset($values['value'])) { + $property = 'value'; + } + + // handle a not given attribute or null value + if (!isset($values[$property])) { + if ($type['required']) { + throw AnnotationException::requiredError($property, $originalName, $this->context, 'a(n) '.$type['value']); + } + + continue; + } + + if ($type['type'] === 'array') { + // handle the case of a single value + if (!is_array($values[$property])) { + $values[$property] = array($values[$property]); + } + + // checks if the attribute has array type declaration, such as "array" + if (isset($type['array_type'])) { + foreach ($values[$property] as $item) { + if (gettype($item) !== $type['array_type'] && !$item instanceof $type['array_type']) { + throw AnnotationException::typeError($property, $originalName, $this->context, 'either a(n) '.$type['array_type'].', or an array of '.$type['array_type'].'s', $item); + } + } + } + } elseif (gettype($values[$property]) !== $type['type'] && !$values[$property] instanceof $type['type']) { + throw AnnotationException::typeError($property, $originalName, $this->context, 'a(n) '.$type['value'], $values[$property]); + } + } + + // check if the annotation expects values via the constructor, + // or directly injected into public properties + if (self::$annotationMetadata[$name]['has_constructor'] === true) { + return new $name($values); + } + + $instance = new $name(); + foreach ($values as $property => $value) { + if (!isset(self::$annotationMetadata[$name]['properties'][$property])) { + if ('value' !== $property) { + throw AnnotationException::creationError(sprintf('The annotation @%s declared on %s does not have a property named "%s". Available properties: %s', $originalName, $this->context, $property, implode(', ', self::$annotationMetadata[$name]['properties']))); + } + + // handle the case if the property has no annotations + if (!$property = self::$annotationMetadata[$name]['default_property']) { + throw AnnotationException::creationError(sprintf('The annotation @%s declared on %s does not accept any values, but got %s.', $originalName, $this->context, json_encode($values))); + } + } + + $instance->{$property} = $value; + } + + return $instance; + } + + /** + * Values ::= Array | Value {"," Value}* + * + * @return array + */ + private function Values() + { + $values = array(); + + // Handle the case of a single array as value, i.e. @Foo({....}) + if ($this->lexer->isNextToken(DocLexer::T_OPEN_CURLY_BRACES)) { + $values['value'] = $this->Value(); + return $values; + } + + $values[] = $this->Value(); + + while ($this->lexer->isNextToken(DocLexer::T_COMMA)) { + $this->match(DocLexer::T_COMMA); + $token = $this->lexer->lookahead; + $value = $this->Value(); + + if ( ! is_object($value) && ! is_array($value)) { + $this->syntaxError('Value', $token); + } + + $values[] = $value; + } + + foreach ($values as $k => $value) { + if (is_object($value) && $value instanceof \stdClass) { + $values[$value->name] = $value->value; + } else if ( ! isset($values['value'])){ + $values['value'] = $value; + } else { + if ( ! is_array($values['value'])) { + $values['value'] = array($values['value']); + } + + $values['value'][] = $value; + } + + unset($values[$k]); + } + + return $values; + } + + /** + * Constant ::= integer | string | float | boolean + * + * @throws AnnotationException + * @return mixed + */ + private function Constant() + { + $identifier = $this->Identifier(); + + if (!defined($identifier) && false !== strpos($identifier, '::') && '\\' !== $identifier[0]) { + + list($className, $const) = explode('::', $identifier); + $alias = (false === $pos = strpos($className, '\\'))? $className : substr($className, 0, $pos); + + $found = false; + switch (true) { + case !empty ($this->namespaces): + foreach ($this->namespaces as $ns) { + if (class_exists($ns.'\\'.$className) || interface_exists($ns.'\\'.$className)) { + $className = $ns.'\\'.$className; + $found = true; + break; + } + } + break; + + case isset($this->imports[$loweredAlias = strtolower($alias)]): + $found = true; + if (false !== $pos) { + $className = $this->imports[$loweredAlias].substr($className, $pos); + } else { + $className = $this->imports[$loweredAlias]; + } + break; + + default: + if(isset($this->imports['__NAMESPACE__'])) { + $ns = $this->imports['__NAMESPACE__']; + if (class_exists($ns.'\\'.$className) || interface_exists($ns.'\\'.$className)) { + $className = $ns.'\\'.$className; + $found = true; + } + } + break; + } + + if ($found) { + $identifier = $className . '::' . $const; + } + } + + if (!defined($identifier)) { + throw AnnotationException::semanticalErrorConstants($identifier, $this->context); + } + + return constant($identifier); + } + + /** + * Identifier ::= string + * + * @return string + */ + private function Identifier() + { + // check if we have an annotation + if ($this->lexer->isNextTokenAny(self::$classIdentifiers)) { + $this->lexer->moveNext(); + $className = $this->lexer->token['value']; + } else { + $this->syntaxError('namespace separator or identifier'); + } + + while ($this->lexer->lookahead['position'] === ($this->lexer->token['position'] + strlen($this->lexer->token['value'])) + && $this->lexer->isNextToken(DocLexer::T_NAMESPACE_SEPARATOR)) { + + $this->match(DocLexer::T_NAMESPACE_SEPARATOR); + $this->matchAny(self::$classIdentifiers); + $className .= '\\' . $this->lexer->token['value']; + } + + return $className; + } + + /** + * Value ::= PlainValue | FieldAssignment + * + * @return mixed + */ + private function Value() + { + $peek = $this->lexer->glimpse(); + + if (DocLexer::T_EQUALS === $peek['type']) { + return $this->FieldAssignment(); + } + + return $this->PlainValue(); + } + + /** + * PlainValue ::= integer | string | float | boolean | Array | Annotation + * + * @return mixed + */ + private function PlainValue() + { + if ($this->lexer->isNextToken(DocLexer::T_OPEN_CURLY_BRACES)) { + return $this->Arrayx(); + } + + if ($this->lexer->isNextToken(DocLexer::T_AT)) { + return $this->Annotation(); + } + + if ($this->lexer->isNextToken(DocLexer::T_IDENTIFIER)) { + return $this->Constant(); + } + + switch ($this->lexer->lookahead['type']) { + case DocLexer::T_STRING: + $this->match(DocLexer::T_STRING); + return $this->lexer->token['value']; + + case DocLexer::T_INTEGER: + $this->match(DocLexer::T_INTEGER); + return (int)$this->lexer->token['value']; + + case DocLexer::T_FLOAT: + $this->match(DocLexer::T_FLOAT); + return (float)$this->lexer->token['value']; + + case DocLexer::T_TRUE: + $this->match(DocLexer::T_TRUE); + return true; + + case DocLexer::T_FALSE: + $this->match(DocLexer::T_FALSE); + return false; + + case DocLexer::T_NULL: + $this->match(DocLexer::T_NULL); + return null; + + default: + $this->syntaxError('PlainValue'); + } + } + + /** + * FieldAssignment ::= FieldName "=" PlainValue + * FieldName ::= identifier + * + * @return array + */ + private function FieldAssignment() + { + $this->match(DocLexer::T_IDENTIFIER); + $fieldName = $this->lexer->token['value']; + + $this->match(DocLexer::T_EQUALS); + + $item = new \stdClass(); + $item->name = $fieldName; + $item->value = $this->PlainValue(); + + return $item; + } + + /** + * Array ::= "{" ArrayEntry {"," ArrayEntry}* [","] "}" + * + * @return array + */ + private function Arrayx() + { + $array = $values = array(); + + $this->match(DocLexer::T_OPEN_CURLY_BRACES); + $values[] = $this->ArrayEntry(); + + while ($this->lexer->isNextToken(DocLexer::T_COMMA)) { + $this->match(DocLexer::T_COMMA); + + // optional trailing comma + if ($this->lexer->isNextToken(DocLexer::T_CLOSE_CURLY_BRACES)) { + break; + } + + $values[] = $this->ArrayEntry(); + } + + $this->match(DocLexer::T_CLOSE_CURLY_BRACES); + + foreach ($values as $value) { + list ($key, $val) = $value; + + if ($key !== null) { + $array[$key] = $val; + } else { + $array[] = $val; + } + } + + return $array; + } + + /** + * ArrayEntry ::= Value | KeyValuePair + * KeyValuePair ::= Key ("=" | ":") PlainValue | Constant + * Key ::= string | integer | Constant + * + * @return array + */ + private function ArrayEntry() + { + $peek = $this->lexer->glimpse(); + + if (DocLexer::T_EQUALS === $peek['type'] + || DocLexer::T_COLON === $peek['type']) { + + if ($this->lexer->isNextToken(DocLexer::T_IDENTIFIER)) { + $key = $this->Constant(); + } else { + $this->matchAny(array(DocLexer::T_INTEGER, DocLexer::T_STRING)); + $key = $this->lexer->token['value']; + } + + $this->matchAny(array(DocLexer::T_EQUALS, DocLexer::T_COLON)); + + return array($key, $this->PlainValue()); + } + + return array(null, $this->Value()); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/FileCacheReader.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/FileCacheReader.php new file mode 100644 index 0000000..3934861 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/FileCacheReader.php @@ -0,0 +1,258 @@ +. + */ + +namespace Doctrine\Common\Annotations; + + +/** + * File cache reader for annotations. + * + * @author Johannes M. Schmitt + * @author Benjamin Eberlei + */ +class FileCacheReader implements Reader +{ + /** + * @var Reader + */ + private $reader; + + /** + * @var string + */ + private $dir; + + /** + * @var bool + */ + private $debug; + + /** + * @var array + */ + private $loadedAnnotations = array(); + + /** + * Constructor + * + * @param Reader $reader + * @param string $cacheDir + * @param bool $debug + * + * @throws \InvalidArgumentException + */ + public function __construct(Reader $reader, $cacheDir, $debug = false) + { + $this->reader = $reader; + if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true)) { + throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $cacheDir)); + } + if (!is_writable($cacheDir)) { + throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable. Both, the webserver and the console user need access. You can manage access rights for multiple users with "chmod +a". If your system does not support this, check out the acl package.', $cacheDir)); + } + + $this->dir = rtrim($cacheDir, '\\/'); + $this->debug = $debug; + } + + /** + * Retrieve annotations for class + * + * @param \ReflectionClass $class + * @return array + */ + public function getClassAnnotations(\ReflectionClass $class) + { + $key = $class->getName(); + + if (isset($this->loadedAnnotations[$key])) { + return $this->loadedAnnotations[$key]; + } + + $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; + if (!file_exists($path)) { + $annot = $this->reader->getClassAnnotations($class); + $this->saveCacheFile($path, $annot); + return $this->loadedAnnotations[$key] = $annot; + } + + if ($this->debug + && (false !== $filename = $class->getFilename()) + && filemtime($path) < filemtime($filename)) { + @unlink($path); + + $annot = $this->reader->getClassAnnotations($class); + $this->saveCacheFile($path, $annot); + return $this->loadedAnnotations[$key] = $annot; + } + + return $this->loadedAnnotations[$key] = include $path; + } + + /** + * Get annotations for property + * + * @param \ReflectionProperty $property + * @return array + */ + public function getPropertyAnnotations(\ReflectionProperty $property) + { + $class = $property->getDeclaringClass(); + $key = $class->getName().'$'.$property->getName(); + + if (isset($this->loadedAnnotations[$key])) { + return $this->loadedAnnotations[$key]; + } + + $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; + if (!file_exists($path)) { + $annot = $this->reader->getPropertyAnnotations($property); + $this->saveCacheFile($path, $annot); + return $this->loadedAnnotations[$key] = $annot; + } + + if ($this->debug + && (false !== $filename = $class->getFilename()) + && filemtime($path) < filemtime($filename)) { + unlink($path); + + $annot = $this->reader->getPropertyAnnotations($property); + $this->saveCacheFile($path, $annot); + return $this->loadedAnnotations[$key] = $annot; + } + + return $this->loadedAnnotations[$key] = include $path; + } + + /** + * Retrieve annotations for method + * + * @param \ReflectionMethod $method + * @return array + */ + public function getMethodAnnotations(\ReflectionMethod $method) + { + $class = $method->getDeclaringClass(); + $key = $class->getName().'#'.$method->getName(); + + if (isset($this->loadedAnnotations[$key])) { + return $this->loadedAnnotations[$key]; + } + + $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; + if (!file_exists($path)) { + $annot = $this->reader->getMethodAnnotations($method); + $this->saveCacheFile($path, $annot); + return $this->loadedAnnotations[$key] = $annot; + } + + if ($this->debug + && (false !== $filename = $class->getFilename()) + && filemtime($path) < filemtime($filename)) { + unlink($path); + + $annot = $this->reader->getMethodAnnotations($method); + $this->saveCacheFile($path, $annot); + return $this->loadedAnnotations[$key] = $annot; + } + + return $this->loadedAnnotations[$key] = include $path; + } + + /** + * Save cache file + * + * @param string $path + * @param mixed $data + */ + private function saveCacheFile($path, $data) + { + file_put_contents($path, 'getClassAnnotations($class); + + foreach ($annotations as $annotation) { + if ($annotation instanceof $annotationName) { + return $annotation; + } + } + + return null; + } + + /** + * Gets a method annotation. + * + * @param \ReflectionMethod $method + * @param string $annotationName The name of the annotation. + * @return mixed The Annotation or NULL, if the requested annotation does not exist. + */ + public function getMethodAnnotation(\ReflectionMethod $method, $annotationName) + { + $annotations = $this->getMethodAnnotations($method); + + foreach ($annotations as $annotation) { + if ($annotation instanceof $annotationName) { + return $annotation; + } + } + + return null; + } + + /** + * Gets a property annotation. + * + * @param \ReflectionProperty $property + * @param string $annotationName The name of the annotation. + * @return mixed The Annotation or NULL, if the requested annotation does not exist. + */ + public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) + { + $annotations = $this->getPropertyAnnotations($property); + + foreach ($annotations as $annotation) { + if ($annotation instanceof $annotationName) { + return $annotation; + } + } + + return null; + } + + /** + * Clear stores annotations + */ + public function clearLoadedAnnotations() + { + $this->loadedAnnotations = array(); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/IndexedReader.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/IndexedReader.php new file mode 100644 index 0000000..2dfdd4d --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/IndexedReader.php @@ -0,0 +1,141 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +use Doctrine\Common\Annotations\Reader; + +/** + * Allows the reader to be used in-place of Doctrine's reader. + * + * @author Johannes M. Schmitt + */ +class IndexedReader implements Reader +{ + /** + * @var Reader + */ + private $delegate; + + /** + * Constructor + * + * @param Reader $reader + */ + public function __construct(Reader $reader) + { + $this->delegate = $reader; + } + + /** + * Get Annotations for class + * + * @param \ReflectionClass $class + * @return array + */ + public function getClassAnnotations(\ReflectionClass $class) + { + $annotations = array(); + foreach ($this->delegate->getClassAnnotations($class) as $annot) { + $annotations[get_class($annot)] = $annot; + } + + return $annotations; + } + + /** + * Get selected annotation for class + * + * @param \ReflectionClass $class + * @param string $annotation + * @return mixed + */ + public function getClassAnnotation(\ReflectionClass $class, $annotation) + { + return $this->delegate->getClassAnnotation($class, $annotation); + } + + /** + * Get Annotations for method + * + * @param \ReflectionMethod $method + * @return array + */ + public function getMethodAnnotations(\ReflectionMethod $method) + { + $annotations = array(); + foreach ($this->delegate->getMethodAnnotations($method) as $annot) { + $annotations[get_class($annot)] = $annot; + } + + return $annotations; + } + + /** + * Get selected annotation for method + * + * @param \ReflectionMethod $method + * @param string $annotation + * @return mixed + */ + public function getMethodAnnotation(\ReflectionMethod $method, $annotation) + { + return $this->delegate->getMethodAnnotation($method, $annotation); + } + + /** + * Get annotations for property + * + * @param \ReflectionProperty $property + * @return array + */ + public function getPropertyAnnotations(\ReflectionProperty $property) + { + $annotations = array(); + foreach ($this->delegate->getPropertyAnnotations($property) as $annot) { + $annotations[get_class($annot)] = $annot; + } + + return $annotations; + } + + /** + * Get selected annotation for property + * + * @param \ReflectionProperty $property + * @param string $annotation + * @return mixed + */ + public function getPropertyAnnotation(\ReflectionProperty $property, $annotation) + { + return $this->delegate->getPropertyAnnotation($property, $annotation); + } + + /** + * Proxy all methods to the delegate. + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + return call_user_func_array(array($this->delegate, $method), $args); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/PhpParser.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/PhpParser.php new file mode 100644 index 0000000..c09dd51 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/PhpParser.php @@ -0,0 +1,80 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +use SplFileObject; + +/** + * Parses a file for namespaces/use/class declarations. + * + * @author Fabien Potencier + * @author Christian Kaps + */ +final class PhpParser +{ + /** + * Parses a class. + * + * @param \ReflectionClass $class A ReflectionClass object. + * @return array A list with use statements in the form (Alias => FQN). + */ + public function parseClass(\ReflectionClass $class) + { + if (method_exists($class, 'getUseStatements')) { + return $class->getUseStatements(); + } + + if (false === $filename = $class->getFilename()) { + return array(); + } + + $content = $this->getFileContent($filename, $class->getStartLine()); + $namespace = str_replace('\\', '\\\\', $class->getNamespaceName()); + $content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content); + $tokenizer = new TokenParser('parseUseStatements($class->getNamespaceName()); + + return $statements; + } + + /** + * Get the content of the file right up to the given line number. + * + * @param string $filename The name of the file to load. + * @param int $lineNumber The number of lines to read from file. + * @return string The content of the file. + */ + private function getFileContent($filename, $lineNumber) + { + $content = ''; + $lineCnt = 0; + $file = new SplFileObject($filename); + while (!$file->eof()) { + if ($lineCnt++ == $lineNumber) { + break; + } + + $content .= $file->fgets(); + } + + return $content; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Reader.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Reader.php new file mode 100644 index 0000000..6a01cb4 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/Reader.php @@ -0,0 +1,67 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +/** + * Interface for annotation readers. + * + * @author Johannes M. Schmitt + */ +interface Reader +{ + /** + * @param \ReflectionClass $class + * @return mixed + */ + function getClassAnnotations(\ReflectionClass $class); + + /** + * @param \ReflectionClass $class + * @param string $annotationName + * @return mixed + */ + function getClassAnnotation(\ReflectionClass $class, $annotationName); + + /** + * @param \ReflectionMethod $method + * @return mixed + */ + function getMethodAnnotations(\ReflectionMethod $method); + + /** + * @param \ReflectionMethod $method + * @param string $annotationName + * @return mixed + */ + function getMethodAnnotation(\ReflectionMethod $method, $annotationName); + + /** + * @param \ReflectionProperty $property + * @return mixed + */ + function getPropertyAnnotations(\ReflectionProperty $property); + + /** + * @param \ReflectionProperty $property + * @param string $annotationName + * @return mixed + */ + function getPropertyAnnotation(\ReflectionProperty $property, $annotationName); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php new file mode 100644 index 0000000..4210d90 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php @@ -0,0 +1,157 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +use Doctrine\Common\Annotations\Annotation\Target; + +/** + * Simple Annotation Reader. + * + * This annotation reader is intended to be used in projects where you have + * full-control over all annotations that are available. + * + * @since 2.2 + * @author Johannes M. Schmitt + * @author Fabio B. Silva + */ +class SimpleAnnotationReader implements Reader +{ + /** + * @var DocParser + */ + private $parser; + + /** + * Constructor. + * + * Initializes a new SimpleAnnotationReader. + */ + public function __construct() + { + $this->parser = new DocParser(); + $this->parser->setIgnoreNotImportedAnnotations(true); + } + + /** + * Adds a namespace in which we will look for annotations. + * + * @param string $namespace + */ + public function addNamespace($namespace) + { + $this->parser->addNamespace($namespace); + } + + /** + * Gets the annotations applied to a class. + * + * @param \ReflectionClass $class The ReflectionClass of the class from which + * the class annotations should be read. + * + * @return array An array of Annotations. + */ + public function getClassAnnotations(\ReflectionClass $class) + { + return $this->parser->parse($class->getDocComment(), 'class '.$class->getName()); + } + + /** + * Gets the annotations applied to a method. + * + * @param \ReflectionMethod $method The ReflectionMethod of the method from which + * the annotations should be read. + * + * @return array An array of Annotations. + */ + public function getMethodAnnotations(\ReflectionMethod $method) + { + return $this->parser->parse($method->getDocComment(), 'method '.$method->getDeclaringClass()->name.'::'.$method->getName().'()'); + } + + /** + * Gets the annotations applied to a property. + * + * @param \ReflectionProperty $property The ReflectionProperty of the property + * from which the annotations should be read. + * + * @return array An array of Annotations. + */ + public function getPropertyAnnotations(\ReflectionProperty $property) + { + return $this->parser->parse($property->getDocComment(), 'property '.$property->getDeclaringClass()->name.'::$'.$property->getName()); + } + + /** + * Gets a class annotation. + * + * @param \ReflectionClass $class The ReflectionClass of the class from which + * the class annotations should be read. + * @param string $annotationName The name of the annotation. + * + * @return mixed The Annotation or NULL, if the requested annotation does not exist. + */ + public function getClassAnnotation(\ReflectionClass $class, $annotationName) + { + foreach ($this->getClassAnnotations($class) as $annot) { + if ($annot instanceof $annotationName) { + return $annot; + } + } + + return null; + } + + /** + * Gets a method annotation. + * + * @param \ReflectionMethod $method + * @param string $annotationName The name of the annotation. + * + * @return mixed The Annotation or NULL, if the requested annotation does not exist. + */ + public function getMethodAnnotation(\ReflectionMethod $method, $annotationName) + { + foreach ($this->getMethodAnnotations($method) as $annot) { + if ($annot instanceof $annotationName) { + return $annot; + } + } + + return null; + } + + /** + * Gets a property annotation. + * + * @param \ReflectionProperty $property + * @param string $annotationName The name of the annotation. + * @return mixed The Annotation or NULL, if the requested annotation does not exist. + */ + public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) + { + foreach ($this->getPropertyAnnotations($property) as $annot) { + if ($annot instanceof $annotationName) { + return $annot; + } + } + + return null; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Annotations/TokenParser.php b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/TokenParser.php new file mode 100644 index 0000000..a1ef115 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Annotations/TokenParser.php @@ -0,0 +1,175 @@ +. + */ + +namespace Doctrine\Common\Annotations; + +/** + * Parses a file for namespaces/use/class declarations. + * + * @author Fabien Potencier + * @author Christian Kaps + */ +class TokenParser +{ + /** + * The token list. + * + * @var array + */ + private $tokens; + + /** + * The number of tokens. + * + * @var int + */ + private $numTokens = 0; + + /** + * The current array pointer. + * + * @var int + */ + private $pointer = 0; + + public function __construct($contents) + { + $this->tokens = token_get_all($contents); + $this->numTokens = count($this->tokens); + $this->pointer = 0; + } + + /** + * Gets the next non whitespace and non comment token. + * + * @param $docCommentIsComment + * If TRUE then a doc comment is considered a comment and skipped. + * If FALSE then only whitespace and normal comments are skipped. + * + * @return array The token if exists, null otherwise. + */ + public function next($docCommentIsComment = TRUE) + { + for ($i = $this->pointer; $i < $this->numTokens; $i++) { + $this->pointer++; + if ($this->tokens[$i][0] === T_WHITESPACE || + $this->tokens[$i][0] === T_COMMENT || + ($docCommentIsComment && $this->tokens[$i][0] === T_DOC_COMMENT)) { + + continue; + } + + return $this->tokens[$i]; + } + + return null; + } + + /** + * Parse a single use statement. + * + * @return array A list with all found class names for a use statement. + */ + public function parseUseStatement() + { + $class = ''; + $alias = ''; + $statements = array(); + $explicitAlias = false; + while (($token = $this->next())) { + $isNameToken = $token[0] === T_STRING || $token[0] === T_NS_SEPARATOR; + if (!$explicitAlias && $isNameToken) { + $class .= $token[1]; + $alias = $token[1]; + } else if ($explicitAlias && $isNameToken) { + $alias .= $token[1]; + } else if ($token[0] === T_AS) { + $explicitAlias = true; + $alias = ''; + } else if ($token === ',') { + $statements[strtolower($alias)] = $class; + $class = ''; + $alias = ''; + $explicitAlias = false; + } else if ($token === ';') { + $statements[strtolower($alias)] = $class; + break; + } else { + break; + } + } + + return $statements; + } + + /** + * Get all use statements. + * + * @param string $namespaceName The namespace name of the reflected class. + * @return array A list with all found use statements. + */ + public function parseUseStatements($namespaceName) + { + $statements = array(); + while (($token = $this->next())) { + if ($token[0] === T_USE) { + $statements = array_merge($statements, $this->parseUseStatement()); + continue; + } + if ($token[0] !== T_NAMESPACE || $this->parseNamespace() != $namespaceName) { + continue; + } + + // Get fresh array for new namespace. This is to prevent the parser to collect the use statements + // for a previous namespace with the same name. This is the case if a namespace is defined twice + // or if a namespace with the same name is commented out. + $statements = array(); + } + + return $statements; + } + + /** + * Get the namespace. + * + * @return string The found namespace. + */ + public function parseNamespace() + { + $name = ''; + while (($token = $this->next()) && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR)) { + $name .= $token[1]; + } + + return $name; + } + + /** + * Get the class name. + * + * @return string The foundclass name. + */ + public function parseClass() + { + // Namespaces and class names are tokenized the same: T_STRINGs + // separated by T_NS_SEPARATOR so we can use one function to provide + // both. + return $this->parseNamespace(); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/ApcCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/ApcCache.php new file mode 100644 index 0000000..2d0cd23 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/ApcCache.php @@ -0,0 +1,93 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * APC cache provider. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class ApcCache extends CacheProvider +{ + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return apc_fetch($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return apc_exists($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + return (bool) apc_store($id, $data, (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return apc_delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return apc_clear_cache() && apc_clear_cache('user'); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $info = apc_cache_info(); + $sma = apc_sma_info(); + + return array( + Cache::STATS_HITS => $info['num_hits'], + Cache::STATS_MISSES => $info['num_misses'], + Cache::STATS_UPTIME => $info['start_time'], + Cache::STATS_MEMORY_USAGE => $info['mem_size'], + Cache::STATS_MEMORY_AVAILIABLE => $sma['avail_mem'], + ); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/ArrayCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/ArrayCache.php new file mode 100644 index 0000000..a7a70aa --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/ArrayCache.php @@ -0,0 +1,96 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Array cache driver. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class ArrayCache extends CacheProvider +{ + /** + * @var array $data + */ + private $data = array(); + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return (isset($this->data[$id])) ? $this->data[$id] : false; + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return isset($this->data[$id]); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + $this->data[$id] = $data; + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + unset($this->data[$id]); + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + $this->data = array(); + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + return null; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/Cache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/Cache.php new file mode 100644 index 0000000..5493562 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/Cache.php @@ -0,0 +1,102 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Interface for cache drivers. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Fabio B. Silva + */ +interface Cache +{ + const STATS_HITS = 'hits'; + const STATS_MISSES = 'misses'; + const STATS_UPTIME = 'uptime'; + const STATS_MEMORY_USAGE = 'memory_usage'; + const STATS_MEMORY_AVAILIABLE = 'memory_available'; + + /** + * Fetches an entry from the cache. + * + * @param string $id cache id The id of the cache entry to fetch. + * @return mixed The cached data or FALSE, if no cache entry exists for the given id. + */ + function fetch($id); + + /** + * Test if an entry exists in the cache. + * + * @param string $id cache id The cache id of the entry to check for. + * @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise. + */ + function contains($id); + + /** + * Puts data into the cache. + * + * @param string $id The cache id. + * @param mixed $data The cache entry/data. + * @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this cache entry (0 => infinite lifeTime). + * @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise. + */ + function save($id, $data, $lifeTime = 0); + + /** + * Deletes a cache entry. + * + * @param string $id cache id + * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise. + */ + function delete($id); + + /** + * Retrieves cached information from data store + * + * The server's statistics array has the following values: + * + * - hits + * Number of keys that have been requested and found present. + * + * - misses + * Number of items that have been requested and not found. + * + * - uptime + * Time that the server is running. + * + * - memory_usage + * Memory used by this server to store items. + * + * - memory_available + * Memory allowed to use for storage. + * + * @since 2.2 + * @var array Associative array with server's statistics if available, NULL otherwise. + */ + function getStats(); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/CacheProvider.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/CacheProvider.php new file mode 100644 index 0000000..4221a62 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/CacheProvider.php @@ -0,0 +1,231 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Base class for cache provider implementations. + * + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Fabio B. Silva + */ +abstract class CacheProvider implements Cache +{ + const DOCTRINE_NAMESPACE_CACHEKEY = 'DoctrineNamespaceCacheKey[%s]'; + + /** + * @var string The namespace to prefix all cache ids with + */ + private $namespace = ''; + + /** + * @var string The namespace version + */ + private $namespaceVersion; + + /** + * Set the namespace to prefix all cache ids with. + * + * @param string $namespace + * @return void + */ + public function setNamespace($namespace) + { + $this->namespace = (string) $namespace; + } + + /** + * Retrieve the namespace that prefixes all cache ids. + * + * @return string + */ + public function getNamespace() + { + return $this->namespace; + } + + /** + * {@inheritdoc} + */ + public function fetch($id) + { + return $this->doFetch($this->getNamespacedId($id)); + } + + /** + * {@inheritdoc} + */ + public function contains($id) + { + return $this->doContains($this->getNamespacedId($id)); + } + + /** + * {@inheritdoc} + */ + public function save($id, $data, $lifeTime = 0) + { + return $this->doSave($this->getNamespacedId($id), $data, $lifeTime); + } + + /** + * {@inheritdoc} + */ + public function delete($id) + { + return $this->doDelete($this->getNamespacedId($id)); + } + + /** + * {@inheritdoc} + */ + public function getStats() + { + return $this->doGetStats(); + } + + /** + * Deletes all cache entries. + * + * @return boolean TRUE if the cache entries were successfully flushed, FALSE otherwise. + */ + public function flushAll() + { + return $this->doFlush(); + } + + /** + * Delete all cache entries. + * + * @return boolean TRUE if the cache entries were successfully deleted, FALSE otherwise. + */ + public function deleteAll() + { + $namespaceCacheKey = $this->getNamespaceCacheKey(); + $namespaceVersion = $this->getNamespaceVersion() + 1; + + $this->namespaceVersion = $namespaceVersion; + + return $this->doSave($namespaceCacheKey, $namespaceVersion); + } + + /** + * Prefix the passed id with the configured namespace value + * + * @param string $id The id to namespace + * @return string $id The namespaced id + */ + private function getNamespacedId($id) + { + $namespaceVersion = $this->getNamespaceVersion(); + + return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion); + } + + /** + * Namespace cache key + * + * @return string $namespaceCacheKey + */ + private function getNamespaceCacheKey() + { + return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace); + } + + /** + * Namespace version + * + * @return string $namespaceVersion + */ + private function getNamespaceVersion() + { + if (null !== $this->namespaceVersion) { + return $this->namespaceVersion; + } + + $namespaceCacheKey = $this->getNamespaceCacheKey(); + $namespaceVersion = $this->doFetch($namespaceCacheKey); + + if (false === $namespaceVersion) { + $namespaceVersion = 1; + + $this->doSave($namespaceCacheKey, $namespaceVersion); + } + + $this->namespaceVersion = $namespaceVersion; + + return $this->namespaceVersion; + } + + /** + * Fetches an entry from the cache. + * + * @param string $id cache id The id of the cache entry to fetch. + * @return string The cached data or FALSE, if no cache entry exists for the given id. + */ + abstract protected function doFetch($id); + + /** + * Test if an entry exists in the cache. + * + * @param string $id cache id The cache id of the entry to check for. + * @return boolean TRUE if a cache entry exists for the given cache id, FALSE otherwise. + */ + abstract protected function doContains($id); + + /** + * Puts data into the cache. + * + * @param string $id The cache id. + * @param string $data The cache entry/data. + * @param bool|int $lifeTime The lifetime. If != false, sets a specific lifetime for this + * cache entry (null => infinite lifeTime). + * + * @return boolean TRUE if the entry was successfully stored in the cache, FALSE otherwise. + */ + abstract protected function doSave($id, $data, $lifeTime = false); + + /** + * Deletes a cache entry. + * + * @param string $id cache id + * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise. + */ + abstract protected function doDelete($id); + + /** + * Deletes all cache entries. + * + * @return boolean TRUE if the cache entry was successfully deleted, FALSE otherwise. + */ + abstract protected function doFlush(); + + /** + * Retrieves cached information from data store + * + * @since 2.2 + * @return array An associative array with server's statistics if available, NULL otherwise. + */ + abstract protected function doGetStats(); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/FileCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/FileCache.php new file mode 100644 index 0000000..da650b4 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/FileCache.php @@ -0,0 +1,132 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Base file cache driver. + * + * @since 2.3 + * @author Fabio B. Silva + */ +abstract class FileCache extends CacheProvider +{ + /** + * @var string Cache directory. + */ + protected $directory; + + /** + * @var string Cache file extension. + */ + protected $extension; + + /** + * Constructor + * + * @param string $directory Cache directory. + * @param string $directory Cache file extension. + * + * @throws \InvalidArgumentException + */ + public function __construct($directory, $extension = null) + { + if ( ! is_dir($directory) && ! @mkdir($directory, 0777, true)) { + throw new \InvalidArgumentException(sprintf( + 'The directory "%s" does not exist and could not be created.', + $directory + )); + } + + if ( ! is_writable($directory)) { + throw new \InvalidArgumentException(sprintf( + 'The directory "%s" is not writable.', + $directory + )); + } + + $this->directory = realpath($directory); + $this->extension = $extension ?: $this->extension; + } + + /** + * Gets the cache directory. + * + * @return string + */ + public function getDirectory() + { + return $this->directory; + } + + /** + * Gets the cache file extension. + * + * @return string + */ + public function getExtension() + { + return $this->extension; + } + + /** + * @return string + */ + protected function getFilename($id) + { + $path = implode(str_split(md5($id), 12), DIRECTORY_SEPARATOR); + $path = $this->directory . DIRECTORY_SEPARATOR . $path; + + return $path . DIRECTORY_SEPARATOR . $id . $this->extension; + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return @unlink($this->getFilename($id)); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + $pattern = '/^.+\\' . $this->extension . '$/i'; + $iterator = new \RecursiveDirectoryIterator($this->directory); + $iterator = new \RecursiveIteratorIterator($iterator); + $iterator = new \RegexIterator($iterator, $pattern); + + foreach ($iterator as $name => $file) { + @unlink($name); + } + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + return null; + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/FilesystemCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/FilesystemCache.php new file mode 100644 index 0000000..a27a717 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/FilesystemCache.php @@ -0,0 +1,114 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Filesystem cache driver. + * + * @since 2.3 + * @author Fabio B. Silva + */ +class FilesystemCache extends FileCache +{ + const EXTENSION = '.doctrinecache.data'; + + /** + * {@inheritdoc} + */ + protected $extension = self::EXTENSION; + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + $data = ''; + $lifetime = -1; + $filename = $this->getFilename($id); + + if ( ! file_exists($filename)) { + return false; + } + + $resource = fopen($filename, "r"); + + if (false !== ($line = fgets($resource))) { + $lifetime = (integer) $line; + } + + if ($lifetime !== 0 && $lifetime < time()) { + fclose($resource); + + return false; + } + + while (false !== ($line = fgets($resource))) { + $data .= $line; + } + + fclose($resource); + + return unserialize($data); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + $lifetime = -1; + $filename = $this->getFilename($id); + + if ( ! file_exists($filename)) { + return false; + } + + $resource = fopen($filename, "r"); + + if (false !== ($line = fgets($resource))) { + $lifetime = (integer) $line; + } + + fclose($resource); + + return $lifetime === 0 || $lifetime > time(); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 0) { + $lifeTime = time() + $lifeTime; + } + + $data = serialize($data); + $filename = $this->getFilename($id); + $filepath = pathinfo($filename, PATHINFO_DIRNAME); + + if ( ! is_dir($filepath)) { + mkdir($filepath, 0777, true); + } + + return file_put_contents($filename, $lifeTime . PHP_EOL . $data); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/MemcacheCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/MemcacheCache.php new file mode 100644 index 0000000..5687b96 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/MemcacheCache.php @@ -0,0 +1,121 @@ +. + */ + +namespace Doctrine\Common\Cache; + +use \Memcache; + +/** + * Memcache cache provider. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class MemcacheCache extends CacheProvider +{ + /** + * @var Memcache + */ + private $memcache; + + /** + * Sets the memcache instance to use. + * + * @param Memcache $memcache + */ + public function setMemcache(Memcache $memcache) + { + $this->memcache = $memcache; + } + + /** + * Gets the memcache instance used by the cache. + * + * @return Memcache + */ + public function getMemcache() + { + return $this->memcache; + } + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return $this->memcache->get($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return (bool) $this->memcache->get($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 30 * 24 * 3600) { + $lifeTime = time() + $lifeTime; + } + return $this->memcache->set($id, $data, 0, (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return $this->memcache->delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return $this->memcache->flush(); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $stats = $this->memcache->getStats(); + return array( + Cache::STATS_HITS => $stats['get_hits'], + Cache::STATS_MISSES => $stats['get_misses'], + Cache::STATS_UPTIME => $stats['uptime'], + Cache::STATS_MEMORY_USAGE => $stats['bytes'], + Cache::STATS_MEMORY_AVAILIABLE => $stats['limit_maxbytes'], + ); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/MemcachedCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/MemcachedCache.php new file mode 100644 index 0000000..75f1345 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/MemcachedCache.php @@ -0,0 +1,124 @@ +. + */ + +namespace Doctrine\Common\Cache; + +use \Memcached; + +/** + * Memcached cache provider. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class MemcachedCache extends CacheProvider +{ + /** + * @var Memcached + */ + private $memcached; + + /** + * Sets the memcache instance to use. + * + * @param Memcached $memcached + */ + public function setMemcached(Memcached $memcached) + { + $this->memcached = $memcached; + } + + /** + * Gets the memcached instance used by the cache. + * + * @return Memcached + */ + public function getMemcached() + { + return $this->memcached; + } + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return $this->memcached->get($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return (false !== $this->memcached->get($id)); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 30 * 24 * 3600) { + $lifeTime = time() + $lifeTime; + } + return $this->memcached->set($id, $data, (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return $this->memcached->delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return $this->memcached->flush(); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $stats = $this->memcached->getStats(); + $servers = $this->memcached->getServerList(); + $key = $servers[0]['host'] . ':' . $servers[0]['port']; + $stats = $stats[$key]; + return array( + Cache::STATS_HITS => $stats['get_hits'], + Cache::STATS_MISSES => $stats['get_misses'], + Cache::STATS_UPTIME => $stats['uptime'], + Cache::STATS_MEMORY_USAGE => $stats['bytes'], + Cache::STATS_MEMORY_AVAILIABLE => $stats['limit_maxbytes'], + ); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/PhpFileCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/PhpFileCache.php new file mode 100644 index 0000000..0971cd9 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/PhpFileCache.php @@ -0,0 +1,108 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Php file cache driver. + * + * @since 2.3 + * @author Fabio B. Silva + */ +class PhpFileCache extends FileCache +{ + const EXTENSION = '.doctrinecache.php'; + + /** + * {@inheritdoc} + */ + protected $extension = self::EXTENSION; + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + $filename = $this->getFilename($id); + + if ( ! file_exists($filename)) { + return false; + } + + $value = include $filename; + + if ($value['lifetime'] !== 0 && $value['lifetime'] < time()) { + return false; + } + + return $value['data']; + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + $filename = $this->getFilename($id); + + if ( ! file_exists($filename)) { + return false; + } + + $value = include $filename; + + return $value['lifetime'] === 0 || $value['lifetime'] > time(); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + if ($lifeTime > 0) { + $lifeTime = time() + $lifeTime; + } + + if (is_object($data) && ! method_exists($data, '__set_state')) { + throw new \InvalidArgumentException( + "Invalid argument given, PhpFileCache only allows objects that implement __set_state() " . + "and fully support var_export(). You can use the FilesystemCache to save arbitrary object " . + "graphs using serialize()/deserialize()." + ); + } + + $filename = $this->getFilename($id); + $filepath = pathinfo($filename, PATHINFO_DIRNAME); + + if ( ! is_dir($filepath)) { + mkdir($filepath, 0777, true); + } + + $value = array( + 'lifetime' => $lifeTime, + 'data' => $data + ); + + $value = var_export($value, true); + $code = sprintf('. + */ + +namespace Doctrine\Common\Cache; + +use Redis; + +/** + * Redis cache provider. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.2 + * @author Osman Ungur + */ +class RedisCache extends CacheProvider +{ + /** + * @var Redis + */ + private $redis; + + /** + * Sets the redis instance to use. + * + * @param Redis $redis + */ + public function setRedis(Redis $redis) + { + $redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_IGBINARY); + $this->redis = $redis; + } + + /** + * Gets the redis instance used by the cache. + * + * @return Redis + */ + public function getRedis() + { + return $this->redis; + } + + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return $this->redis->get($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return $this->redis->exists($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + $result = $this->redis->set($id, $data); + if ($lifeTime > 0) { + $this->redis->expire($id, $lifeTime); + } + return $result; + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return $this->redis->delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return $this->redis->flushDB(); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $info = $this->redis->info(); + return array( + Cache::STATS_HITS => false, + Cache::STATS_MISSES => false, + Cache::STATS_UPTIME => $info['uptime_in_seconds'], + Cache::STATS_MEMORY_USAGE => $info['used_memory'], + Cache::STATS_MEMORY_AVAILIABLE => false + ); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/WinCacheCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/WinCacheCache.php new file mode 100644 index 0000000..777d0fd --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/WinCacheCache.php @@ -0,0 +1,93 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * WinCache cache provider. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class WinCacheCache extends CacheProvider +{ + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return wincache_ucache_get($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return wincache_ucache_exists($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + return (bool) wincache_ucache_set($id, $data, (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return wincache_ucache_delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + return wincache_ucache_clear(); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $info = wincache_ucache_info(); + $meminfo = wincache_ucache_meminfo(); + + return array( + Cache::STATS_HITS => $info['total_hit_count'], + Cache::STATS_MISSES => $info['total_miss_count'], + Cache::STATS_UPTIME => $info['total_cache_uptime'], + Cache::STATS_MEMORY_USAGE => $meminfo['memory_total'], + Cache::STATS_MEMORY_AVAILIABLE => $meminfo['memory_free'], + ); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/XcacheCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/XcacheCache.php new file mode 100644 index 0000000..8733e26 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/XcacheCache.php @@ -0,0 +1,110 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Xcache cache driver. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author David Abdemoulaie + */ +class XcacheCache extends CacheProvider +{ + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return $this->doContains($id) ? unserialize(xcache_get($id)) : false; + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return xcache_isset($id); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + return xcache_set($id, serialize($data), (int) $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return xcache_unset($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + $this->checkAuthorization(); + + xcache_clear_cache(XC_TYPE_VAR, 0); + + return true; + } + + /** + * Checks that xcache.admin.enable_auth is Off + * + * @throws \BadMethodCallException When xcache.admin.enable_auth is On + * @return void + */ + protected function checkAuthorization() + { + if (ini_get('xcache.admin.enable_auth')) { + throw new \BadMethodCallException('To use all features of \Doctrine\Common\Cache\XcacheCache, you must set "xcache.admin.enable_auth" to "Off" in your php.ini.'); + } + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + $this->checkAuthorization(); + + $info = xcache_info(XC_TYPE_VAR, 0); + return array( + Cache::STATS_HITS => $info['hits'], + Cache::STATS_MISSES => $info['misses'], + Cache::STATS_UPTIME => null, + Cache::STATS_MEMORY_USAGE => $info['size'], + Cache::STATS_MEMORY_AVAILIABLE => $info['avail'], + ); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Cache/ZendDataCache.php b/vendor/doctrine/common/lib/Doctrine/Common/Cache/ZendDataCache.php new file mode 100644 index 0000000..fc90bc6 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Cache/ZendDataCache.php @@ -0,0 +1,84 @@ +. + */ + +namespace Doctrine\Common\Cache; + +/** + * Zend Data Cache cache driver. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Ralph Schindler + * @author Guilherme Blanco + */ +class ZendDataCache extends CacheProvider +{ + /** + * {@inheritdoc} + */ + protected function doFetch($id) + { + return zend_shm_cache_fetch($id); + } + + /** + * {@inheritdoc} + */ + protected function doContains($id) + { + return (false !== zend_shm_cache_fetch($id)); + } + + /** + * {@inheritdoc} + */ + protected function doSave($id, $data, $lifeTime = 0) + { + return zend_shm_cache_store($id, $data, $lifeTime); + } + + /** + * {@inheritdoc} + */ + protected function doDelete($id) + { + return zend_shm_cache_delete($id); + } + + /** + * {@inheritdoc} + */ + protected function doFlush() + { + $namespace = $this->getNamespace(); + if (empty($namespace)) { + return zend_shm_cache_clear(); + } + return zend_shm_cache_clear($namespace); + } + + /** + * {@inheritdoc} + */ + protected function doGetStats() + { + return null; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php b/vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php new file mode 100644 index 0000000..45024e1 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php @@ -0,0 +1,263 @@ +. + */ + +namespace Doctrine\Common; + +/** + * A ClassLoader is an autoloader for class files that can be + * installed on the SPL autoload stack. It is a class loader that either loads only classes + * of a specific namespace or all namespaces and it is suitable for working together + * with other autoloaders in the SPL autoload stack. + * + * If no include path is configured through the constructor or {@link setIncludePath}, a ClassLoader + * relies on the PHP include_path. + * + * @author Roman Borschel + * @since 2.0 + */ +class ClassLoader +{ + /** + * @var string PHP file extension + */ + protected $fileExtension = '.php'; + + /** + * @var string Current namespace + */ + protected $namespace; + + /** + * @var string Current include path + */ + protected $includePath; + + /** + * @var string PHP namespace separator + */ + protected $namespaceSeparator = '\\'; + + /** + * Creates a new ClassLoader that loads classes of the + * specified namespace from the specified include path. + * + * If no include path is given, the ClassLoader relies on the PHP include_path. + * If neither a namespace nor an include path is given, the ClassLoader will + * be responsible for loading all classes, thereby relying on the PHP include_path. + * + * @param string $ns The namespace of the classes to load. + * @param string $includePath The base include path to use. + */ + public function __construct($ns = null, $includePath = null) + { + $this->namespace = $ns; + $this->includePath = $includePath; + } + + /** + * Sets the namespace separator used by classes in the namespace of this ClassLoader. + * + * @param string $sep The separator to use. + */ + public function setNamespaceSeparator($sep) + { + $this->namespaceSeparator = $sep; + } + + /** + * Gets the namespace separator used by classes in the namespace of this ClassLoader. + * + * @return string + */ + public function getNamespaceSeparator() + { + return $this->namespaceSeparator; + } + + /** + * Sets the base include path for all class files in the namespace of this ClassLoader. + * + * @param string $includePath + */ + public function setIncludePath($includePath) + { + $this->includePath = $includePath; + } + + /** + * Gets the base include path for all class files in the namespace of this ClassLoader. + * + * @return string + */ + public function getIncludePath() + { + return $this->includePath; + } + + /** + * Sets the file extension of class files in the namespace of this ClassLoader. + * + * @param string $fileExtension + */ + public function setFileExtension($fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * Gets the file extension of class files in the namespace of this ClassLoader. + * + * @return string + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Registers this ClassLoader on the SPL autoload stack. + */ + public function register() + { + spl_autoload_register(array($this, 'loadClass')); + } + + /** + * Removes this ClassLoader from the SPL autoload stack. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $className The name of the class to load. + + * @return boolean TRUE if the class has been successfully loaded, FALSE otherwise. + */ + public function loadClass($className) + { + if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) { + return false; + } + + require ($this->includePath !== null ? $this->includePath . DIRECTORY_SEPARATOR : '') + . str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) + . $this->fileExtension; + + return true; + } + + /** + * Asks this ClassLoader whether it can potentially load the class (file) with + * the given name. + * + * @param string $className The fully-qualified name of the class. + * @return boolean TRUE if this ClassLoader can load the class, FALSE otherwise. + */ + public function canLoadClass($className) + { + if ($this->namespace !== null && strpos($className, $this->namespace.$this->namespaceSeparator) !== 0) { + return false; + } + + $file = str_replace($this->namespaceSeparator, DIRECTORY_SEPARATOR, $className) . $this->fileExtension; + + if ($this->includePath !== null) { + return file_exists($this->includePath . DIRECTORY_SEPARATOR . $file); + } + + return (false !== stream_resolve_include_path($file)); + } + + /** + * Checks whether a class with a given name exists. A class "exists" if it is either + * already defined in the current request or if there is an autoloader on the SPL + * autoload stack that is a) responsible for the class in question and b) is able to + * load a class file in which the class definition resides. + * + * If the class is not already defined, each autoloader in the SPL autoload stack + * is asked whether it is able to tell if the class exists. If the autoloader is + * a ClassLoader, {@link canLoadClass} is used, otherwise the autoload + * function of the autoloader is invoked and expected to return a value that + * evaluates to TRUE if the class (file) exists. As soon as one autoloader reports + * that the class exists, TRUE is returned. + * + * Note that, depending on what kinds of autoloaders are installed on the SPL + * autoload stack, the class (file) might already be loaded as a result of checking + * for its existence. This is not the case with a ClassLoader, who separates + * these responsibilities. + * + * @param string $className The fully-qualified name of the class. + * @return boolean TRUE if the class exists as per the definition given above, FALSE otherwise. + */ + public static function classExists($className) + { + if (class_exists($className, false) || interface_exists($className, false)) { + return true; + } + + foreach (spl_autoload_functions() as $loader) { + if (is_array($loader)) { // array(???, ???) + if (is_object($loader[0])) { + if ($loader[0] instanceof ClassLoader) { // array($obj, 'methodName') + if ($loader[0]->canLoadClass($className)) { + return true; + } + } else if ($loader[0]->{$loader[1]}($className)) { + return true; + } + } else if ($loader[0]::$loader[1]($className)) { // array('ClassName', 'methodName') + return true; + } + } else if ($loader instanceof \Closure) { // function($className) {..} + if ($loader($className)) { + return true; + } + } else if (is_string($loader) && $loader($className)) { // "MyClass::loadClass" + return true; + } + } + + return class_exists($className, false) || interface_exists($className, false); + } + + /** + * Gets the ClassLoader from the SPL autoload stack that is responsible + * for (and is able to load) the class with the given name. + * + * @param string $className The name of the class. + * @return ClassLoader The ClassLoader for the class or NULL if no such ClassLoader exists. + */ + public static function getClassLoader($className) + { + foreach (spl_autoload_functions() as $loader) { + if (is_array($loader) + && $loader[0] instanceof ClassLoader + && $loader[0]->canLoadClass($className) + ) { + return $loader[0]; + } + } + + return null; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/ArrayCollection.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/ArrayCollection.php new file mode 100644 index 0000000..7c2b13e --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/ArrayCollection.php @@ -0,0 +1,500 @@ +. + */ + +namespace Doctrine\Common\Collections; + +use Closure, ArrayIterator; +use Doctrine\Common\Collections\Expr\Expression; +use Doctrine\Common\Collections\Expr\ClosureExpressionVisitor; + +/** + * An ArrayCollection is a Collection implementation that wraps a regular PHP array. + * + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ArrayCollection implements Collection, Selectable +{ + /** + * An array containing the entries of this collection. + * + * @var array + */ + private $_elements; + + /** + * Initializes a new ArrayCollection. + * + * @param array $elements + */ + public function __construct(array $elements = array()) + { + $this->_elements = $elements; + } + + /** + * Gets the PHP array representation of this collection. + * + * @return array The PHP array representation of this collection. + */ + public function toArray() + { + return $this->_elements; + } + + /** + * Sets the internal iterator to the first element in the collection and + * returns this element. + * + * @return mixed + */ + public function first() + { + return reset($this->_elements); + } + + /** + * Sets the internal iterator to the last element in the collection and + * returns this element. + * + * @return mixed + */ + public function last() + { + return end($this->_elements); + } + + /** + * Gets the current key/index at the current internal iterator position. + * + * @return mixed + */ + public function key() + { + return key($this->_elements); + } + + /** + * Moves the internal iterator position to the next element. + * + * @return mixed + */ + public function next() + { + return next($this->_elements); + } + + /** + * Gets the element of the collection at the current internal iterator position. + * + * @return mixed + */ + public function current() + { + return current($this->_elements); + } + + /** + * Removes an element with a specific key/index from the collection. + * + * @param mixed $key + * @return mixed The removed element or NULL, if no element exists for the given key. + */ + public function remove($key) + { + if (isset($this->_elements[$key])) { + $removed = $this->_elements[$key]; + unset($this->_elements[$key]); + + return $removed; + } + + return null; + } + + /** + * Removes the specified element from the collection, if it is found. + * + * @param mixed $element The element to remove. + * @return boolean TRUE if this collection contained the specified element, FALSE otherwise. + */ + public function removeElement($element) + { + $key = array_search($element, $this->_elements, true); + + if ($key !== false) { + unset($this->_elements[$key]); + + return true; + } + + return false; + } + + /** + * ArrayAccess implementation of offsetExists() + * + * @see containsKey() + * + * @param mixed $offset + * @return bool + */ + public function offsetExists($offset) + { + return $this->containsKey($offset); + } + + /** + * ArrayAccess implementation of offsetGet() + * + * @see get() + * + * @param mixed $offset + * @return mixed + */ + public function offsetGet($offset) + { + return $this->get($offset); + } + + /** + * ArrayAccess implementation of offsetSet() + * + * @see add() + * @see set() + * + * @param mixed $offset + * @param mixed $value + * @return bool + */ + public function offsetSet($offset, $value) + { + if ( ! isset($offset)) { + return $this->add($value); + } + return $this->set($offset, $value); + } + + /** + * ArrayAccess implementation of offsetUnset() + * + * @see remove() + * + * @param mixed $offset + * @return mixed + */ + public function offsetUnset($offset) + { + return $this->remove($offset); + } + + /** + * Checks whether the collection contains a specific key/index. + * + * @param mixed $key The key to check for. + * @return boolean TRUE if the given key/index exists, FALSE otherwise. + */ + public function containsKey($key) + { + return isset($this->_elements[$key]); + } + + /** + * Checks whether the given element is contained in the collection. + * Only element values are compared, not keys. The comparison of two elements + * is strict, that means not only the value but also the type must match. + * For objects this means reference equality. + * + * @param mixed $element + * @return boolean TRUE if the given element is contained in the collection, + * FALSE otherwise. + */ + public function contains($element) + { + foreach ($this->_elements as $collectionElement) { + if ($element === $collectionElement) { + return true; + } + } + + return false; + } + + /** + * Tests for the existence of an element that satisfies the given predicate. + * + * @param Closure $p The predicate. + * @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise. + */ + public function exists(Closure $p) + { + foreach ($this->_elements as $key => $element) { + if ($p($key, $element)) { + return true; + } + } + return false; + } + + /** + * Searches for a given element and, if found, returns the corresponding key/index + * of that element. The comparison of two elements is strict, that means not + * only the value but also the type must match. + * For objects this means reference equality. + * + * @param mixed $element The element to search for. + * @return mixed The key/index of the element or FALSE if the element was not found. + */ + public function indexOf($element) + { + return array_search($element, $this->_elements, true); + } + + /** + * Gets the element with the given key/index. + * + * @param mixed $key The key. + * @return mixed The element or NULL, if no element exists for the given key. + */ + public function get($key) + { + if (isset($this->_elements[$key])) { + return $this->_elements[$key]; + } + return null; + } + + /** + * Gets all keys/indexes of the collection elements. + * + * @return array + */ + public function getKeys() + { + return array_keys($this->_elements); + } + + /** + * Gets all elements. + * + * @return array + */ + public function getValues() + { + return array_values($this->_elements); + } + + /** + * Returns the number of elements in the collection. + * + * Implementation of the Countable interface. + * + * @return integer The number of elements in the collection. + */ + public function count() + { + return count($this->_elements); + } + + /** + * Adds/sets an element in the collection at the index / with the specified key. + * + * When the collection is a Map this is like put(key,value)/add(key,value). + * When the collection is a List this is like add(position,value). + * + * @param mixed $key + * @param mixed $value + */ + public function set($key, $value) + { + $this->_elements[$key] = $value; + } + + /** + * Adds an element to the collection. + * + * @param mixed $value + * @return boolean Always TRUE. + */ + public function add($value) + { + $this->_elements[] = $value; + return true; + } + + /** + * Checks whether the collection is empty. + * + * Note: This is preferable over count() == 0. + * + * @return boolean TRUE if the collection is empty, FALSE otherwise. + */ + public function isEmpty() + { + return ! $this->_elements; + } + + /** + * Gets an iterator for iterating over the elements in the collection. + * + * @return ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->_elements); + } + + /** + * Applies the given function to each element in the collection and returns + * a new collection with the elements returned by the function. + * + * @param Closure $func + * @return Collection + */ + public function map(Closure $func) + { + return new static(array_map($func, $this->_elements)); + } + + /** + * Returns all the elements of this collection that satisfy the predicate p. + * The order of the elements is preserved. + * + * @param Closure $p The predicate used for filtering. + * @return Collection A collection with the results of the filter operation. + */ + public function filter(Closure $p) + { + return new static(array_filter($this->_elements, $p)); + } + + /** + * Applies the given predicate p to all elements of this collection, + * returning true, if the predicate yields true for all elements. + * + * @param Closure $p The predicate. + * @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise. + */ + public function forAll(Closure $p) + { + foreach ($this->_elements as $key => $element) { + if ( ! $p($key, $element)) { + return false; + } + } + + return true; + } + + /** + * Partitions this collection in two collections according to a predicate. + * Keys are preserved in the resulting collections. + * + * @param Closure $p The predicate on which to partition. + * @return array An array with two elements. The first element contains the collection + * of elements where the predicate returned TRUE, the second element + * contains the collection of elements where the predicate returned FALSE. + */ + public function partition(Closure $p) + { + $coll1 = $coll2 = array(); + foreach ($this->_elements as $key => $element) { + if ($p($key, $element)) { + $coll1[$key] = $element; + } else { + $coll2[$key] = $element; + } + } + return array(new static($coll1), new static($coll2)); + } + + /** + * Returns a string representation of this object. + * + * @return string + */ + public function __toString() + { + return __CLASS__ . '@' . spl_object_hash($this); + } + + /** + * Clears the collection. + */ + public function clear() + { + $this->_elements = array(); + } + + /** + * Extract a slice of $length elements starting at position $offset from the Collection. + * + * If $length is null it returns all elements from $offset to the end of the Collection. + * Keys have to be preserved by this method. Calling this method will only return the + * selected slice and NOT change the elements contained in the collection slice is called on. + * + * @param int $offset + * @param int $length + * @return array + */ + public function slice($offset, $length = null) + { + return array_slice($this->_elements, $offset, $length, true); + } + + /** + * Select all elements from a selectable that match the criteria and + * return a new collection containing these elements. + * + * @param Criteria $criteria + * @return Collection + */ + public function matching(Criteria $criteria) + { + $expr = $criteria->getWhereExpression(); + $filtered = $this->_elements; + + if ($expr) { + $visitor = new ClosureExpressionVisitor(); + $filter = $visitor->dispatch($expr); + $filtered = array_filter($filtered, $filter); + } + + if ($orderings = $criteria->getOrderings()) { + $next = null; + foreach (array_reverse($orderings) as $field => $ordering) { + $next = ClosureExpressionVisitor::sortByField($field, $ordering == 'DESC' ? -1 : 1, $next); + } + + usort($filtered, $next); + } + + $offset = $criteria->getFirstResult(); + $length = $criteria->getMaxResults(); + + if ($offset || $length) { + $filtered = array_slice($filtered, (int)$offset, $length); + } + + return new static($filtered); + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/Collection.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Collection.php new file mode 100644 index 0000000..51eb9e7 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Collection.php @@ -0,0 +1,243 @@ +. + */ + +namespace Doctrine\Common\Collections; + +use Closure, Countable, IteratorAggregate, ArrayAccess; + +/** + * The missing (SPL) Collection/Array/OrderedMap interface. + * + * A Collection resembles the nature of a regular PHP array. That is, + * it is essentially an ordered map that can also be used + * like a list. + * + * A Collection has an internal iterator just like a PHP array. In addition, + * a Collection can be iterated with external iterators, which is preferrable. + * To use an external iterator simply use the foreach language construct to + * iterate over the collection (which calls {@link getIterator()} internally) or + * explicitly retrieve an iterator though {@link getIterator()} which can then be + * used to iterate over the collection. + * You can not rely on the internal iterator of the collection being at a certain + * position unless you explicitly positioned it before. Prefer iteration with + * external iterators. + * + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +interface Collection extends Countable, IteratorAggregate, ArrayAccess +{ + /** + * Adds an element at the end of the collection. + * + * @param mixed $element The element to add. + * @return boolean Always TRUE. + */ + function add($element); + + /** + * Clears the collection, removing all elements. + */ + function clear(); + + /** + * Checks whether an element is contained in the collection. + * This is an O(n) operation, where n is the size of the collection. + * + * @param mixed $element The element to search for. + * @return boolean TRUE if the collection contains the element, FALSE otherwise. + */ + function contains($element); + + /** + * Checks whether the collection is empty (contains no elements). + * + * @return boolean TRUE if the collection is empty, FALSE otherwise. + */ + function isEmpty(); + + /** + * Removes the element at the specified index from the collection. + * + * @param string|integer $key The kex/index of the element to remove. + * @return mixed The removed element or NULL, if the collection did not contain the element. + */ + function remove($key); + + /** + * Removes the specified element from the collection, if it is found. + * + * @param mixed $element The element to remove. + * @return boolean TRUE if this collection contained the specified element, FALSE otherwise. + */ + function removeElement($element); + + /** + * Checks whether the collection contains an element with the specified key/index. + * + * @param string|integer $key The key/index to check for. + * @return boolean TRUE if the collection contains an element with the specified key/index, + * FALSE otherwise. + */ + function containsKey($key); + + /** + * Gets the element at the specified key/index. + * + * @param string|integer $key The key/index of the element to retrieve. + * @return mixed + */ + function get($key); + + /** + * Gets all keys/indices of the collection. + * + * @return array The keys/indices of the collection, in the order of the corresponding + * elements in the collection. + */ + function getKeys(); + + /** + * Gets all values of the collection. + * + * @return array The values of all elements in the collection, in the order they + * appear in the collection. + */ + function getValues(); + + /** + * Sets an element in the collection at the specified key/index. + * + * @param string|integer $key The key/index of the element to set. + * @param mixed $value The element to set. + */ + function set($key, $value); + + /** + * Gets a native PHP array representation of the collection. + * + * @return array + */ + function toArray(); + + /** + * Sets the internal iterator to the first element in the collection and + * returns this element. + * + * @return mixed + */ + function first(); + + /** + * Sets the internal iterator to the last element in the collection and + * returns this element. + * + * @return mixed + */ + function last(); + + /** + * Gets the key/index of the element at the current iterator position. + * + */ + function key(); + + /** + * Gets the element of the collection at the current iterator position. + * + */ + function current(); + + /** + * Moves the internal iterator position to the next element. + * + */ + function next(); + + /** + * Tests for the existence of an element that satisfies the given predicate. + * + * @param Closure $p The predicate. + * @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise. + */ + function exists(Closure $p); + + /** + * Returns all the elements of this collection that satisfy the predicate p. + * The order of the elements is preserved. + * + * @param Closure $p The predicate used for filtering. + * @return Collection A collection with the results of the filter operation. + */ + function filter(Closure $p); + + /** + * Applies the given predicate p to all elements of this collection, + * returning true, if the predicate yields true for all elements. + * + * @param Closure $p The predicate. + * @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise. + */ + function forAll(Closure $p); + + /** + * Applies the given function to each element in the collection and returns + * a new collection with the elements returned by the function. + * + * @param Closure $func + * @return Collection + */ + function map(Closure $func); + + /** + * Partitions this collection in two collections according to a predicate. + * Keys are preserved in the resulting collections. + * + * @param Closure $p The predicate on which to partition. + * @return array An array with two elements. The first element contains the collection + * of elements where the predicate returned TRUE, the second element + * contains the collection of elements where the predicate returned FALSE. + */ + function partition(Closure $p); + + /** + * Gets the index/key of a given element. The comparison of two elements is strict, + * that means not only the value but also the type must match. + * For objects this means reference equality. + * + * @param mixed $element The element to search for. + * @return mixed The key/index of the element or FALSE if the element was not found. + */ + function indexOf($element); + + /** + * Extract a slice of $length elements starting at position $offset from the Collection. + * + * If $length is null it returns all elements from $offset to the end of the Collection. + * Keys have to be preserved by this method. Calling this method will only return the + * selected slice and NOT change the elements contained in the collection slice is called on. + * + * @param int $offset + * @param int $length + * @return array + */ + function slice($offset, $length = null); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/Criteria.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Criteria.php new file mode 100644 index 0000000..3b05549 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Criteria.php @@ -0,0 +1,240 @@ +. + */ + +namespace Doctrine\Common\Collections; + +use Doctrine\Common\Collections\Expr\Expression; +use Doctrine\Common\Collections\Expr\CompositeExpression; + +/** + * Criteria for filtering Selectable collections. + * + * @author Benjamin Eberlei + * @since 2.3 + */ +class Criteria +{ + /** + * @var string + */ + const ASC = 'ASC'; + + /** + * @var string + */ + const DESC = 'DESC'; + + /** + * @var \Doctrine\Common\Collections\ExpressionBuilder + */ + private static $expressionBuilder; + + /** + * @var \Doctrine\Common\Collections\Expr\Expression + */ + private $expression; + + /** + * @var array|null + */ + private $orderings; + + /** + * @var int + */ + private $firstResult; + + /** + * @var int + */ + private $maxResults; + + /** + * Creates an instance of the class. + * + * @return Criteria + */ + public static function create() + { + return new static(); + } + + /** + * Return the expression builder. + * + * @return \Doctrine\Common\Collections\ExpressionBuilder + */ + public static function expr() + { + if (self::$expressionBuilder === null) { + self::$expressionBuilder = new ExpressionBuilder(); + } + return self::$expressionBuilder; + } + + /** + * Construct new criteria + * + * @param Expression $expression + * @param array $orderings + * @param int $firstResult + * @param int $maxResults + */ + public function __construct(Expression $expression = null, array $orderings = null, $firstResult = null, $maxResults = null) + { + $this->expression = $expression; + $this->orderings = $orderings; + $this->firstResult = $firstResult; + $this->maxResults = $maxResults; + } + + /** + * Set the where expression to evaluate when this criteria is searched for. + * + * @param Expression + * @return Criteria + */ + public function where(Expression $expression) + { + $this->expression = $expression; + return $this; + } + + /** + * Append the where expression to evaluate when this criteria is searched for + * using an AND with previous expression. + * + * @param Expression + * @return Criteria + */ + public function andWhere(Expression $expression) + { + if ($this->expression === null) { + return $this->where($expression); + } + + $this->expression = new CompositeExpression(CompositeExpression::TYPE_AND, array( + $this->expression, $expression + )); + + return $this; + } + + /** + * Append the where expression to evaluate when this criteria is searched for + * using an OR with previous expression. + * + * @param Expression + * @return Criteria + */ + public function orWhere(Expression $expression) + { + if ($this->expression === null) { + return $this->where($expression); + } + + $this->expression = new CompositeExpression(CompositeExpression::TYPE_OR, array( + $this->expression, $expression + )); + + return $this; + } + + /** + * Get the expression attached to this criteria. + * + * @return Expression|null + */ + public function getWhereExpression() + { + return $this->expression; + } + + /** + * Get current orderings of this Criteria + * + * @return array + */ + public function getOrderings() + { + return $this->orderings; + } + + /** + * Set the ordering of the result of this criteria. + * + * Keys are field and values are the order, being either ASC or DESC. + * + * @see Criteria::ASC + * @see Criteria::DESC + * + * @param array + * @return Criteria + */ + public function orderBy(array $orderings) + { + $this->orderings = $orderings; + return $this; + } + + /** + * Get current first result option of the critera. + * + * @return firstResult. + */ + public function getFirstResult() + { + return $this->firstResult; + } + + /** + * Set number of first result that this criteria should return. + * + * @param firstResult the value to set. + * @return Criteria + */ + public function setFirstResult($firstResult) + { + $this->firstResult = $firstResult; + return $this; + } + + /** + * Get maxResults. + * + * @return maxResults. + */ + public function getMaxResults() + { + return $this->maxResults; + } + + /** + * Set maxResults. + * + * @param maxResults the value to set. + * @return Criteria + */ + public function setMaxResults($maxResults) + { + $this->maxResults = $maxResults; + return $this; + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php new file mode 100644 index 0000000..06ccb04 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php @@ -0,0 +1,195 @@ +. + */ + +namespace Doctrine\Common\Collections\Expr; + +/** + * Walks an expression graph and turns it into a PHP closure. + * + * This closure can be used with {@Collection#filter()} and is used internally + * by {@ArrayCollection#select()}. + * + * @author Benjamin Eberlei + * @since 2.3 + */ +class ClosureExpressionVisitor extends ExpressionVisitor +{ + /** + * Access the field of a given object. This field has to be public directly + * or indirectly (through an accessor get* or a magic method, __get, __call). + * + * is*() is not supported. + * + * @return mixed + */ + static public function getObjectFieldValue($object, $field) + { + $accessor = "get" . $field; + + if (method_exists($object, $accessor) || method_exists($object, '__call')) { + return $object->$accessor(); + } + + if ($object instanceof \ArrayAccess) { + return $object[$field]; + } + + return $object->$field; + } + + /** + * Helper for sorting arrays of objects based on multiple fields + + * orientations. + * + * @param string $name + * @param int $orientation + * @param Closure $next + * @return Closure + */ + static public function sortByField($name, $orientation = 1, \Closure $next = null) + { + if (!$next) { + $next = function() { + return 0; + }; + } + + return function ($a, $b) use ($name, $next, $orientation) { + $aValue = ClosureExpressionVisitor::getObjectFieldValue($a, $name); + $bValue = ClosureExpressionVisitor::getObjectFieldValue($b, $name); + + if ($aValue === $bValue) { + return $next($a, $b); + } + + return (($aValue > $bValue) ? 1 : -1) * $orientation; + }; + } + + /** + * {@inheritDoc} + */ + public function walkComparison(Comparison $comparison) + { + $field = $comparison->getField(); + $value = $comparison->getValue()->getValue(); // shortcut for walkValue() + + switch ($comparison->getOperator()) { + case Comparison::EQ: + case Comparison::IS: + return function ($object) use ($field, $value) { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value; + }; + + case Comparison::NEQ: + return function ($object) use ($field, $value) { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value; + }; + + case Comparison::LT: + return function ($object) use ($field, $value) { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value; + }; + + case Comparison::LTE: + return function ($object) use ($field, $value) { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value; + }; + + case Comparison::GT: + return function ($object) use ($field, $value) { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value; + }; + + case Comparison::GTE: + return function ($object) use ($field, $value) { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value; + }; + + case Comparison::IN: + return function ($object) use ($field, $value) { + return in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value); + }; + + case Comparison::NIN: + return function ($object) use ($field, $value) { + return ! in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value); + }; + + default: + throw new \RuntimeException("Unknown comparison operator: " . $comparison->getOperator()); + } + } + + /** + * {@inheritDoc} + */ + public function walkValue(Value $value) + { + return $value->getValue(); + } + + /** + * {@inheritDoc} + */ + public function walkCompositeExpression(CompositeExpression $expr) + { + $expressionList = array(); + + foreach ($expr->getExpressionList() as $child) { + $expressionList[] = $this->dispatch($child); + } + + switch($expr->getType()) { + case CompositeExpression::TYPE_AND: + return $this->andExpressions($expressionList); + + case CompositeExpression::TYPE_OR: + return $this->orExpressions($expressionList); + + default: + throw new \RuntimeException("Unknown composite " . $expr->getType()); + } + } + + private function andExpressions($expressions) + { + return function ($object) use ($expressions) { + foreach ($expressions as $expression) { + if ( ! $expression($object)) { + return false; + } + } + return true; + }; + } + + private function orExpressions($expressions) + { + return function ($object) use ($expressions) { + foreach ($expressions as $expression) { + if ($expression($object)) { + return true; + } + } + return false; + }; + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Comparison.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Comparison.php new file mode 100644 index 0000000..29cfcff --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Comparison.php @@ -0,0 +1,75 @@ +. + */ + +namespace Doctrine\Common\Collections\Expr; + +/** + * Comparison of a field with a value by the given operator. + * + * @author Benjamin Eberlei + * @since 2.3 + */ +class Comparison implements Expression +{ + const EQ = '='; + const NEQ = '<>'; + const LT = '<'; + const LTE = '<='; + const GT = '>'; + const GTE = '>='; + const IS = 'IS'; + const IN = 'IN'; + const NIN = 'NIN'; + + private $field; + private $op; + private $value; + + public function __construct($field, $operator, $value) + { + if ( ! ($value instanceof Value)) { + $value = new Value($value); + } + + $this->field = $field; + $this->op = $operator; + $this->value = $value; + } + + public function getField() + { + return $this->field; + } + + public function getValue() + { + return $this->value; + } + + public function getOperator() + { + return $this->op; + } + + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkComparison($this); + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php new file mode 100644 index 0000000..fe917cf --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php @@ -0,0 +1,72 @@ +. + */ + +namespace Doctrine\Common\Collections\Expr; + +/** + * Expression of Expressions combined by AND or OR operation. + * + * @author Benjamin Eberlei + * @since 2.3 + */ +class CompositeExpression implements Expression +{ + const TYPE_AND = 'AND'; + const TYPE_OR = 'OR'; + + private $type; + private $expressions = array(); + + public function __construct($type, array $expressions) + { + $this->type = $type; + + foreach ($expressions as $expr) { + if ($expr instanceof Value) { + throw new \RuntimeException("Values are not supported expressions as children of and/or expressions."); + } + if ( ! ($expr instanceof Expression)) { + throw new \RuntimeException("No expression given to CompositeExpression."); + } + + $this->expressions[] = $expr; + } + } + + /** + * Return the list of expressions nested in this composite. + * + * @return Expression[] + */ + public function getExpressionList() + { + return $this->expressions; + } + + public function getType() + { + return $this->type; + } + + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkCompositeExpression($this); + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Expression.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Expression.php new file mode 100644 index 0000000..b0762ad --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Expression.php @@ -0,0 +1,31 @@ +. + */ + +namespace Doctrine\Common\Collections\Expr; + +/** + * Expression for the {@link Selectable} interface. + * + * @author Benjamin Eberlei + */ +interface Expression +{ + public function visit(ExpressionVisitor $visitor); +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php new file mode 100644 index 0000000..5e69b98 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/ExpressionVisitor.php @@ -0,0 +1,81 @@ +. + */ + +namespace Doctrine\Common\Collections\Expr; + +/** + * An Expression visitor walks a graph of expressions and turns them into a + * query for the underlying implementation. + * + * @author Benjamin Eberlei + */ +abstract class ExpressionVisitor +{ + /** + * Convert a comparison expression into the target query language output + * + * @param Comparison $comparison + * + * @return mixed + */ + abstract public function walkComparison(Comparison $comparison); + + /** + * Convert a value expression into the target query language part. + * + * @param Value $value + * + * @return mixed + */ + abstract public function walkValue(Value $value); + + /** + * Convert a composite expression into the target query language output + * + * @param CompositeExpression $expr + * + * @return mixed + */ + abstract public function walkCompositeExpression(CompositeExpression $expr); + + /** + * Dispatch walking an expression to the appropriate handler. + * + * @param Expression + * + * @return mixed + */ + public function dispatch(Expression $expr) + { + switch (true) { + case ($expr instanceof Comparison): + return $this->walkComparison($expr); + + case ($expr instanceof Value): + return $this->walkValue($expr); + + case ($expr instanceof CompositeExpression): + return $this->walkCompositeExpression($expr); + + default: + throw new \RuntimeException("Unknown Expression " . get_class($expr)); + } + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Value.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Value.php new file mode 100644 index 0000000..f0df11a --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Expr/Value.php @@ -0,0 +1,41 @@ +. + */ + +namespace Doctrine\Common\Collections\Expr; + +class Value implements Expression +{ + private $value; + + public function __construct($value) + { + $this->value = $value; + } + + public function getValue() + { + return $this->value; + } + + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkValue($this); + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/ExpressionBuilder.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/ExpressionBuilder.php new file mode 100644 index 0000000..b53f0cd --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/ExpressionBuilder.php @@ -0,0 +1,149 @@ +. + */ + +namespace Doctrine\Common\Collections; + +use Doctrine\Common\Collections\Expr\Comparison; +use Doctrine\Common\Collections\Expr\CompositeExpression; +use Doctrine\Common\Collections\Expr\Value; + +/** + * Builder for Expressions in the {@link Selectable} interface. + * + * @author Benjamin Eberlei + * @since 2.3 + */ +class ExpressionBuilder +{ + /** + * @return CompositeExpression + */ + public function andX($x = null) + { + return new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args()); + } + + /** + * @return CompositeExpression + */ + public function orX($x = null) + { + return new CompositeExpression(CompositeExpression::TYPE_OR, func_get_args()); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function eq($field, $value) + { + return new Comparison($field, Comparison::EQ, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function gt($field, $value) + { + return new Comparison($field, Comparison::GT, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function lt($field, $value) + { + return new Comparison($field, Comparison::LT, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function gte($field, $value) + { + return new Comparison($field, Comparison::GTE, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function lte($field, $value) + { + return new Comparison($field, Comparison::LTE, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function neq($field, $value) + { + return new Comparison($field, Comparison::NEQ, new Value($value)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function isNull($field) + { + return new Comparison($field, Comparison::IS, new Value(null)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function in($field, array $values) + { + return new Comparison($field, Comparison::IN, new Value($values)); + } + + /** + * @param string $field + * @param mixed $value + * + * @return Comparison + */ + public function notIn($field, array $values) + { + return new Comparison($field, Comparison::NIN, new Value($values)); + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Collections/Selectable.php b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Selectable.php new file mode 100644 index 0000000..675d6ea --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Collections/Selectable.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\Common\Collections; + +/** + * Interface for collections that allow efficient filtering with an expression API. + * + * Goal of this interface is a backend independent method to fetch elements + * from a collections. {@link Expression} is crafted in a way that you can + * implement queries from both in-memory and database-backed collections. + * + * For database backed collections this allows very efficient access by + * utilizing the query APIs, for example SQL in the ORM. Applications using + * this API can implement efficient database access without having to ask the + * EntityManager or Repositories. + * + * @author Benjamin Eberlei + * @since 2.3 + */ +interface Selectable +{ + /** + * Select all elements from a selectable that match the expression and + * return a new collection containing these elements. + * + * @param Criteria $criteria + * @return Collection + */ + function matching(Criteria $criteria); +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/CommonException.php b/vendor/doctrine/common/lib/Doctrine/Common/CommonException.php new file mode 100644 index 0000000..6db7675 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/CommonException.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\Common; + +/** + * Base exception class for package Doctrine\Common + * @author heinrich + * + */ +class CommonException extends \Exception { +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Comparable.php b/vendor/doctrine/common/lib/Doctrine/Common/Comparable.php new file mode 100644 index 0000000..20d065e --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Comparable.php @@ -0,0 +1,49 @@ +. + */ + + +namespace Doctrine\Common; + +/** + * Comparable interface that allows to compare two value objects to each other for similarity. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + */ +interface Comparable +{ + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantical equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other + * + * @return int + */ + public function compareTo($other); +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/EventArgs.php b/vendor/doctrine/common/lib/Doctrine/Common/EventArgs.php new file mode 100644 index 0000000..a87eee8 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/EventArgs.php @@ -0,0 +1,67 @@ +. + */ + +namespace Doctrine\Common; + +/** + * EventArgs is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass state + * information to an event handler when an event is raised. The single empty EventArgs + * instance can be obtained through {@link getEmptyInstance}. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EventArgs +{ + /** + * @var EventArgs Single instance of EventArgs + */ + private static $_emptyEventArgsInstance; + + /** + * Gets the single, empty and immutable EventArgs instance. + * + * This instance will be used when events are dispatched without any parameter, + * like this: EventManager::dispatchEvent('eventname'); + * + * The benefit from this is that only one empty instance is instantiated and shared + * (otherwise there would be instances for every dispatched in the abovementioned form) + * + * @see EventManager::dispatchEvent + * @link http://msdn.microsoft.com/en-us/library/system.eventargs.aspx + * @return EventArgs + */ + public static function getEmptyInstance() + { + if ( ! self::$_emptyEventArgsInstance) { + self::$_emptyEventArgsInstance = new EventArgs; + } + + return self::$_emptyEventArgsInstance; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/EventManager.php b/vendor/doctrine/common/lib/Doctrine/Common/EventManager.php new file mode 100644 index 0000000..25aac44 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/EventManager.php @@ -0,0 +1,147 @@ +. + */ + +namespace Doctrine\Common; + +/** + * The EventManager is the central point of Doctrine's event listener system. + * Listeners are registered on the manager and events are dispatched through the + * manager. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EventManager +{ + /** + * Map of registered listeners. + * => + * + * @var array + */ + private $_listeners = array(); + + /** + * Dispatches an event to all registered listeners. + * + * @param string $eventName The name of the event to dispatch. The name of the event is + * the name of the method that is invoked on listeners. + * @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners. + * If not supplied, the single empty EventArgs instance is used. + * @return boolean + */ + public function dispatchEvent($eventName, EventArgs $eventArgs = null) + { + if (isset($this->_listeners[$eventName])) { + $eventArgs = $eventArgs === null ? EventArgs::getEmptyInstance() : $eventArgs; + + foreach ($this->_listeners[$eventName] as $listener) { + $listener->$eventName($eventArgs); + } + } + } + + /** + * Gets the listeners of a specific event or all listeners. + * + * @param string $event The name of the event. + * @return array The event listeners for the specified event, or all event listeners. + */ + public function getListeners($event = null) + { + return $event ? $this->_listeners[$event] : $this->_listeners; + } + + /** + * Checks whether an event has any registered listeners. + * + * @param string $event + * @return boolean TRUE if the specified event has any listeners, FALSE otherwise. + */ + public function hasListeners($event) + { + return isset($this->_listeners[$event]) && $this->_listeners[$event]; + } + + /** + * Adds an event listener that listens on the specified events. + * + * @param string|array $events The event(s) to listen on. + * @param object $listener The listener object. + */ + public function addEventListener($events, $listener) + { + // Picks the hash code related to that listener + $hash = spl_object_hash($listener); + + foreach ((array) $events as $event) { + // Overrides listener if a previous one was associated already + // Prevents duplicate listeners on same event (same instance only) + $this->_listeners[$event][$hash] = $listener; + } + } + + /** + * Removes an event listener from the specified events. + * + * @param string|array $events + * @param object $listener + */ + public function removeEventListener($events, $listener) + { + // Picks the hash code related to that listener + $hash = spl_object_hash($listener); + + foreach ((array) $events as $event) { + // Check if actually have this listener associated + if (isset($this->_listeners[$event][$hash])) { + unset($this->_listeners[$event][$hash]); + } + } + } + + /** + * Adds an EventSubscriber. The subscriber is asked for all the events he is + * interested in and added as a listener for these events. + * + * @param \Doctrine\Common\EventSubscriber $subscriber The subscriber. + */ + public function addEventSubscriber(EventSubscriber $subscriber) + { + $this->addEventListener($subscriber->getSubscribedEvents(), $subscriber); + } + + /** + * Removes an EventSubscriber. The subscriber is asked for all the events it is + * interested in and removed as a listener for these events. + * + * @param \Doctrine\Common\EventSubscriber $subscriber The subscriber. + */ + public function removeEventSubscriber(EventSubscriber $subscriber) + { + $this->removeEventListener($subscriber->getSubscribedEvents(), $subscriber); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/EventSubscriber.php b/vendor/doctrine/common/lib/Doctrine/Common/EventSubscriber.php new file mode 100644 index 0000000..1458791 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/EventSubscriber.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\Common; + +/** + * An EventSubscriber knows himself what events he is interested in. + * If an EventSubscriber is added to an EventManager, the manager invokes + * {@link getSubscribedEvents} and registers the subscriber as a listener for all + * returned events. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +interface EventSubscriber +{ + /** + * Returns an array of events this subscriber wants to listen to. + * + * @return array + */ + function getSubscribedEvents(); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Lexer.php b/vendor/doctrine/common/lib/Doctrine/Common/Lexer.php new file mode 100644 index 0000000..8e2554c --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Lexer.php @@ -0,0 +1,266 @@ +. + */ + +namespace Doctrine\Common; + +/** + * Base class for writing simple lexers, i.e. for creating small DSLs. + * + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @todo Rename: AbstractLexer + */ +abstract class Lexer +{ + /** + * @var array Array of scanned tokens + */ + private $tokens = array(); + + /** + * @var integer Current lexer position in input string + */ + private $position = 0; + + /** + * @var integer Current peek of current lexer position + */ + private $peek = 0; + + /** + * @var array The next token in the input. + */ + public $lookahead; + + /** + * @var array The last matched/seen token. + */ + public $token; + + /** + * Sets the input data to be tokenized. + * + * The Lexer is immediately reset and the new input tokenized. + * Any unprocessed tokens from any previous input are lost. + * + * @param string $input The input to be tokenized. + */ + public function setInput($input) + { + $this->tokens = array(); + $this->reset(); + $this->scan($input); + } + + /** + * Resets the lexer. + */ + public function reset() + { + $this->lookahead = null; + $this->token = null; + $this->peek = 0; + $this->position = 0; + } + + /** + * Resets the peek pointer to 0. + */ + public function resetPeek() + { + $this->peek = 0; + } + + /** + * Resets the lexer position on the input to the given position. + * + * @param integer $position Position to place the lexical scanner + */ + public function resetPosition($position = 0) + { + $this->position = $position; + } + + /** + * Checks whether a given token matches the current lookahead. + * + * @param integer|string $token + * @return boolean + */ + public function isNextToken($token) + { + return null !== $this->lookahead && $this->lookahead['type'] === $token; + } + + /** + * Checks whether any of the given tokens matches the current lookahead + * + * @param array $tokens + * @return boolean + */ + public function isNextTokenAny(array $tokens) + { + return null !== $this->lookahead && in_array($this->lookahead['type'], $tokens, true); + } + + /** + * Moves to the next token in the input string. + * + * A token is an associative array containing three items: + * - 'value' : the string value of the token in the input string + * - 'type' : the type of the token (identifier, numeric, string, input + * parameter, none) + * - 'position' : the position of the token in the input string + * + * @return array|null the next token; null if there is no more tokens left + */ + public function moveNext() + { + $this->peek = 0; + $this->token = $this->lookahead; + $this->lookahead = (isset($this->tokens[$this->position])) + ? $this->tokens[$this->position++] : null; + + return $this->lookahead !== null; + } + + /** + * Tells the lexer to skip input tokens until it sees a token with the given value. + * + * @param string $type The token type to skip until. + */ + public function skipUntil($type) + { + while ($this->lookahead !== null && $this->lookahead['type'] !== $type) { + $this->moveNext(); + } + } + + /** + * Checks if given value is identical to the given token + * + * @param mixed $value + * @param integer $token + * @return boolean + */ + public function isA($value, $token) + { + return $this->getType($value) === $token; + } + + /** + * Moves the lookahead token forward. + * + * @return array | null The next token or NULL if there are no more tokens ahead. + */ + public function peek() + { + if (isset($this->tokens[$this->position + $this->peek])) { + return $this->tokens[$this->position + $this->peek++]; + } else { + return null; + } + } + + /** + * Peeks at the next token, returns it and immediately resets the peek. + * + * @return array|null The next token or NULL if there are no more tokens ahead. + */ + public function glimpse() + { + $peek = $this->peek(); + $this->peek = 0; + return $peek; + } + + /** + * Scans the input string for tokens. + * + * @param string $input a query string + */ + protected function scan($input) + { + static $regex; + + if ( ! isset($regex)) { + $regex = '/(' . implode(')|(', $this->getCatchablePatterns()) . ')|' + . implode('|', $this->getNonCatchablePatterns()) . '/i'; + } + + $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE; + $matches = preg_split($regex, $input, -1, $flags); + + foreach ($matches as $match) { + // Must remain before 'value' assignment since it can change content + $type = $this->getType($match[0]); + + $this->tokens[] = array( + 'value' => $match[0], + 'type' => $type, + 'position' => $match[1], + ); + } + } + + /** + * Gets the literal for a given token. + * + * @param integer $token + * @return string + */ + public function getLiteral($token) + { + $className = get_class($this); + $reflClass = new \ReflectionClass($className); + $constants = $reflClass->getConstants(); + + foreach ($constants as $name => $value) { + if ($value === $token) { + return $className . '::' . $name; + } + } + + return $token; + } + + /** + * Lexical catchable patterns. + * + * @return array + */ + abstract protected function getCatchablePatterns(); + + /** + * Lexical non-catchable patterns. + * + * @return array + */ + abstract protected function getNonCatchablePatterns(); + + /** + * Retrieve token type. Also processes the token value if necessary. + * + * @param string $value + * @return integer + */ + abstract protected function getType(&$value); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/NotifyPropertyChanged.php b/vendor/doctrine/common/lib/Doctrine/Common/NotifyPropertyChanged.php new file mode 100644 index 0000000..e32c0b9 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/NotifyPropertyChanged.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\Common; + +/** + * Contract for classes that provide the service of notifying listeners of + * changes to their properties. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +interface NotifyPropertyChanged +{ + /** + * Adds a listener that wants to be notified about property changes. + * + * @param PropertyChangedListener $listener + */ + function addPropertyChangedListener(PropertyChangedListener $listener); +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/AbstractManagerRegistry.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/AbstractManagerRegistry.php new file mode 100644 index 0000000..94fcd05 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/AbstractManagerRegistry.php @@ -0,0 +1,259 @@ +. + */ + +namespace Doctrine\Common\Persistence; + +use Doctrine\Common\Persistence\ManagerRegistry; + +/** + * Abstract implementation of the ManagerRegistry contract. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.2 + * @author Fabien Potencier + * @author Benjamin Eberlei + * @author Lukas Kahwe Smith + */ +abstract class AbstractManagerRegistry implements ManagerRegistry +{ + /** + * @var string + */ + private $name; + + /** + * @var array + */ + private $connections; + + /** + * @var array + */ + private $managers; + + /** + * @var string + */ + private $defaultConnection; + + /** + * @var string + */ + private $defaultManager; + + /** + * @var string + */ + private $proxyInterfaceName; + + /** + * Constructor + * + * @param string $name + * @param array $connections + * @param array $managers + * @param string $defaultConnection + * @param string $defaultManager + * @param string $proxyInterfaceName + */ + public function __construct($name, array $connections, array $managers, $defaultConnection, $defaultManager, $proxyInterfaceName) + { + $this->name = $name; + $this->connections = $connections; + $this->managers = $managers; + $this->defaultConnection = $defaultConnection; + $this->defaultManager = $defaultManager; + $this->proxyInterfaceName = $proxyInterfaceName; + } + + /** + * Fetches/creates the given services + * + * A service in this context is connection or a manager instance + * + * @param string $name name of the service + * @return object instance of the given service + */ + abstract protected function getService($name); + + /** + * Resets the given services + * + * A service in this context is connection or a manager instance + * + * @param string $name name of the service + * @return void + */ + abstract protected function resetService($name); + + /** + * Get the name of the registry + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function getConnection($name = null) + { + if (null === $name) { + $name = $this->defaultConnection; + } + + if (!isset($this->connections[$name])) { + throw new \InvalidArgumentException(sprintf('Doctrine %s Connection named "%s" does not exist.', $this->name, $name)); + } + + return $this->getService($this->connections[$name]); + } + + /** + * {@inheritdoc} + */ + public function getConnectionNames() + { + return $this->connections; + } + + /** + * {@inheritdoc} + */ + public function getConnections() + { + $connections = array(); + foreach ($this->connections as $name => $id) { + $connections[$name] = $this->getService($id); + } + + return $connections; + } + + /** + * {@inheritdoc} + */ + public function getDefaultConnectionName() + { + return $this->defaultConnection; + } + + /** + * {@inheritdoc} + */ + public function getDefaultManagerName() + { + return $this->defaultManager; + } + + /** + * {@inheritdoc} + * + * @throws \InvalidArgumentException + */ + public function getManager($name = null) + { + if (null === $name) { + $name = $this->defaultManager; + } + + if (!isset($this->managers[$name])) { + throw new \InvalidArgumentException(sprintf('Doctrine %s Manager named "%s" does not exist.', $this->name, $name)); + } + + return $this->getService($this->managers[$name]); + } + + /** + * {@inheritdoc} + */ + public function getManagerForClass($class) + { + // Check for namespace alias + if (strpos($class, ':') !== false) { + list($namespaceAlias, $simpleClassName) = explode(':', $class); + $class = $this->getAliasNamespace($namespaceAlias) . '\\' . $simpleClassName; + } + + $proxyClass = new \ReflectionClass($class); + if ($proxyClass->implementsInterface($this->proxyInterfaceName)) { + $class = $proxyClass->getParentClass()->getName(); + } + + foreach ($this->managers as $id) { + $manager = $this->getService($id); + + if (!$manager->getMetadataFactory()->isTransient($class)) { + return $manager; + } + } + } + + /** + * {@inheritdoc} + */ + public function getManagerNames() + { + return $this->managers; + } + + /** + * {@inheritdoc} + */ + public function getManagers() + { + $dms = array(); + foreach ($this->managers as $name => $id) { + $dms[$name] = $this->getService($id); + } + + return $dms; + } + + /** + * {@inheritdoc} + */ + public function getRepository($persistentObjectName, $persistentManagerName = null) + { + return $this->getManager($persistentManagerName)->getRepository($persistentObjectName); + } + + /** + * {@inheritdoc} + */ + public function resetManager($name = null) + { + if (null === $name) { + $name = $this->defaultManager; + } + + if (!isset($this->managers[$name])) { + throw new \InvalidArgumentException(sprintf('Doctrine %s Manager named "%s" does not exist.', $this->name, $name)); + } + + // force the creation of a new document manager + // if the current one is closed + $this->resetService($this->managers[$name]); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ConnectionRegistry.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ConnectionRegistry.php new file mode 100644 index 0000000..7d6f0cf --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ConnectionRegistry.php @@ -0,0 +1,63 @@ +. + */ + +namespace Doctrine\Common\Persistence; + +/** + * Contract covering connection for a Doctrine persistence layer ManagerRegistry class to implement. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.2 + * @author Fabien Potencier + * @author Benjamin Eberlei + * @author Lukas Kahwe Smith + */ +interface ConnectionRegistry +{ + /** + * Gets the default connection name. + * + * @return string The default connection name + */ + function getDefaultConnectionName(); + + /** + * Gets the named connection. + * + * @param string $name The connection name (null for the default one) + * + * @return object + */ + function getConnection($name = null); + + /** + * Gets an array of all registered connections + * + * @return array An array of Connection instances + */ + function getConnections(); + + /** + * Gets all connection names. + * + * @return array An array of connection names + */ + function getConnectionNames(); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LifecycleEventArgs.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LifecycleEventArgs.php new file mode 100644 index 0000000..2fb7c47 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LifecycleEventArgs.php @@ -0,0 +1,77 @@ +. +*/ + +namespace Doctrine\Common\Persistence\Event; + +use Doctrine\Common\EventArgs; +use Doctrine\Common\Persistence\ObjectManager; + +/** + * Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions + * of entities. + * + * @link www.doctrine-project.org + * @since 2.2 + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class LifecycleEventArgs extends EventArgs +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var object + */ + private $entity; + + /** + * Constructor + * + * @param object $entity + * @param ObjectManager $objectManager + */ + public function __construct($entity, ObjectManager $objectManager) + { + $this->entity = $entity; + $this->objectManager = $objectManager; + } + + /** + * Retrieve associated Entity. + * + * @return object + */ + public function getEntity() + { + return $this->entity; + } + + /** + * Retrieve associated ObjectManager. + * + * @return ObjectManager + */ + public function getObjectManager() + { + return $this->objectManager; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LoadClassMetadataEventArgs.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LoadClassMetadataEventArgs.php new file mode 100644 index 0000000..c014d73 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/LoadClassMetadataEventArgs.php @@ -0,0 +1,76 @@ +. + */ + +namespace Doctrine\Common\Persistence\Event; + +use Doctrine\Common\EventArgs; +use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Common\Persistence\Mapping\ClassMetadata; + +/** + * Class that holds event arguments for a loadMetadata event. + * + * @author Jonathan H. Wage + * @since 2.2 + */ +class LoadClassMetadataEventArgs extends EventArgs +{ + /** + * @var ClassMetadata + */ + private $classMetadata; + + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * Constructor. + * + * @param ClassMetadata $classMetadata + * @param ObjectManager $objectManager + */ + public function __construct(ClassMetadata $classMetadata, ObjectManager $objectManager) + { + $this->classMetadata = $classMetadata; + $this->objectManager = $objectManager; + } + + /** + * Retrieve associated ClassMetadata. + * + * @return ClassMetadata + */ + public function getClassMetadata() + { + return $this->classMetadata; + } + + /** + * Retrieve associated ObjectManager. + * + * @return ObjectManager + */ + public function getObjectManager() + { + return $this->objectManager; + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/ManagerEventArgs.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/ManagerEventArgs.php new file mode 100644 index 0000000..f139365 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/ManagerEventArgs.php @@ -0,0 +1,59 @@ +. +*/ + +namespace Doctrine\Common\Persistence\Event; + +use Doctrine\Common\Persistence\ObjectManager; + +/** + * Provides event arguments for the preFlush event. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.2 + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class ManagerEventArgs extends \Doctrine\Common\EventArgs +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * Constructor. + * + * @param ObjectManager $objectManager + */ + public function __construct(ObjectManager $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Retrieve associated ObjectManager. + * + * @return ObjectManager + */ + public function getObjectManager() + { + return $this->objectManager; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/OnClearEventArgs.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/OnClearEventArgs.php new file mode 100644 index 0000000..18b6554 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/OnClearEventArgs.php @@ -0,0 +1,84 @@ +. + */ + +namespace Doctrine\Common\Persistence\Event; + +/** + * Provides event arguments for the onClear event. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.2 + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class OnClearEventArgs extends \Doctrine\Common\EventArgs +{ + /** + * @var \Doctrine\Common\Persistence\ObjectManager + */ + private $objectManager; + + /** + * @var string + */ + private $entityClass; + + /** + * Constructor. + * + * @param \Doctrine\Common\Persistence\ObjectManager $objectManager + * @param string $entityClass Optional entity class + */ + public function __construct($objectManager, $entityClass = null) + { + $this->objectManager = $objectManager; + $this->entityClass = $entityClass; + } + + /** + * Retrieve associated ObjectManager. + * + * @return \Doctrine\Common\Persistence\ObjectManager + */ + public function getObjectManager() + { + return $this->objectManager; + } + + /** + * Name of the entity class that is cleared, or empty if all are cleared. + * + * @return string + */ + public function getEntityClass() + { + return $this->entityClass; + } + + /** + * Check if event clears all entities. + * + * @return bool + */ + public function clearsAllEntities() + { + return ($this->entityClass === null); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/PreUpdateEventArgs.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/PreUpdateEventArgs.php new file mode 100644 index 0000000..86ac819 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Event/PreUpdateEventArgs.php @@ -0,0 +1,133 @@ +. + */ + +namespace Doctrine\Common\Persistence\Event; + +use Doctrine\Common\EventArgs, + Doctrine\Common\Persistence\ObjectManager; + +/** + * Class that holds event arguments for a preUpdate event. + * + * @author Guilherme Blanco + * @author Roman Borschel + * @author Benjamin Eberlei + * @since 2.2 + */ +class PreUpdateEventArgs extends LifecycleEventArgs +{ + /** + * @var array + */ + private $entityChangeSet; + + /** + * Constructor. + * + * @param object $entity + * @param ObjectManager $objectManager + * @param array $changeSet + */ + public function __construct($entity, ObjectManager $objectManager, array &$changeSet) + { + parent::__construct($entity, $objectManager); + + $this->entityChangeSet = &$changeSet; + } + + /** + * Retrieve entity changeset. + * + * @return array + */ + public function getEntityChangeSet() + { + return $this->entityChangeSet; + } + + /** + * Check if field has a changeset. + * + * @param string $field + * + * @return boolean + */ + public function hasChangedField($field) + { + return isset($this->entityChangeSet[$field]); + } + + /** + * Get the old value of the changeset of the changed field. + * + * @param string $field + * @return mixed + */ + public function getOldValue($field) + { + $this->assertValidField($field); + + return $this->entityChangeSet[$field][0]; + } + + /** + * Get the new value of the changeset of the changed field. + * + * @param string $field + * @return mixed + */ + public function getNewValue($field) + { + $this->assertValidField($field); + + return $this->entityChangeSet[$field][1]; + } + + /** + * Set the new value of this field. + * + * @param string $field + * @param mixed $value + */ + public function setNewValue($field, $value) + { + $this->assertValidField($field); + + $this->entityChangeSet[$field][1] = $value; + } + + /** + * Assert the field exists in changeset. + * + * @param string $field + * + * @throws \InvalidArgumentException + */ + private function assertValidField($field) + { + if ( ! isset($this->entityChangeSet[$field])) { + throw new \InvalidArgumentException(sprintf( + 'Field "%s" is not a valid field of the entity "%s" in PreUpdateEventArgs.', + $field, + get_class($this->getEntity()) + )); + } + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ManagerRegistry.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ManagerRegistry.php new file mode 100644 index 0000000..bdb23bd --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ManagerRegistry.php @@ -0,0 +1,112 @@ +. + */ + +namespace Doctrine\Common\Persistence; + +/** + * Contract covering object managers for a Doctrine persistence layer ManagerRegistry class to implement. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.2 + * @author Fabien Potencier + * @author Benjamin Eberlei + * @author Lukas Kahwe Smith + */ +interface ManagerRegistry extends ConnectionRegistry +{ + /** + * Gets the default object manager name. + * + * @return string The default object manager name + */ + function getDefaultManagerName(); + + /** + * Gets a named object manager. + * + * @param string $name The object manager name (null for the default one) + * + * @return \Doctrine\Common\Persistence\ObjectManager + */ + function getManager($name = null); + + /** + * Gets an array of all registered object managers + * + * @return \Doctrine\Common\Persistence\ObjectManager[] An array of ObjectManager instances + */ + function getManagers(); + + /** + * Resets a named object manager. + * + * This method is useful when an object manager has been closed + * because of a rollbacked transaction AND when you think that + * it makes sense to get a new one to replace the closed one. + * + * Be warned that you will get a brand new object manager as + * the existing one is not useable anymore. This means that any + * other object with a dependency on this object manager will + * hold an obsolete reference. You can inject the registry instead + * to avoid this problem. + * + * @param string $name The object manager name (null for the default one) + * + * @return \Doctrine\Common\Persistence\ObjectManager + */ + function resetManager($name = null); + + /** + * Resolves a registered namespace alias to the full namespace. + * + * This method looks for the alias in all registered object managers. + * + * @param string $alias The alias + * + * @return string The full namespace + */ + function getAliasNamespace($alias); + + /** + * Gets all connection names. + * + * @return array An array of connection names + */ + function getManagerNames(); + + /** + * Gets the ObjectRepository for an persistent object. + * + * @param string $persistentObject The name of the persistent object. + * @param string $persistentManagerName The object manager name (null for the default one) + * + * @return \Doctrine\Common\Persistence\ObjectRepository + */ + function getRepository($persistentObject, $persistentManagerName = null); + + /** + * Gets the object manager associated with a given class. + * + * @param string $class A persistent object class name + * + * @return \Doctrine\Common\Persistence\ObjectManager|null + */ + function getManagerForClass($class); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php new file mode 100644 index 0000000..1ace1cc --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -0,0 +1,383 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping; + +use Doctrine\Common\Cache\Cache, + Doctrine\Common\Util\ClassUtils; + +/** + * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the + * metadata mapping informations of a class which describes how a class should be mapped + * to a relational database. + * + * This class was abstracted from the ORM ClassMetadataFactory + * + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +abstract class AbstractClassMetadataFactory implements ClassMetadataFactory +{ + /** + * Salt used by specific Object Manager implementation. + * + * @var string + */ + protected $cacheSalt = "\$CLASSMETADATA"; + + /** + * @var \Doctrine\Common\Cache\Cache + */ + private $cacheDriver; + + /** + * @var array + */ + private $loadedMetadata = array(); + + /** + * @var bool + */ + protected $initialized = false; + + /** + * @var ReflectionService + */ + private $reflectionService; + + /** + * Sets the cache driver used by the factory to cache ClassMetadata instances. + * + * @param Doctrine\Common\Cache\Cache $cacheDriver + */ + public function setCacheDriver(Cache $cacheDriver = null) + { + $this->cacheDriver = $cacheDriver; + } + + /** + * Gets the cache driver used by the factory to cache ClassMetadata instances. + * + * @return Doctrine\Common\Cache\Cache + */ + public function getCacheDriver() + { + return $this->cacheDriver; + } + + /** + * Return an array of all the loaded metadata currently in memory. + * + * @return array + */ + public function getLoadedMetadata() + { + return $this->loadedMetadata; + } + + /** + * Forces the factory to load the metadata of all classes known to the underlying + * mapping driver. + * + * @return array The ClassMetadata instances of all mapped classes. + */ + public function getAllMetadata() + { + if ( ! $this->initialized) { + $this->initialize(); + } + + $driver = $this->getDriver(); + $metadata = array(); + foreach ($driver->getAllClassNames() as $className) { + $metadata[] = $this->getMetadataFor($className); + } + + return $metadata; + } + + /** + * Lazy initialization of this stuff, especially the metadata driver, + * since these are not needed at all when a metadata cache is active. + * + * @return void + */ + abstract protected function initialize(); + + /** + * Get the fully qualified class-name from the namespace alias. + * + * @param string $namespaceAlias + * @param string $simpleClassName + * @return string + */ + abstract protected function getFqcnFromAlias($namespaceAlias, $simpleClassName); + + /** + * Return the mapping driver implementation. + * + * @return \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver + */ + abstract protected function getDriver(); + + /** + * Wakeup reflection after ClassMetadata gets unserialized from cache. + * + * @param ClassMetadata $class + * @param ReflectionService $reflService + * @return void + */ + abstract protected function wakeupReflection(ClassMetadata $class, ReflectionService $reflService); + + /** + * Initialize Reflection after ClassMetadata was constructed. + * + * @param ClassMetadata $class + * @param ReflectionService $reflService + * @return void + */ + abstract protected function initializeReflection(ClassMetadata $class, ReflectionService $reflService); + + /** + * Checks whether the class metadata is an entity. + * + * This method should false for mapped superclasses or + * embedded classes. + * + * @param ClassMetadata $class + * @return boolean + */ + abstract protected function isEntity(ClassMetadata $class); + + /** + * Gets the class metadata descriptor for a class. + * + * @param string $className The name of the class. + * @return \Doctrine\Common\Persistence\Mapping\ClassMetadata + */ + public function getMetadataFor($className) + { + if (isset($this->loadedMetadata[$className])) { + return $this->loadedMetadata[$className]; + } + + $realClassName = $className; + + // Check for namespace alias + if (strpos($className, ':') !== false) { + list($namespaceAlias, $simpleClassName) = explode(':', $className); + $realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName); + } else { + $realClassName = ClassUtils::getRealClass($realClassName); + } + + if (isset($this->loadedMetadata[$realClassName])) { + // We do not have the alias name in the map, include it + $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName]; + + return $this->loadedMetadata[$realClassName]; + } + + if ($this->cacheDriver) { + if (($cached = $this->cacheDriver->fetch($realClassName . $this->cacheSalt)) !== false) { + $this->loadedMetadata[$realClassName] = $cached; + $this->wakeupReflection($cached, $this->getReflectionService()); + } else { + foreach ($this->loadMetadata($realClassName) as $loadedClassName) { + $this->cacheDriver->save( + $loadedClassName . $this->cacheSalt, $this->loadedMetadata[$loadedClassName], null + ); + } + } + } else { + $this->loadMetadata($realClassName); + } + + if ($className != $realClassName) { + // We do not have the alias name in the map, include it + $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName]; + } + + return $this->loadedMetadata[$className]; + } + + /** + * Checks whether the factory has the metadata for a class loaded already. + * + * @param string $className + * @return boolean TRUE if the metadata of the class in question is already loaded, FALSE otherwise. + */ + public function hasMetadataFor($className) + { + return isset($this->loadedMetadata[$className]); + } + + /** + * Sets the metadata descriptor for a specific class. + * + * NOTE: This is only useful in very special cases, like when generating proxy classes. + * + * @param string $className + * @param ClassMetadata $class + */ + public function setMetadataFor($className, $class) + { + $this->loadedMetadata[$className] = $class; + } + + /** + * Get array of parent classes for the given entity class + * + * @param string $name + * @return array $parentClasses + */ + protected function getParentClasses($name) + { + // Collect parent classes, ignoring transient (not-mapped) classes. + $parentClasses = array(); + foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) { + if ( ! $this->getDriver()->isTransient($parentClass)) { + $parentClasses[] = $parentClass; + } + } + return $parentClasses; + } + + /** + * Loads the metadata of the class in question and all it's ancestors whose metadata + * is still not loaded. + * + * @param string $name The name of the class for which the metadata should get loaded. + * + * @return array + */ + protected function loadMetadata($name) + { + if ( ! $this->initialized) { + $this->initialize(); + } + + $loaded = array(); + + $parentClasses = $this->getParentClasses($name); + $parentClasses[] = $name; + + // Move down the hierarchy of parent classes, starting from the topmost class + $parent = null; + $rootEntityFound = false; + $visited = array(); + $reflService = $this->getReflectionService(); + foreach ($parentClasses as $className) { + if (isset($this->loadedMetadata[$className])) { + $parent = $this->loadedMetadata[$className]; + if ($this->isEntity($parent)) { + $rootEntityFound = true; + array_unshift($visited, $className); + } + continue; + } + + $class = $this->newClassMetadataInstance($className); + $this->initializeReflection($class, $reflService); + + $this->doLoadMetadata($class, $parent, $rootEntityFound, $visited); + + $this->loadedMetadata[$className] = $class; + + $parent = $class; + + if ($this->isEntity($class)) { + $rootEntityFound = true; + array_unshift($visited, $className); + } + + $this->wakeupReflection($class, $reflService); + + $loaded[] = $className; + } + + return $loaded; + } + + /** + * Actually load the metadata from the underlying metadata + * + * @param ClassMetadata $class + * @param ClassMetadata|null $parent + * @param bool $rootEntityFound + * @param array $nonSuperclassParents classnames all parent classes that are not marked as mapped superclasses + * @return void + */ + abstract protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents); + + /** + * Creates a new ClassMetadata instance for the given class name. + * + * @param string $className + * @return ClassMetadata + */ + abstract protected function newClassMetadataInstance($className); + + /** + * Check if this class is mapped by this Object Manager + ClassMetadata configuration + * + * @param $class + * @return bool + */ + public function isTransient($class) + { + if ( ! $this->initialized) { + $this->initialize(); + } + + // Check for namespace alias + if (strpos($class, ':') !== false) { + list($namespaceAlias, $simpleClassName) = explode(':', $class); + $class = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName); + } + + return $this->getDriver()->isTransient($class); + } + + /** + * Set reflectionService. + * + * @param ReflectionService $reflectionService + */ + public function setReflectionService(ReflectionService $reflectionService) + { + $this->reflectionService = $reflectionService; + } + + /** + * Get the reflection service associated with this metadata factory. + * + * @return ReflectionService + */ + public function getReflectionService() + { + if ($this->reflectionService === null) { + $this->reflectionService = new RuntimeReflectionService(); + } + return $this->reflectionService; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadata.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadata.php new file mode 100644 index 0000000..4836bf8 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadata.php @@ -0,0 +1,165 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping; + +/** + * Contract for a Doctrine persistence layer ClassMetadata class to implement. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.1 + * @author Benjamin Eberlei + * @author Jonathan Wage + */ +interface ClassMetadata +{ + /** + * Get fully-qualified class name of this persistent class. + * + * @return string + */ + function getName(); + + /** + * Gets the mapped identifier field name. + * + * The returned structure is an array of the identifier field names. + * + * @return array + */ + function getIdentifier(); + + /** + * Gets the ReflectionClass instance for this mapped class. + * + * @return \ReflectionClass + */ + function getReflectionClass(); + + /** + * Checks if the given field name is a mapped identifier for this class. + * + * @param string $fieldName + * @return boolean + */ + function isIdentifier($fieldName); + + /** + * Checks if the given field is a mapped property for this class. + * + * @param string $fieldName + * @return boolean + */ + function hasField($fieldName); + + /** + * Checks if the given field is a mapped association for this class. + * + * @param string $fieldName + * @return boolean + */ + function hasAssociation($fieldName); + + /** + * Checks if the given field is a mapped single valued association for this class. + * + * @param string $fieldName + * @return boolean + */ + function isSingleValuedAssociation($fieldName); + + /** + * Checks if the given field is a mapped collection valued association for this class. + * + * @param string $fieldName + * @return boolean + */ + function isCollectionValuedAssociation($fieldName); + + /** + * A numerically indexed list of field names of this persistent class. + * + * This array includes identifier fields if present on this class. + * + * @return array + */ + function getFieldNames(); + + /** + * Returns an array of identifier field names numerically indexed. + * + * @return array + */ + function getIdentifierFieldNames(); + + /** + * A numerically indexed list of association names of this persistent class. + * + * This array includes identifier associations if present on this class. + * + * @return array + */ + function getAssociationNames(); + + /** + * Returns a type name of this field. + * + * This type names can be implementation specific but should at least include the php types: + * integer, string, boolean, float/double, datetime. + * + * @param string $fieldName + * @return string + */ + function getTypeOfField($fieldName); + + /** + * Returns the target class name of the given association. + * + * @param string $assocName + * @return string + */ + function getAssociationTargetClass($assocName); + + /** + * Checks if the association is the inverse side of a bidirectional association + * + * @param string $assocName + * @return boolean + */ + function isAssociationInverseSide($assocName); + + /** + * Returns the target field of the owning side of the association + * + * @param string $assocName + * @return string + */ + function getAssociationMappedByTargetField($assocName); + + /** + * Return the identifier of this object as an array with field name as key. + * + * Has to return an empty array if no identifier isset. + * + * @param object $object + * @return array + */ + function getIdentifierValues($object); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadataFactory.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadataFactory.php new file mode 100644 index 0000000..3fa39bc --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ClassMetadataFactory.php @@ -0,0 +1,74 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping; + +/** + * Contract for a Doctrine persistence layer ClassMetadata class to implement. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.1 + * @author Benjamin Eberlei + * @author Jonathan Wage + */ +interface ClassMetadataFactory +{ + /** + * Forces the factory to load the metadata of all classes known to the underlying + * mapping driver. + * + * @return array The ClassMetadata instances of all mapped classes. + */ + function getAllMetadata(); + + /** + * Gets the class metadata descriptor for a class. + * + * @param string $className The name of the class. + * @return ClassMetadata + */ + function getMetadataFor($className); + + /** + * Checks whether the factory has the metadata for a class loaded already. + * + * @param string $className + * @return boolean TRUE if the metadata of the class in question is already loaded, FALSE otherwise. + */ + function hasMetadataFor($className); + + /** + * Sets the metadata descriptor for a specific class. + * + * @param string $className + * @param ClassMetadata $class + */ + function setMetadataFor($className, $class); + + /** + * Whether the class with the specified name should have its metadata loaded. + * This is only the case if it is either mapped directly or as a + * MappedSuperclass. + * + * @param string $className + * @return boolean + */ + function isTransient($className); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/AnnotationDriver.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/AnnotationDriver.php new file mode 100644 index 0000000..1131add --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/AnnotationDriver.php @@ -0,0 +1,214 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping\Driver; + +use Doctrine\Common\Cache\ArrayCache, + Doctrine\Common\Annotations\AnnotationReader, + Doctrine\Common\Annotations\AnnotationRegistry, + Doctrine\Common\Persistence\Mapping\MappingException; + +/** + * The AnnotationDriver reads the mapping metadata from docblock annotations. + * + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel + */ +abstract class AnnotationDriver implements MappingDriver +{ + /** + * The AnnotationReader. + * + * @var AnnotationReader + */ + protected $reader; + + /** + * The paths where to look for mapping files. + * + * @var array + */ + protected $paths = array(); + + /** + * The file extension of mapping documents. + * + * @var string + */ + protected $fileExtension = '.php'; + + /** + * Cache for AnnotationDriver#getAllClassNames() + * + * @var array + */ + protected $classNames; + + /** + * Name of the entity annotations as keys + * + * @var array + */ + protected $entityAnnotationClasses = array(); + + /** + * Initializes a new AnnotationDriver that uses the given AnnotationReader for reading + * docblock annotations. + * + * @param AnnotationReader $reader The AnnotationReader to use, duck-typed. + * @param string|array $paths One or multiple paths where mapping classes can be found. + */ + public function __construct($reader, $paths = null) + { + $this->reader = $reader; + if ($paths) { + $this->addPaths((array) $paths); + } + } + + /** + * Append lookup paths to metadata driver. + * + * @param array $paths + */ + public function addPaths(array $paths) + { + $this->paths = array_unique(array_merge($this->paths, $paths)); + } + + /** + * Retrieve the defined metadata lookup paths. + * + * @return array + */ + public function getPaths() + { + return $this->paths; + } + + /** + * Retrieve the current annotation reader + * + * @return AnnotationReader + */ + public function getReader() + { + return $this->reader; + } + + /** + * Get the file extension used to look for mapping files under + * + * @return string + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Set the file extension used to look for mapping files under + * + * @param string $fileExtension The file extension to set + * @return void + */ + public function setFileExtension($fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * Whether the class with the specified name is transient. Only non-transient + * classes, that is entities and mapped superclasses, should have their metadata loaded. + * + * A class is non-transient if it is annotated with an annotation + * from the {@see AnnotationDriver::entityAnnotationClasses}. + * + * @param string $className + * @return boolean + */ + public function isTransient($className) + { + $classAnnotations = $this->reader->getClassAnnotations(new \ReflectionClass($className)); + + foreach ($classAnnotations as $annot) { + if (isset($this->entityAnnotationClasses[get_class($annot)])) { + return false; + } + } + return true; + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames() + { + if ($this->classNames !== null) { + return $this->classNames; + } + + if (!$this->paths) { + throw MappingException::pathRequired(); + } + + $classes = array(); + $includedFiles = array(); + + foreach ($this->paths as $path) { + if ( ! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new \RegexIterator( + new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS), + \RecursiveIteratorIterator::LEAVES_ONLY + ), + '/^.+' . str_replace('.', '\.', $this->fileExtension) . '$/i', + \RecursiveRegexIterator::GET_MATCH + ); + + foreach ($iterator as $file) { + $sourceFile = realpath($file[0]); + + require_once $sourceFile; + + $includedFiles[] = $sourceFile; + } + } + + $declared = get_declared_classes(); + + foreach ($declared as $className) { + $rc = new \ReflectionClass($className); + $sourceFile = $rc->getFileName(); + if (in_array($sourceFile, $includedFiles) && ! $this->isTransient($className)) { + $classes[] = $className; + } + } + + $this->classNames = $classes; + + return $classes; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/DefaultFileLocator.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/DefaultFileLocator.php new file mode 100644 index 0000000..0d61174 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/DefaultFileLocator.php @@ -0,0 +1,170 @@ +. +*/ + +namespace Doctrine\Common\Persistence\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\MappingException; + +/** + * Locate the file that contains the metadata information for a given class name. + * + * This behavior is inpependent of the actual content of the file. It just detects + * the file which is responsible for the given class name. + * + * @author Benjamin Eberlei + * @author Johannes M. Schmitt + */ +class DefaultFileLocator implements FileLocator +{ + /** + * The paths where to look for mapping files. + * + * @var array + */ + protected $paths = array(); + + /** + * The file extension of mapping documents. + * + * @var string + */ + protected $fileExtension; + + /** + * Initializes a new FileDriver that looks in the given path(s) for mapping + * documents and operates in the specified operating mode. + * + * @param string|array $paths One or multiple paths where mapping documents can be found. + * @param string|null $fileExtension + */ + public function __construct($paths, $fileExtension = null) + { + $this->addPaths((array) $paths); + $this->fileExtension = $fileExtension; + } + + /** + * Append lookup paths to metadata driver. + * + * @param array $paths + */ + public function addPaths(array $paths) + { + $this->paths = array_unique(array_merge($this->paths, $paths)); + } + + /** + * Retrieve the defined metadata lookup paths. + * + * @return array + */ + public function getPaths() + { + return $this->paths; + } + + /** + * Get the file extension used to look for mapping files under + * + * @return string + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Set the file extension used to look for mapping files under + * + * @param string $fileExtension The file extension to set + * @return void + */ + public function setFileExtension($fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * {@inheritDoc} + */ + public function findMappingFile($className) + { + $fileName = str_replace('\\', '.', $className) . $this->fileExtension; + + // Check whether file exists + foreach ($this->paths as $path) { + if (file_exists($path . DIRECTORY_SEPARATOR . $fileName)) { + return $path . DIRECTORY_SEPARATOR . $fileName; + } + } + + throw MappingException::mappingFileNotFound($className, $fileName); + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames($globalBasename) + { + $classes = array(); + + if ($this->paths) { + foreach ($this->paths as $path) { + if ( ! is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($path), + \RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + $fileName = $file->getBasename($this->fileExtension); + + if ($fileName == $file->getBasename() || $fileName == $globalBasename) { + continue; + } + + // NOTE: All files found here means classes are not transient! + $classes[] = str_replace('.', '\\', $fileName); + } + } + } + + return $classes; + } + + /** + * {@inheritDoc} + */ + public function fileExists($className) + { + $fileName = str_replace('\\', '.', $className) . $this->fileExtension; + + // Check whether file exists + foreach ((array) $this->paths as $path) { + if (file_exists($path . DIRECTORY_SEPARATOR . $fileName)) { + return true; + } + } + + return false; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileDriver.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileDriver.php new file mode 100644 index 0000000..b0a7685 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileDriver.php @@ -0,0 +1,214 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\MappingException; + +/** + * Base driver for file-based metadata drivers. + * + * A file driver operates in a mode where it loads the mapping files of individual + * classes on demand. This requires the user to adhere to the convention of 1 mapping + * file per class and the file names of the mapping files must correspond to the full + * class name, including namespace, with the namespace delimiters '\', replaced by dots '.'. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel + */ +abstract class FileDriver implements MappingDriver +{ + /** + * @var FileLocator + */ + protected $locator; + + /** + * @var array + */ + protected $classCache; + + /** + * @var string + */ + protected $globalBasename; + + /** + * Initializes a new FileDriver that looks in the given path(s) for mapping + * documents and operates in the specified operating mode. + * + * @param string|array|FileLocator $locator A FileLocator or one/multiple paths where mapping documents can be found. + * @param string $fileExtension + */ + public function __construct($locator, $fileExtension = null) + { + if ($locator instanceof FileLocator) { + $this->locator = $locator; + } else { + $this->locator = new DefaultFileLocator((array)$locator, $fileExtension); + } + } + + /** + * Set global basename + * + * @param string $file + */ + public function setGlobalBasename($file) + { + $this->globalBasename = $file; + } + + /** + * Retrieve global basename + * + * @return string + */ + public function getGlobalBasename() + { + return $this->globalBasename; + } + + /** + * Get the element of schema meta data for the class from the mapping file. + * This will lazily load the mapping file if it is not loaded yet + * + * @param string $className + * + * @throws MappingException + * @return array The element of schema meta data + */ + public function getElement($className) + { + if ($this->classCache === null) { + $this->initialize(); + } + + if (isset($this->classCache[$className])) { + return $this->classCache[$className]; + } + + $result = $this->loadMappingFile($this->locator->findMappingFile($className)); + if (!isset($result[$className])) { + throw MappingException::invalidMappingFile($className, str_replace('\\', '.', $className) . $this->locator->getFileExtension()); + } + + return $result[$className]; + } + + /** + * Whether the class with the specified name should have its metadata loaded. + * This is only the case if it is either mapped as an Entity or a + * MappedSuperclass. + * + * @param string $className + * @return boolean + */ + public function isTransient($className) + { + if ($this->classCache === null) { + $this->initialize(); + } + + if (isset($this->classCache[$className])) { + return false; + } + + return !$this->locator->fileExists($className); + } + + /** + * Gets the names of all mapped classes known to this driver. + * + * @return array The names of all mapped classes known to this driver. + */ + public function getAllClassNames() + { + if ($this->classCache === null) { + $this->initialize(); + } + + $classNames = (array)$this->locator->getAllClassNames($this->globalBasename); + if ($this->classCache) { + $classNames = array_merge(array_keys($this->classCache), $classNames); + } + return $classNames; + } + + /** + * Loads a mapping file with the given name and returns a map + * from class/entity names to their corresponding file driver elements. + * + * @param string $file The mapping file to load. + * @return array + */ + abstract protected function loadMappingFile($file); + + /** + * Initialize the class cache from all the global files. + * + * Using this feature adds a substantial performance hit to file drivers as + * more metadata has to be loaded into memory than might actually be + * necessary. This may not be relevant to scenarios where caching of + * metadata is in place, however hits very hard in scenarios where no + * caching is used. + * + * @return void + */ + protected function initialize() + { + $this->classCache = array(); + if (null !== $this->globalBasename) { + foreach ($this->locator->getPaths() as $path) { + $file = $path.'/'.$this->globalBasename.$this->locator->getFileExtension(); + if (is_file($file)) { + $this->classCache = array_merge( + $this->classCache, + $this->loadMappingFile($file) + ); + } + } + } + } + + /** + * Retrieve the locator used to discover mapping files by className + * + * @return FileLocator + */ + public function getLocator() + { + return $this->locator; + } + + /** + * Set the locator used to discover mapping files by className + * + * @param FileLocator $locator + */ + public function setLocator(FileLocator $locator) + { + $this->locator = $locator; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileLocator.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileLocator.php new file mode 100644 index 0000000..ec2b606 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileLocator.php @@ -0,0 +1,71 @@ +. +*/ + +namespace Doctrine\Common\Persistence\Mapping\Driver; + +/** + * Locate the file that contains the metadata information for a given class name. + * + * This behavior is independent of the actual content of the file. It just detects + * the file which is responsible for the given class name. + * + * @author Benjamin Eberlei + * @author Johannes M. Schmitt + */ +interface FileLocator +{ + /** + * Locate mapping file for the given class name. + * + * @param string $className + * @return string + */ + function findMappingFile($className); + + /** + * Get all class names that are found with this file locator. + * + * @param string $globalBasename Passed to allow excluding the basename + * @return array + */ + function getAllClassNames($globalBasename); + + /** + * Check if a file can be found for this class name. + * + * @param string $className + * + * @return bool + */ + function fileExists($className); + + /** + * Get all the paths that this file locator looks for mapping files. + * + * @return array + */ + function getPaths(); + + /** + * Get the file extension that mapping files are suffixed with. + * + * @return string + */ + function getFileExtension(); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriver.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriver.php new file mode 100644 index 0000000..955d831 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriver.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\ClassMetadata; + +/** + * Contract for metadata drivers. + * + * @since 2.2 + * @author Jonathan H. Wage + */ +interface MappingDriver +{ + /** + * Loads the metadata for the specified class into the provided container. + * + * @param string $className + * @param ClassMetadata $metadata + */ + function loadMetadataForClass($className, ClassMetadata $metadata); + + /** + * Gets the names of all mapped classes known to this driver. + * + * @return array The names of all mapped classes known to this driver. + */ + function getAllClassNames(); + + /** + * Whether the class with the specified name should have its metadata loaded. + * This is only the case if it is either mapped as an Entity or a + * MappedSuperclass. + * + * @param string $className + * @return boolean + */ + function isTransient($className); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriverChain.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriverChain.php new file mode 100644 index 0000000..3b1049d --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriverChain.php @@ -0,0 +1,168 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver, + Doctrine\Common\Persistence\Mapping\ClassMetadata, + Doctrine\Common\Persistence\Mapping\MappingException; + +/** + * The DriverChain allows you to add multiple other mapping drivers for + * certain namespaces + * + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel + */ +class MappingDriverChain implements MappingDriver +{ + /** + * The default driver + * + * @var MappingDriver + */ + private $defaultDriver; + + /** + * @var array + */ + private $drivers = array(); + + /** + * Get the default driver. + * + * @return MappingDriver|null + */ + public function getDefaultDriver() + { + return $this->defaultDriver; + } + + /** + * Set the default driver. + * + * @param MappingDriver $driver + */ + public function setDefaultDriver(MappingDriver $driver) + { + $this->defaultDriver = $driver; + } + + /** + * Add a nested driver. + * + * @param MappingDriver $nestedDriver + * @param string $namespace + */ + public function addDriver(MappingDriver $nestedDriver, $namespace) + { + $this->drivers[$namespace] = $nestedDriver; + } + + /** + * Get the array of nested drivers. + * + * @return array $drivers + */ + public function getDrivers() + { + return $this->drivers; + } + + /** + * Loads the metadata for the specified class into the provided container. + * + * @param string $className + * @param ClassMetadata $metadata + * + * @throws MappingException + */ + public function loadMetadataForClass($className, ClassMetadata $metadata) + { + /* @var $driver MappingDriver */ + foreach ($this->drivers as $namespace => $driver) { + if (strpos($className, $namespace) === 0) { + $driver->loadMetadataForClass($className, $metadata); + return; + } + } + + if (null !== $this->defaultDriver) { + $this->defaultDriver->loadMetadataForClass($className, $metadata); + return; + } + + throw MappingException::classNotFoundInNamespaces($className, array_keys($this->drivers)); + } + + /** + * Gets the names of all mapped classes known to this driver. + * + * @return array The names of all mapped classes known to this driver. + */ + public function getAllClassNames() + { + $classNames = array(); + $driverClasses = array(); + + /* @var $driver MappingDriver */ + foreach ($this->drivers AS $namespace => $driver) { + $oid = spl_object_hash($driver); + + if (!isset($driverClasses[$oid])) { + $driverClasses[$oid] = $driver->getAllClassNames(); + } + + foreach ($driverClasses[$oid] AS $className) { + if (strpos($className, $namespace) === 0) { + $classNames[$className] = true; + } + } + } + + return array_keys($classNames); + } + + /** + * Whether the class with the specified name should have its metadata loaded. + * + * This is only the case for non-transient classes either mapped as an Entity or MappedSuperclass. + * + * @param string $className + * @return boolean + */ + public function isTransient($className) + { + /* @var $driver MappingDriver */ + foreach ($this->drivers AS $namespace => $driver) { + if (strpos($className, $namespace) === 0) { + return $driver->isTransient($className); + } + } + + if ($this->defaultDriver !== null) { + return $this->defaultDriver->isTransient($className); + } + + return true; + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/PHPDriver.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/PHPDriver.php new file mode 100644 index 0000000..e0c8611 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/PHPDriver.php @@ -0,0 +1,72 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\ClassMetadata; + +/** + * The PHPDriver includes php files which just populate ClassMetadataInfo + * instances with plain php code + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel + */ +class PHPDriver extends FileDriver +{ + /** + * {@inheritdoc} + */ + protected $metadata; + + /** + * {@inheritDoc} + */ + public function __construct($locator, $fileExtension = null) + { + $fileExtension = ".php"; + parent::__construct($locator, $fileExtension); + } + + /** + * {@inheritdoc} + */ + public function loadMetadataForClass($className, ClassMetadata $metadata) + { + $this->metadata = $metadata; + $this->loadMappingFile($this->locator->findMappingFile($className)); + } + + /** + * {@inheritdoc} + */ + protected function loadMappingFile($file) + { + $metadata = $this->metadata; + include $file; + + return array($metadata->getName() => $metadata); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/StaticPHPDriver.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/StaticPHPDriver.php new file mode 100644 index 0000000..e3cea73 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/StaticPHPDriver.php @@ -0,0 +1,141 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\Common\Persistence\Mapping\MappingException; + +/** + * The StaticPHPDriver calls a static loadMetadata() method on your entity + * classes where you can manually populate the ClassMetadata instance. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel + */ +class StaticPHPDriver implements MappingDriver +{ + /** + * Paths of entity directories. + * + * @var array + */ + private $paths = array(); + + /** + * Map of all class names. + * + * @var array + */ + private $classNames; + + /** + * Constructor + * + * @param array|string $paths + */ + public function __construct($paths) + { + $this->addPaths((array) $paths); + } + + /** + * Add paths + * + * @param array $paths + */ + public function addPaths(array $paths) + { + $this->paths = array_unique(array_merge($this->paths, $paths)); + } + + /** + * {@inheritdoc} + */ + public function loadMetadataForClass($className, ClassMetadata $metadata) + { + $className::loadMetadata($metadata); + } + + /** + * {@inheritDoc} + * @todo Same code exists in AnnotationDriver, should we re-use it somehow or not worry about it? + */ + public function getAllClassNames() + { + if ($this->classNames !== null) { + return $this->classNames; + } + + if (!$this->paths) { + throw MappingException::pathRequired(); + } + + $classes = array(); + $includedFiles = array(); + + foreach ($this->paths as $path) { + if (!is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($path), + \RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + if ($file->getBasename('.php') == $file->getBasename()) { + continue; + } + + $sourceFile = realpath($file->getPathName()); + require_once $sourceFile; + $includedFiles[] = $sourceFile; + } + } + + $declared = get_declared_classes(); + + foreach ($declared as $className) { + $rc = new \ReflectionClass($className); + $sourceFile = $rc->getFileName(); + if (in_array($sourceFile, $includedFiles) && !$this->isTransient($className)) { + $classes[] = $className; + } + } + + $this->classNames = $classes; + + return $classes; + } + + /** + * {@inheritdoc} + */ + public function isTransient($className) + { + return ! method_exists($className, 'loadMetadata'); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/SymfonyFileLocator.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/SymfonyFileLocator.php new file mode 100644 index 0000000..9095187 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/SymfonyFileLocator.php @@ -0,0 +1,214 @@ +. +*/ + +namespace Doctrine\Common\Persistence\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\MappingException; + +/** + * The Symfony File Locator makes a simplifying assumptions compared + * to the DefaultFileLocator. By assuming paths only contain entities of a certain + * namespace the mapping files consists of the short classname only. + * + * @author Fabien Potencier + * @author Benjamin Eberlei + * @license MIT + */ +class SymfonyFileLocator implements FileLocator +{ + /** + * The paths where to look for mapping files. + * + * @var array + */ + protected $paths = array(); + + /** + * A map of mapping directory path to namespace prefix used to expand class shortnames. + * + * @var array + */ + protected $prefixes = array(); + + /** + * File extension that is searched for. + * + * @var string + */ + protected $fileExtension; + + /** + * Constructor + * + * @param array $prefixes + * @param string|null $fileExtension + */ + public function __construct(array $prefixes, $fileExtension = null) + { + $this->addNamespacePrefixes($prefixes); + $this->fileExtension = $fileExtension; + } + + /** + * Add Namespace Prefixes + * + * @param array $prefixes + */ + public function addNamespacePrefixes(array $prefixes) + { + $this->prefixes = array_merge($this->prefixes, $prefixes); + $this->paths = array_merge($this->paths, array_keys($prefixes)); + } + + /** + * Get Namespace Prefixes + * + * @return array + */ + public function getNamespacePrefixes() + { + return $this->prefixes; + } + + /** + * {@inheritDoc} + */ + public function getPaths() + { + return $this->paths; + } + + /** + * {@inheritDoc} + */ + public function getFileExtension() + { + return $this->fileExtension; + } + + /** + * Set the file extension used to look for mapping files under + * + * @param string $fileExtension The file extension to set + * @return void + */ + public function setFileExtension($fileExtension) + { + $this->fileExtension = $fileExtension; + } + + /** + * {@inheritDoc} + */ + public function fileExists($className) + { + $defaultFileName = str_replace('\\', '.', $className).$this->fileExtension; + foreach ($this->paths as $path) { + if (!isset($this->prefixes[$path])) { + // global namespace class + if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) { + return true; + } + + continue; + } + + $prefix = $this->prefixes[$path]; + + if (0 !== strpos($className, $prefix.'\\')) { + continue; + } + + $filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->fileExtension; + return is_file($filename); + } + + return false; + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames($globalBasename = null) + { + $classes = array(); + + if ($this->paths) { + foreach ((array) $this->paths as $path) { + if (!is_dir($path)) { + throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); + } + + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($path), + \RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + $fileName = $file->getBasename($this->fileExtension); + + if ($fileName == $file->getBasename() || $fileName == $globalBasename) { + continue; + } + + // NOTE: All files found here means classes are not transient! + if (isset($this->prefixes[$path])) { + $classes[] = $this->prefixes[$path].'\\'.str_replace('.', '\\', $fileName); + } else { + $classes[] = str_replace('.', '\\', $fileName); + } + } + } + } + + return $classes; + } + + /** + * {@inheritDoc} + */ + public function findMappingFile($className) + { + $defaultFileName = str_replace('\\', '.', $className).$this->fileExtension; + foreach ($this->paths as $path) { + if (!isset($this->prefixes[$path])) { + if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) { + return $path.DIRECTORY_SEPARATOR.$defaultFileName; + } + + continue; + } + + $prefix = $this->prefixes[$path]; + + if (0 !== strpos($className, $prefix.'\\')) { + continue; + } + + $filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->fileExtension; + if (is_file($filename)) { + return $filename; + } + + throw MappingException::mappingFileNotFound($className, $filename); + } + + throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->fileExtension); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/MappingException.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/MappingException.php new file mode 100644 index 0000000..c1e7ad5 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/MappingException.php @@ -0,0 +1,86 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping; + +/** + * A MappingException indicates that something is wrong with the mapping setup. + * + * @since 2.2 + */ +class MappingException extends \Exception +{ + /** + * + * @param string $className + * @param array $namespaces + * + * @return MappingException + */ + public static function classNotFoundInNamespaces($className, $namespaces) + { + return new self("The class '" . $className . "' was not found in the ". + "chain configured namespaces " . implode(", ", $namespaces)); + } + + /** + * @return MappingException + */ + public static function pathRequired() + { + return new self("Specifying the paths to your entities is required ". + "in the AnnotationDriver to retrieve all class names."); + } + + /** + * @param string|null $path + * @return MappingException + */ + public static function fileMappingDriversRequireConfiguredDirectoryPath($path = null) + { + if ( ! empty($path)) { + $path = '[' . $path . ']'; + } + + return new self( + 'File mapping drivers must have a valid directory path, ' . + 'however the given path ' . $path . ' seems to be incorrect!' + ); + } + + /** + * @param string $entityName + * @param string $fileName + * @return MappingException + */ + public static function mappingFileNotFound($entityName, $fileName) + { + return new self("No mapping file found named '$fileName' for class '$entityName'."); + } + + /** + * @param string $entityName + * @param string $fileName + * @return MappingException + */ + public static function invalidMappingFile($entityName, $fileName) + { + return new self("Invalid mapping file '$fileName' for class '$entityName'."); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ReflectionService.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ReflectionService.php new file mode 100644 index 0000000..3db85d9 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/ReflectionService.php @@ -0,0 +1,80 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping; + +/** + * Very simple reflection service abstraction. + * + * This is required inside metadata layers that may require either + * static or runtime reflection. + * + * @author Benjamin Eberlei + */ +interface ReflectionService +{ + /** + * Return an array of the parent classes (not interfaces) for the given class. + * + * @param string $class + * @return array + */ + function getParentClasses($class); + + /** + * Return the shortname of a class. + * + * @param string $class + * @return string + */ + function getClassShortName($class); + + /** + * @param string $class + * @return string + */ + function getClassNamespace($class); + + /** + * Return a reflection class instance or null + * + * @param string $class + * @return \ReflectionClass|null + */ + function getClass($class); + + /** + * Return an accessible property (setAccessible(true)) or null. + * + * @param string $class + * @param string $property + * @return \ReflectionProperty|null + */ + function getAccessibleProperty($class, $property); + + /** + * Check if the class have a public method with the given name. + * + * @param mixed $class + * @param mixed $method + * @return bool + */ + function hasPublicMethod($class, $method); +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php new file mode 100644 index 0000000..77b9e76 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php @@ -0,0 +1,102 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping; + +use ReflectionClass; +use ReflectionProperty; + +/** + * PHP Runtime Reflection Service + * + * @author Benjamin Eberlei + */ +class RuntimeReflectionService implements ReflectionService +{ + /** + * Return an array of the parent classes (not interfaces) for the given class. + * + * @param string $class + * @return array + */ + public function getParentClasses($class) + { + return class_parents($class); + } + + /** + * Return the shortname of a class. + * + * @param string $class + * @return string + */ + public function getClassShortName($class) + { + $r = new ReflectionClass($class); + return $r->getShortName(); + } + + /** + * @param string $class + * @return string + */ + public function getClassNamespace($class) + { + $r = new ReflectionClass($class); + return $r->getNamespaceName(); + } + + /** + * Return a reflection class instance or null + * + * @param string $class + * @return ReflectionClass|null + */ + public function getClass($class) + { + return new ReflectionClass($class); + } + + /** + * Return an accessible property (setAccessible(true)) or null. + * + * @param string $class + * @param string $property + * @return ReflectionProperty|null + */ + public function getAccessibleProperty($class, $property) + { + $property = new ReflectionProperty($class, $property); + $property->setAccessible(true); + return $property; + } + + /** + * Check if the class have a public method with the given name. + * + * @param mixed $class + * @param mixed $method + * @return bool + */ + public function hasPublicMethod($class, $method) + { + return method_exists($class, $method) && is_callable(array($class, $method)); + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/StaticReflectionService.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/StaticReflectionService.php new file mode 100644 index 0000000..4f6d1cf --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/StaticReflectionService.php @@ -0,0 +1,107 @@ +. + */ + +namespace Doctrine\Common\Persistence\Mapping; + +use ReflectionClass; +use ReflectionProperty; + +/** + * PHP Runtime Reflection Service + * + * @author Benjamin Eberlei + */ +class StaticReflectionService implements ReflectionService +{ + /** + * Return an array of the parent classes (not interfaces) for the given class. + * + * @param string $class + * @return array + */ + public function getParentClasses($class) + { + return array(); + } + + /** + * Return the shortname of a class. + * + * @param string $className + * @return string + */ + public function getClassShortName($className) + { + if (strpos($className, '\\') !== false) { + $className = substr($className, strrpos($className, "\\")+1); + } + return $className; + } + + /** + * Return the namespace of a class. + * + * @param string $className + * @return string + */ + public function getClassNamespace($className) + { + $namespace = ''; + if (strpos($className, '\\') !== false) { + $namespace = strrev(substr( strrev($className), strpos(strrev($className), '\\')+1 )); + } + return $namespace; + } + + /** + * Return a reflection class instance or null + * + * @param string $class + * @return ReflectionClass|null + */ + public function getClass($class) + { + return null; + } + + /** + * Return an accessible property (setAccessible(true)) or null. + * + * @param string $class + * @param string $property + * @return ReflectionProperty|null + */ + public function getAccessibleProperty($class, $property) + { + return null; + } + + /** + * Check if the class have a public method with the given name. + * + * @param mixed $class + * @param mixed $method + * @return bool + */ + public function hasPublicMethod($class, $method) + { + return method_exists($class, $method) && is_callable(array($class, $method)); + } +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManager.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManager.php new file mode 100644 index 0000000..2bb8722 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManager.php @@ -0,0 +1,152 @@ +. + */ + +namespace Doctrine\Common\Persistence; + +/** + * Contract for a Doctrine persistence layer ObjectManager class to implement. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.1 + * @author Benjamin Eberlei + * @author Jonathan Wage + */ +interface ObjectManager +{ + /** + * Finds a object by its identifier. + * + * This is just a convenient shortcut for getRepository($className)->find($id). + * + * @param string + * @param mixed + * @return object + */ + function find($className, $id); + + /** + * Tells the ObjectManager to make an instance managed and persistent. + * + * The object will be entered into the database as a result of the flush operation. + * + * NOTE: The persist operation always considers objects that are not yet known to + * this ObjectManager as NEW. Do not pass detached objects to the persist operation. + * + * @param object $object The instance to make managed and persistent. + */ + function persist($object); + + /** + * Removes an object instance. + * + * A removed object will be removed from the database as a result of the flush operation. + * + * @param object $object The object instance to remove. + */ + function remove($object); + + /** + * Merges the state of a detached object into the persistence context + * of this ObjectManager and returns the managed copy of the object. + * The object passed to merge will not become associated/managed with this ObjectManager. + * + * @param object $object + * @return object + */ + function merge($object); + + /** + * Clears the ObjectManager. All objects that are currently managed + * by this ObjectManager become detached. + * + * @param string $objectName if given, only objects of this type will get detached + */ + function clear($objectName = null); + + /** + * Detaches an object from the ObjectManager, causing a managed object to + * become detached. Unflushed changes made to the object if any + * (including removal of the object), will not be synchronized to the database. + * Objects which previously referenced the detached object will continue to + * reference it. + * + * @param object $object The object to detach. + */ + function detach($object); + + /** + * Refreshes the persistent state of an object from the database, + * overriding any local changes that have not yet been persisted. + * + * @param object $object The object to refresh. + */ + function refresh($object); + + /** + * Flushes all changes to objects that have been queued up to now to the database. + * This effectively synchronizes the in-memory state of managed objects with the + * database. + */ + function flush(); + + /** + * Gets the repository for a class. + * + * @param string $className + * @return \Doctrine\Common\Persistence\ObjectRepository + */ + function getRepository($className); + + /** + * Returns the ClassMetadata descriptor for a class. + * + * The class name must be the fully-qualified class name without a leading backslash + * (as it is returned by get_class($obj)). + * + * @param string $className + * @return \Doctrine\Common\Persistence\Mapping\ClassMetadata + */ + function getClassMetadata($className); + + /** + * Gets the metadata factory used to gather the metadata of classes. + * + * @return \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory + */ + function getMetadataFactory(); + + /** + * Helper method to initialize a lazy loading proxy or persistent collection. + * + * This method is a no-op for other objects. + * + * @param object $obj + */ + function initializeObject($obj); + + /** + * Check if the object is part of the current UnitOfWork and therefore + * managed. + * + * @param object $object + * @return bool + */ + function contains($object); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManagerAware.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManagerAware.php new file mode 100644 index 0000000..69fba78 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManagerAware.php @@ -0,0 +1,49 @@ +. + */ + +namespace Doctrine\Common\Persistence; + +use Doctrine\Common\Persistence\Mapping\ClassMetadata; + +/** + * Makes a Persistent Objects aware of its own object-manager. + * + * Using this interface the managing object manager and class metadata instances + * are injected into the persistent object after construction. This allows + * you to implement ActiveRecord functionality on top of the persistance-ignorance + * that Doctrine propagates. + * + * Word of Warning: This is a very powerful hook to change how you can work with your domain models. + * Using this hook will break the Single Responsibility Principle inside your Domain Objects + * and increase the coupling of database and objects. + * + * Every ObjectManager has to implement this functionality itself. + * + * @author Benjamin Eberlei + */ +interface ObjectManagerAware +{ + /** + * Injects responsible ObjectManager and the ClassMetadata into this persistent object. + * + * @param ObjectManager $objectManager + * @param ClassMetadata $classMetadata + */ + public function injectObjectManager(ObjectManager $objectManager, ClassMetadata $classMetadata); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectRepository.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectRepository.php new file mode 100644 index 0000000..9a3e5b6 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectRepository.php @@ -0,0 +1,78 @@ +. + */ + +namespace Doctrine\Common\Persistence; + +/** + * Contract for a Doctrine persistence layer ObjectRepository class to implement. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.1 + * @author Benjamin Eberlei + * @author Jonathan Wage + */ +interface ObjectRepository +{ + /** + * Finds an object by its primary key / identifier. + * + * @param int $id The identifier. + * @return object The object. + */ + function find($id); + + /** + * Finds all objects in the repository. + * + * @return mixed The objects. + */ + function findAll(); + + /** + * Finds objects by a set of criteria. + * + * Optionally sorting and limiting details can be passed. An implementation may throw + * an UnexpectedValueException if certain values of the sorting or limiting details are + * not supported. + * + * @throws \UnexpectedValueException + * @param array $criteria + * @param array|null $orderBy + * @param int|null $limit + * @param int|null $offset + * @return mixed The objects. + */ + function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null); + + /** + * Finds a single object by a set of criteria. + * + * @param array $criteria + * @return object The object. + */ + function findOneBy(array $criteria); + + /** + * Returns the class name of the object managed by the repository + * + * @return string + */ + function getClassName(); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/PersistentObject.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/PersistentObject.php new file mode 100644 index 0000000..9fcc4cb --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/PersistentObject.php @@ -0,0 +1,244 @@ +. + */ + +namespace Doctrine\Common\Persistence; + +use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; + +/** + * PersistentObject base class that implements getter/setter methods for all mapped fields and associations + * by overriding __call. + * + * This class is a forward compatible implementation of the PersistentObject trait. + * + * + * Limitations: + * + * 1. All persistent objects have to be associated with a single ObjectManager, multiple + * ObjectManagers are not supported. You can set the ObjectManager with `PersistentObject#setObjectManager()`. + * 2. Setters and getters only work if a ClassMetadata instance was injected into the PersistentObject. + * This is either done on `postLoad` of an object or by accessing the global object manager. + * 3. There are no hooks for setters/getters. Just implement the method yourself instead of relying on __call(). + * 4. Slower than handcoded implementations: An average of 7 method calls per access to a field and 11 for an association. + * 5. Only the inverse side associations get autoset on the owning side aswell. Setting objects on the owning side + * will not set the inverse side associations. + * + * @example + * + * PersistentObject::setObjectManager($em); + * + * class Foo extends PersistentObject + * { + * private $id; + * } + * + * $foo = new Foo(); + * $foo->getId(); // method exists through __call + * + * @author Benjamin Eberlei + */ +abstract class PersistentObject implements ObjectManagerAware +{ + /** + * @var ObjectManager + */ + private static $objectManager; + + /** + * @var ClassMetadata + */ + private $cm; + + /** + * Set the object manager responsible for all persistent object base classes. + * + * @param ObjectManager $objectManager + */ + static public function setObjectManager(ObjectManager $objectManager = null) + { + self::$objectManager = $objectManager; + } + + /** + * @return ObjectManager + */ + static public function getObjectManager() + { + return self::$objectManager; + } + + /** + * Inject Doctrine Object Manager + * + * @param ObjectManager $objectManager + * @param ClassMetadata $classMetadata + * + * @throws \RuntimeException + */ + public function injectObjectManager(ObjectManager $objectManager, ClassMetadata $classMetadata) + { + if ($objectManager !== self::$objectManager) { + throw new \RuntimeException("Trying to use PersistentObject with different ObjectManager instances. " . + "Was PersistentObject::setObjectManager() called?"); + } + + $this->cm = $classMetadata; + } + + /** + * Sets a persistent fields value. + * + * @param string $field + * @param array $args + * + * @throws \BadMethodCallException - When no persistent field exists by that name. + * @throws \InvalidArgumentException - When the wrong target object type is passed to an association + * @return void + */ + private function set($field, $args) + { + $this->initializeDoctrine(); + + if ($this->cm->hasField($field) && !$this->cm->isIdentifier($field)) { + $this->$field = $args[0]; + } else if ($this->cm->hasAssociation($field) && $this->cm->isSingleValuedAssociation($field)) { + $targetClass = $this->cm->getAssociationTargetClass($field); + if (!($args[0] instanceof $targetClass) && $args[0] !== null) { + throw new \InvalidArgumentException("Expected persistent object of type '".$targetClass."'"); + } + $this->$field = $args[0]; + $this->completeOwningSide($field, $targetClass, $args[0]); + } else { + throw new \BadMethodCallException("no field with name '".$field."' exists on '".$this->cm->getName()."'"); + } + } + + /** + * Get persistent field value. + * + * + * @param string $field + * + * @throws \BadMethodCallException - When no persistent field exists by that name. + * @return mixed + */ + private function get($field) + { + $this->initializeDoctrine(); + + if ( $this->cm->hasField($field) || $this->cm->hasAssociation($field) ) { + return $this->$field; + } else { + throw new \BadMethodCallException("no field with name '".$field."' exists on '".$this->cm->getName()."'"); + } + } + + /** + * If this is an inverse side association complete the owning side. + * + * @param string $field + * @param ClassMetadata $targetClass + * @param object $targetObject + */ + private function completeOwningSide($field, $targetClass, $targetObject) + { + // add this object on the owning side aswell, for obvious infinite recursion + // reasons this is only done when called on the inverse side. + if ($this->cm->isAssociationInverseSide($field)) { + $mappedByField = $this->cm->getAssociationMappedByTargetField($field); + $targetMetadata = self::$objectManager->getClassMetadata($targetClass); + + $setter = ($targetMetadata->isCollectionValuedAssociation($mappedByField) ? "add" : "set").$mappedByField; + $targetObject->$setter($this); + } + } + + /** + * Add an object to a collection + * + * @param string $field + * @param array $args + * + * @throws \BadMethodCallException + * @throws \InvalidArgumentException + */ + private function add($field, $args) + { + $this->initializeDoctrine(); + + if ($this->cm->hasAssociation($field) && $this->cm->isCollectionValuedAssociation($field)) { + $targetClass = $this->cm->getAssociationTargetClass($field); + if (!($args[0] instanceof $targetClass)) { + throw new \InvalidArgumentException("Expected persistent object of type '".$targetClass."'"); + } + if (!($this->$field instanceof Collection)) { + $this->$field = new ArrayCollection($this->$field ?: array()); + } + $this->$field->add($args[0]); + $this->completeOwningSide($field, $targetClass, $args[0]); + } else { + throw new \BadMethodCallException("There is no method add".$field."() on ".$this->cm->getName()); + } + } + + /** + * Initialize Doctrine Metadata for this class. + * + * @throws \RuntimeException + * @return void + */ + private function initializeDoctrine() + { + if ($this->cm !== null) { + return; + } + + if (!self::$objectManager) { + throw new \RuntimeException("No runtime object manager set. Call PersistentObject#setObjectManager()."); + } + + $this->cm = self::$objectManager->getClassMetadata(get_class($this)); + } + + /** + * Magic method that implements + * + * @param string $method + * @param array $args + * + * @throws \BadMethodCallException + * @return mixed + */ + public function __call($method, $args) + { + $command = substr($method, 0, 3); + $field = lcfirst(substr($method, 3)); + if ($command == "set") { + $this->set($field, $args); + } else if ($command == "get") { + return $this->get($field); + } else if ($command == "add") { + $this->add($field, $args); + } else { + throw new \BadMethodCallException("There is no method ".$method." on ".$this->cm->getName()); + } + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Proxy.php b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Proxy.php new file mode 100644 index 0000000..e25598c --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Proxy.php @@ -0,0 +1,60 @@ +. + */ + +namespace Doctrine\Common\Persistence; + +/** + * Interface for proxy classes. + * + * @author Roman Borschel + * @since 2.2 + */ +interface Proxy +{ + /** + * Marker for Proxy class names. + * + * @var string + */ + const MARKER = '__CG__'; + + /** + * Length of the proxy marker + * + * @var int + */ + const MARKER_LENGTH = 6; + + /** + * Initialize this proxy if its not yet initialized. + * + * Acts as a no-op if already initialized. + * + * @return void + */ + public function __load(); + + /** + * Is this proxy initialized or not. + * + * @return bool + */ + public function __isInitialized(); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/PropertyChangedListener.php b/vendor/doctrine/common/lib/Doctrine/Common/PropertyChangedListener.php new file mode 100644 index 0000000..1171874 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/PropertyChangedListener.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\Common; + +/** + * Contract for classes that are potential listeners of a NotifyPropertyChanged + * implementor. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 3938 $ + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +interface PropertyChangedListener +{ + /** + * Notifies the listener of a property change. + * + * @param object $sender The object on which the property changed. + * @param string $propertyName The name of the property that changed. + * @param mixed $oldValue The old value of the property that changed. + * @param mixed $newValue The new value of the property that changed. + */ + function propertyChanged($sender, $propertyName, $oldValue, $newValue); +} + diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ClassFinderInterface.php b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ClassFinderInterface.php new file mode 100644 index 0000000..ae69607 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ClassFinderInterface.php @@ -0,0 +1,38 @@ +. + */ + +namespace Doctrine\Common\Reflection; + +/** + * Finds a class in a PSR-0 structure. + * + * @author Karoly Negyesi + */ +interface ClassFinderInterface +{ + /** + * Finds a class. + * + * @param string $class The name of the class. + * + * @return + * The name of the class or NULL if not found. + */ + public function findFile($class); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Reflection/Psr0FindFile.php b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/Psr0FindFile.php new file mode 100644 index 0000000..b6a5fd1 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/Psr0FindFile.php @@ -0,0 +1,83 @@ +. + */ + +namespace Doctrine\Common\Reflection; + +/** + * Finds a class in a PSR-0 structure. + * + * @author Karoly Negyesi + */ +class Psr0FindFile implements ClassFinderInterface +{ + /** + * The PSR-0 prefixes. + * + * @var string + */ + protected $prefixes; + + /** + * @param string $prefixes + * An array of prefixes. Each key is a PHP namespace and each value is + * a list of directories. + */ + public function __construct($prefixes) + { + $this->prefixes = $prefixes; + } + + /** + * Finds a class. + * + * @param string $class The name of the class. + * + * @return + * The name of the class or NULL if not found. + */ + public function findFile($class) + { + $lastNsPos = strrpos($class, '\\'); + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + if (false !== $lastNsPos) { + // namespaced class name + $classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $lastNsPos)) . DIRECTORY_SEPARATOR; + $className = substr($class, $lastNsPos + 1); + } else { + // PEAR-like class name + $classPath = null; + $className = $class; + } + + $classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; + + foreach ($this->prefixes as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { + return $dir . DIRECTORY_SEPARATOR . $classPath; + } + } + } + } + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ReflectionProviderInterface.php b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ReflectionProviderInterface.php new file mode 100644 index 0000000..a436a2d --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/ReflectionProviderInterface.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\Common\Reflection; + +interface ReflectionProviderInterface +{ + /** + * Get the ReflectionClass equivalent for this class. + * + * @return ReflectionClass + */ + public function getReflectionClass(); + + /** + * Get the ReflectionClass equivalent for this class. + * + * @return ReflectionMethod + */ + public function getReflectionMethod($name); + + /** + * Get the ReflectionClass equivalent for this class. + * + * @return ReflectionMethod + */ + public function getReflectionProperty($name); +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionClass.php b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionClass.php new file mode 100644 index 0000000..12e45d5 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionClass.php @@ -0,0 +1,112 @@ +. + */ + +namespace Doctrine\Common\Reflection; + +use ReflectionClass; +use ReflectionException; + +class StaticReflectionClass extends ReflectionClass +{ + /** + * The static reflection parser object. + * + * @var StaticReflectionParser + */ + private $staticReflectionParser; + + public function __construct(StaticReflectionParser $staticReflectionParser) + { + $this->staticReflectionParser = $staticReflectionParser; + } + + public function getName() + { + return $this->staticReflectionParser->getClassName(); + } + + public function getDocComment() + { + return $this->staticReflectionParser->getDocComment(); + } + + public function getNamespaceName() + { + return $this->staticReflectionParser->getNamespaceName(); + } + + public function getUseStatements() + { + return $this->staticReflectionParser->getUseStatements(); + } + + public function getMethod($name) + { + return $this->staticReflectionParser->getReflectionMethod($name); + } + + public function getProperty($name) + { + return $this->staticReflectionParser->getReflectionProperty($name); + } + + public static function export($argument, $return = false) { throw new ReflectionException('Method not implemented'); } + public function getConstant($name) { throw new ReflectionException('Method not implemented'); } + public function getConstants() { throw new ReflectionException('Method not implemented'); } + public function getConstructor() { throw new ReflectionException('Method not implemented'); } + public function getDefaultProperties() { throw new ReflectionException('Method not implemented'); } + public function getEndLine() { throw new ReflectionException('Method not implemented'); } + public function getExtension() { throw new ReflectionException('Method not implemented'); } + public function getExtensionName() { throw new ReflectionException('Method not implemented'); } + public function getFileName() { throw new ReflectionException('Method not implemented'); } + public function getInterfaceNames() { throw new ReflectionException('Method not implemented'); } + public function getInterfaces() { throw new ReflectionException('Method not implemented'); } + public function getMethods($filter = NULL) { throw new ReflectionException('Method not implemented'); } + public function getModifiers() { throw new ReflectionException('Method not implemented'); } + public function getParentClass() { throw new ReflectionException('Method not implemented'); } + public function getProperties($filter = NULL) { throw new ReflectionException('Method not implemented'); } + public function getShortName() { throw new ReflectionException('Method not implemented'); } + public function getStartLine() { throw new ReflectionException('Method not implemented'); } + public function getStaticProperties() { throw new ReflectionException('Method not implemented'); } + public function getStaticPropertyValue($name, $default = '') { throw new ReflectionException('Method not implemented'); } + public function getTraitAliases() { throw new ReflectionException('Method not implemented'); } + public function getTraitNames() { throw new ReflectionException('Method not implemented'); } + public function getTraits() { throw new ReflectionException('Method not implemented'); } + public function hasConstant($name) { throw new ReflectionException('Method not implemented'); } + public function hasMethod($name) { throw new ReflectionException('Method not implemented'); } + public function hasProperty($name) { throw new ReflectionException('Method not implemented'); } + public function implementsInterface($interface) { throw new ReflectionException('Method not implemented'); } + public function inNamespace() { throw new ReflectionException('Method not implemented'); } + public function isAbstract() { throw new ReflectionException('Method not implemented'); } + public function isCloneable() { throw new ReflectionException('Method not implemented'); } + public function isFinal() { throw new ReflectionException('Method not implemented'); } + public function isInstance($object) { throw new ReflectionException('Method not implemented'); } + public function isInstantiable() { throw new ReflectionException('Method not implemented'); } + public function isInterface() { throw new ReflectionException('Method not implemented'); } + public function isInternal() { throw new ReflectionException('Method not implemented'); } + public function isIterateable() { throw new ReflectionException('Method not implemented'); } + public function isSubclassOf($class) { throw new ReflectionException('Method not implemented'); } + public function isTrait() { throw new ReflectionException('Method not implemented'); } + public function isUserDefined() { throw new ReflectionException('Method not implemented'); } + public function newInstance($args) { throw new ReflectionException('Method not implemented'); } + public function newInstanceArgs(array $args = array()) { throw new ReflectionException('Method not implemented'); } + public function newInstanceWithoutConstructor() { throw new ReflectionException('Method not implemented'); } + public function setStaticPropertyValue($name, $value) { throw new ReflectionException('Method not implemented'); } + public function __toString() { throw new ReflectionException('Method not implemented'); } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionMethod.php b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionMethod.php new file mode 100644 index 0000000..6482036 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionMethod.php @@ -0,0 +1,103 @@ +. + */ + +namespace Doctrine\Common\Reflection; + +use ReflectionMethod; +use ReflectionException; + +class StaticReflectionMethod extends ReflectionMethod +{ + /** + * The PSR-0 parser object. + * + * @var StaticReflectionParser + */ + protected $staticReflectionParser; + + /** + * The name of the method. + * + * @var string + */ + protected $methodName; + + public function __construct(StaticReflectionParser $staticReflectionParser, $methodName) + { + $this->staticReflectionParser = $staticReflectionParser; + $this->methodName = $methodName; + } + public function getName() + { + return $this->methodName; + } + protected function getStaticReflectionParser() + { + return $this->staticReflectionParser->getStaticReflectionParserForDeclaringClass('method', $this->methodName); + } + public function getDeclaringClass() + { + return $this->getStaticReflectionParser()->getReflectionClass(); + } + public function getNamespaceName() + { + return $this->getStaticReflectionParser()->getNamespaceName(); + } + public function getDocComment() + { + return $this->getStaticReflectionParser()->getDocComment('method', $this->methodName); + } + public function getUseStatements() + { + return $this->getStaticReflectionParser()->getUseStatements(); + } + public static function export($class, $name, $return = false) { throw new ReflectionException('Method not implemented'); } + public function getClosure($object) { throw new ReflectionException('Method not implemented'); } + public function getModifiers() { throw new ReflectionException('Method not implemented'); } + public function getPrototype() { throw new ReflectionException('Method not implemented'); } + public function invoke($object, $parameter = NULL) { throw new ReflectionException('Method not implemented'); } + public function invokeArgs($object, array $args) { throw new ReflectionException('Method not implemented'); } + public function isAbstract() { throw new ReflectionException('Method not implemented'); } + public function isConstructor() { throw new ReflectionException('Method not implemented'); } + public function isDestructor() { throw new ReflectionException('Method not implemented'); } + public function isFinal() { throw new ReflectionException('Method not implemented'); } + public function isPrivate() { throw new ReflectionException('Method not implemented'); } + public function isProtected() { throw new ReflectionException('Method not implemented'); } + public function isPublic() { throw new ReflectionException('Method not implemented'); } + public function isStatic() { throw new ReflectionException('Method not implemented'); } + public function setAccessible($accessible) { throw new ReflectionException('Method not implemented'); } + public function __toString() { throw new ReflectionException('Method not implemented'); } + public function getClosureThis() { throw new ReflectionException('Method not implemented'); } + public function getEndLine() { throw new ReflectionException('Method not implemented'); } + public function getExtension() { throw new ReflectionException('Method not implemented'); } + public function getExtensionName() { throw new ReflectionException('Method not implemented'); } + public function getFileName() { throw new ReflectionException('Method not implemented'); } + public function getNumberOfParameters() { throw new ReflectionException('Method not implemented'); } + public function getNumberOfRequiredParameters() { throw new ReflectionException('Method not implemented'); } + public function getParameters() { throw new ReflectionException('Method not implemented'); } + public function getShortName() { throw new ReflectionException('Method not implemented'); } + public function getStartLine() { throw new ReflectionException('Method not implemented'); } + public function getStaticVariables() { throw new ReflectionException('Method not implemented'); } + public function inNamespace() { throw new ReflectionException('Method not implemented'); } + public function isClosure() { throw new ReflectionException('Method not implemented'); } + public function isDeprecated() { throw new ReflectionException('Method not implemented'); } + public function isInternal() { throw new ReflectionException('Method not implemented'); } + public function isUserDefined() { throw new ReflectionException('Method not implemented'); } + public function returnsReference() { throw new ReflectionException('Method not implemented'); } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php new file mode 100644 index 0000000..7f3e41f --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionParser.php @@ -0,0 +1,282 @@ +. + */ + +namespace Doctrine\Common\Reflection; + +use ReflectionException; +use Doctrine\Common\Annotations\TokenParser; + +/** + * Parses a file for namespaces/use/class declarations. + * + * @author Karoly Negyesi + */ +class StaticReflectionParser implements ReflectionProviderInterface +{ + + /** + * The name of the class. + * + * @var string + */ + protected $className; + + /** + * TRUE if the caller only wants class annotations. + * + * @var boolean. + */ + protected $classAnnotationOptimize; + + /** + * TRUE when the parser has ran. + * + * @var boolean + */ + protected $parsed = false; + + /** + * The namespace of the class + * + * @var string + */ + protected $namespace = ''; + + /** + * The use statements of this class. + * + * @var array + */ + protected $useStatements = array(); + + /** + * The docComment of the class. + * + * @var string + */ + protected $docComment = array( + 'class' => '', + 'property' => array(), + 'method' => array(), + ); + + /** + * The name of the class this class extends, if any. + * + * @var string + */ + protected $parentClassName = ''; + + /** + * The parent PSR-0 Parser. + * + * @var \Doctrine\Common\Annotations\StaticReflectionParser + */ + protected $parentStaticReflectionParser; + + /** + * Parses a class residing in a PSR-0 hierarchy. + * + * @param string $class + * The full, namespaced class name. + * @param ClassFinder $finder + * A ClassFinder object which finds the class. + * @param boolean $classAnnotationOptimize + * Only retrieve the class docComment. Presumes there is only one + * statement per line. + */ + public function __construct($className, $finder, $classAnnotationOptimize = false) + { + $this->className = ltrim($className, '\\'); + if ($lastNsPos = strrpos($this->className, '\\')) { + $this->namespace = substr($this->className, 0, $lastNsPos); + } + $this->finder = $finder; + $this->classAnnotationOptimize = $classAnnotationOptimize; + } + + protected function parse() + { + if ($this->parsed || !$fileName = $this->finder->findFile($this->className)) { + return; + } + $this->parsed = true; + $contents = file_get_contents($fileName); + if ($this->classAnnotationOptimize) { + if (preg_match("/(\A.*)^\s+(abstract|final)?\s+class\s+$className\s+{/sm", $contents, $matches)) { + $contents = $matches[1]; + } + } + $tokenParser = new TokenParser($contents); + $docComment = ''; + while ($token = $tokenParser->next(false)) { + if (is_array($token)) { + switch ($token[0]) { + case T_USE: + $this->useStatements = array_merge($this->useStatements, $tokenParser->parseUseStatement()); + break; + case T_DOC_COMMENT: + $docComment = $token[1]; + break; + case T_CLASS: + $this->docComment['class'] = $docComment; + $docComment = ''; + break; + case T_VAR: + case T_PRIVATE: + case T_PROTECTED: + case T_PUBLIC: + $token = $tokenParser->next(); + if ($token[0] === T_VARIABLE) { + $propertyName = substr($token[1], 1); + $this->docComment['property'][$propertyName] = $docComment; + continue 2; + } + if ($token[0] !== T_FUNCTION) { + // For example, it can be T_FINAL. + continue 2; + } + // No break. + case T_FUNCTION: + // The next string after function is the name, but + // there can be & before the function name so find the + // string. + while (($token = $tokenParser->next()) && $token[0] !== T_STRING); + $methodName = $token[1]; + $this->docComment['method'][$methodName] = $docComment; + $docComment = ''; + break; + case T_EXTENDS: + $this->parentClassName = $tokenParser->parseClass(); + $nsPos = strpos($this->parentClassName, '\\'); + $fullySpecified = false; + if ($nsPos === 0) { + $fullySpecified = true; + } else { + if ($nsPos) { + $prefix = strtolower(substr($this->parentClassName, 0, $nsPos)); + $postfix = substr($this->parentClassName, $nsPos); + } else { + $prefix = strtolower($this->parentClassName); + $postfix = ''; + } + foreach ($this->useStatements as $alias => $use) { + if ($alias == $prefix) { + $this->parentClassName = '\\' . $use . $postfix; + $fullySpecified = true; + } + } + } + if (!$fullySpecified) { + $this->parentClassName = '\\' . $this->namespace . '\\' . $this->parentClassName; + } + break; + } + } + } + } + + protected function getParentStaticReflectionParser() + { + if (empty($this->parentStaticReflectionParser)) { + $this->parentStaticReflectionParser = new static($this->parentClassName, $this->finder); + } + + return $this->parentStaticReflectionParser; + } + + public function getClassName() + { + return $this->className; + } + + public function getNamespaceName() + { + return $this->namespace; + } + + /** + * Get the ReflectionClass equivalent for this file / class. + */ + public function getReflectionClass() + { + return new StaticReflectionClass($this); + } + + /** + * Get the ReflectionMethod equivalent for the method of this file / class. + */ + public function getReflectionMethod($methodName) + { + return new StaticReflectionMethod($this, $methodName); + } + + /** + * Get the ReflectionProperty equivalent for the method of this file / class. + */ + public function getReflectionProperty($propertyName) + { + return new StaticReflectionProperty($this, $propertyName); + } + + /** + * Get the use statements from this file. + */ + public function getUseStatements() + { + $this->parse(); + + return $this->useStatements; + } + + /** + * Get docComment. + * + * @param string $type class, property or method. + * @param string $name Name of the property or method, not needed for class. + * + * @return string the doc comment or empty string if none. + */ + public function getDocComment($type = 'class', $name = '') + { + $this->parse(); + + return $name ? $this->docComment[$type][$name] : $this->docComment[$type]; + } + + /** + * Get the PSR-0 parser for the declaring class. + * + * @param string $type property or method. + * @param string $name Name of the property or method. + * + * @return StaticReflectionParser A static reflection parser for the declaring class. + */ + public function getStaticReflectionParserForDeclaringClass($type, $name) + { + $this->parse(); + if (isset($this->docComment[$type][$name])) { + return $this; + } + if (!empty($this->parentClassName)) { + return $this->getParentStaticReflectionParser()->getStaticReflectionParserForDeclaringClass($type, $name); + } + throw new ReflectionException('Invalid ' . $type . ' "' . $name . '"'); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionProperty.php b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionProperty.php new file mode 100644 index 0000000..7c6411a --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Reflection/StaticReflectionProperty.php @@ -0,0 +1,77 @@ +. + */ + +namespace Doctrine\Common\Reflection; + +use ReflectionProperty; +use ReflectionException; + +class StaticReflectionProperty extends ReflectionProperty +{ + /** + * The PSR-0 parser object. + * + * @var StaticReflectionParser + */ + protected $staticReflectionParser; + + /** + * The name of the property. + * + * @var string + */ + protected $propertyName; + + public function __construct(StaticReflectionParser $staticReflectionParser, $propertyName) + { + $this->staticReflectionParser = $staticReflectionParser; + $this->propertyName = $propertyName; + } + public function getName() + { + return $this->propertyName; + } + protected function getStaticReflectionParser() + { + return $this->staticReflectionParser->getStaticReflectionParserForDeclaringClass('property', $this->propertyName); + } + public function getDeclaringClass() + { + return $this->getStaticReflectionParser()->getReflectionClass(); + } + public function getDocComment() + { + return $this->getStaticReflectionParser()->getDocComment('property', $this->propertyName); + } + public function getUseStatements() + { + return $this->getStaticReflectionParser()->getUseStatements(); + } + public static function export ($class, $name, $return = false) { throw new ReflectionException('Method not implemented'); } + public function getModifiers() { throw new ReflectionException('Method not implemented'); } + public function getValue($object = NULL) { throw new ReflectionException('Method not implemented'); } + public function isDefault() { throw new ReflectionException('Method not implemented'); } + public function isPrivate() { throw new ReflectionException('Method not implemented'); } + public function isProtected() { throw new ReflectionException('Method not implemented'); } + public function isPublic() { throw new ReflectionException('Method not implemented'); } + public function isStatic() { throw new ReflectionException('Method not implemented'); } + public function setAccessible ($accessible) { throw new ReflectionException('Method not implemented'); } + public function setValue ($object, $value = NULL) { throw new ReflectionException('Method not implemented'); } + public function __toString() { throw new ReflectionException('Method not implemented'); } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php b/vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php new file mode 100644 index 0000000..078a8db --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Util/ClassUtils.php @@ -0,0 +1,103 @@ +. + */ + +namespace Doctrine\Common\Util; + +use Doctrine\Common\Persistence\Proxy; + +/** + * Class and reflection related functionality for objects that + * might or not be proxy objects at the moment. + * + * @author Benjamin Eberlei + * @author Johannes Schmitt + */ +class ClassUtils +{ + /** + * Get the real class name of a class name that could be a proxy. + * + * @param string + * @return string + */ + public static function getRealClass($class) + { + if (false === $pos = strrpos($class, '\\'.Proxy::MARKER.'\\')) { + return $class; + } + + return substr($class, $pos + Proxy::MARKER_LENGTH + 2); + } + + /** + * Get the real class name of an object (even if its a proxy) + * + * @param object + * @return string + */ + public static function getClass($object) + { + return self::getRealClass(get_class($object)); + } + + /** + * Get the real parent class name of a class or object + * + * @param string + * @return string + */ + public static function getParentClass($className) + { + return get_parent_class( self::getRealClass( $className ) ); + } + + /** + * Create a new reflection class + * + * @param string + * @return \ReflectionClass + */ + public static function newReflectionClass($class) + { + return new \ReflectionClass( self::getRealClass( $class ) ); + } + + /** + * Create a new reflection object + * + * @param object + * @return \ReflectionObject + */ + public static function newReflectionObject($object) + { + return self::newReflectionClass( self::getClass( $object ) ); + } + + /** + * Given a class name and a proxy namespace return the proxy name. + * + * @param string $className + * @param string $proxyNamespace + * @return string + */ + public static function generateProxyClassName($className, $proxyNamespace) + { + return rtrim($proxyNamespace, '\\') . '\\'.Proxy::MARKER.'\\' . ltrim($className, '\\'); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php b/vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php new file mode 100644 index 0000000..458e5c8 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Util/Debug.php @@ -0,0 +1,135 @@ +. + */ + +namespace Doctrine\Common\Util; + +/** + * Static class containing most used debug methods. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Giorgio Sironi + */ +final class Debug +{ + /** + * Private constructor (prevents from instantiation) + * + */ + private function __construct() {} + + /** + * Prints a dump of the public, protected and private properties of $var. + * + * @link http://xdebug.org/ + * @param mixed $var + * @param integer $maxDepth Maximum nesting level for object properties + * @param boolean $stripTags Flag that indicate if output should strip HTML tags + */ + public static function dump($var, $maxDepth = 2, $stripTags = true) + { + ini_set('html_errors', 'On'); + + if (extension_loaded('xdebug')) { + ini_set('xdebug.var_display_max_depth', $maxDepth); + } + + $var = self::export($var, $maxDepth++); + + ob_start(); + var_dump($var); + $dump = ob_get_contents(); + ob_end_clean(); + + echo ($stripTags ? strip_tags(html_entity_decode($dump)) : $dump); + + ini_set('html_errors', 'Off'); + } + + /** + * Export + * + * @param mixed $var + * @param int $maxDepth + * @return mixed + */ + public static function export($var, $maxDepth) + { + $return = null; + $isObj = is_object($var); + + if ($isObj && in_array('Doctrine\Common\Collections\Collection', class_implements($var))) { + $var = $var->toArray(); + } + + if ($maxDepth) { + if (is_array($var)) { + $return = array(); + + foreach ($var as $k => $v) { + $return[$k] = self::export($v, $maxDepth - 1); + } + } else if ($isObj) { + $return = new \stdclass(); + if ($var instanceof \DateTime) { + $return->__CLASS__ = "DateTime"; + $return->date = $var->format('c'); + $return->timezone = $var->getTimeZone()->getName(); + } else { + $reflClass = ClassUtils::newReflectionObject($var); + $return->__CLASS__ = ClassUtils::getClass($var); + + if ($var instanceof \Doctrine\Common\Persistence\Proxy) { + $return->__IS_PROXY__ = true; + $return->__PROXY_INITIALIZED__ = $var->__isInitialized(); + } + + foreach ($reflClass->getProperties() as $reflProperty) { + $name = $reflProperty->getName(); + + $reflProperty->setAccessible(true); + $return->$name = self::export($reflProperty->getValue($var), $maxDepth - 1); + } + } + } else { + $return = $var; + } + } else { + $return = is_object($var) ? get_class($var) + : (is_array($var) ? 'Array(' . count($var) . ')' : $var); + } + + return $return; + } + + /** + * Convert to string + * + * @param object $obj + * @return string + */ + public static function toString($obj) + { + return method_exists('__toString', $obj) ? (string) $obj : get_class($obj) . '@' . spl_object_hash($obj); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Util/Inflector.php b/vendor/doctrine/common/lib/Doctrine/Common/Util/Inflector.php new file mode 100644 index 0000000..214ed57 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Util/Inflector.php @@ -0,0 +1,72 @@ +. + */ + +namespace Doctrine\Common\Util; + +/** + * Doctrine inflector has static methods for inflecting text + * + * The methods in these classes are from several different sources collected + * across several different php projects and several different authors. The + * original author names and emails are not known + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 1.0 + * @version $Revision: 3189 $ + * @author Konsta Vesterinen + * @author Jonathan H. Wage + */ +class Inflector +{ + /** + * Convert word in to the format for a Doctrine table name. Converts 'ModelName' to 'model_name' + * + * @param string $word Word to tableize + * @return string $word Tableized word + */ + public static function tableize($word) + { + return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $word)); + } + + /** + * Convert a word in to the format for a Doctrine class name. Converts 'table_name' to 'TableName' + * + * @param string $word Word to classify + * @return string $word Classified word + */ + public static function classify($word) + { + return str_replace(" ", "", ucwords(strtr($word, "_-", " "))); + } + + /** + * Camelize a word. This uses the classify() method and turns the first character to lowercase + * + * @param string $word + * @return string $word + */ + public static function camelize($word) + { + return lcfirst(self::classify($word)); + } +} diff --git a/vendor/doctrine/common/lib/Doctrine/Common/Version.php b/vendor/doctrine/common/lib/Doctrine/Common/Version.php new file mode 100644 index 0000000..cca4894 --- /dev/null +++ b/vendor/doctrine/common/lib/Doctrine/Common/Version.php @@ -0,0 +1,55 @@ +. + */ + +namespace Doctrine\Common; + +/** + * Class to store and retrieve the version of Doctrine + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Version +{ + /** + * Current Doctrine Version + */ + const VERSION = '2.3.0'; + + /** + * Compares a Doctrine version with the current one. + * + * @param string $version Doctrine version to compare. + * @return int Returns -1 if older, 0 if it is the same, 1 if version + * passed as argument is newer. + */ + public static function compare($version) + { + $currentVersion = str_replace(' ', '', strtolower(self::VERSION)); + $version = str_replace(' ', '', $version); + + return version_compare($version, $currentVersion); + } +} diff --git a/vendor/doctrine/common/phpunit.xml.dist b/vendor/doctrine/common/phpunit.xml.dist new file mode 100644 index 0000000..b9d3b34 --- /dev/null +++ b/vendor/doctrine/common/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + ./tests/Doctrine/ + + + + + + ./lib/Doctrine/ + + + + + + performance + + + diff --git a/vendor/doctrine/common/tests/.gitignore b/vendor/doctrine/common/tests/.gitignore new file mode 100644 index 0000000..7210405 --- /dev/null +++ b/vendor/doctrine/common/tests/.gitignore @@ -0,0 +1,3 @@ +Doctrine/Tests/Proxies/ +Doctrine/Tests/ORM/Proxy/generated/ +Doctrine/Tests/ORM/Tools/Export/export diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/AbstractReaderTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/AbstractReaderTest.php new file mode 100644 index 0000000..4261e6b --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/AbstractReaderTest.php @@ -0,0 +1,517 @@ + array($testsRoot), + ); + $staticReflectionParser = new StaticReflectionParser($className, new Psr0FindFile($paths)); + return array( + 'native' => array(new ReflectionClass($className)), + 'static' => array($staticReflectionParser->getReflectionClass()), + ); + } + + /** + * @dataProvider getReflectionClass + */ + public function testAnnotations($class) + { + $reader = $this->getReader(); + $this->assertEquals(1, count($reader->getClassAnnotations($class))); + $this->assertInstanceOf($annotName = 'Doctrine\Tests\Common\Annotations\DummyAnnotation', $annot = $reader->getClassAnnotation($class, $annotName)); + $this->assertEquals("hello", $annot->dummyValue); + + $field1Prop = $class->getProperty('field1'); + $propAnnots = $reader->getPropertyAnnotations($field1Prop); + $this->assertEquals(1, count($propAnnots)); + $this->assertInstanceOf($annotName, $annot = $reader->getPropertyAnnotation($field1Prop, $annotName)); + $this->assertEquals("fieldHello", $annot->dummyValue); + + $getField1Method = $class->getMethod('getField1'); + $methodAnnots = $reader->getMethodAnnotations($getField1Method); + $this->assertEquals(1, count($methodAnnots)); + $this->assertInstanceOf($annotName, $annot = $reader->getMethodAnnotation($getField1Method, $annotName)); + $this->assertEquals(array(1, 2, "three"), $annot->value); + + $field2Prop = $class->getProperty('field2'); + $propAnnots = $reader->getPropertyAnnotations($field2Prop); + $this->assertEquals(1, count($propAnnots)); + $this->assertInstanceOf($annotName = 'Doctrine\Tests\Common\Annotations\DummyJoinTable', $joinTableAnnot = $reader->getPropertyAnnotation($field2Prop, $annotName)); + $this->assertEquals(1, count($joinTableAnnot->joinColumns)); + $this->assertEquals(1, count($joinTableAnnot->inverseJoinColumns)); + $this->assertTrue($joinTableAnnot->joinColumns[0] instanceof DummyJoinColumn); + $this->assertTrue($joinTableAnnot->inverseJoinColumns[0] instanceof DummyJoinColumn); + $this->assertEquals('col1', $joinTableAnnot->joinColumns[0]->name); + $this->assertEquals('col2', $joinTableAnnot->joinColumns[0]->referencedColumnName); + $this->assertEquals('col3', $joinTableAnnot->inverseJoinColumns[0]->name); + $this->assertEquals('col4', $joinTableAnnot->inverseJoinColumns[0]->referencedColumnName); + + $dummyAnnot = $reader->getMethodAnnotation($class->getMethod('getField1'), 'Doctrine\Tests\Common\Annotations\DummyAnnotation'); + $this->assertEquals('', $dummyAnnot->dummyValue); + $this->assertEquals(array(1, 2, 'three'), $dummyAnnot->value); + + $dummyAnnot = $reader->getPropertyAnnotation($class->getProperty('field1'), 'Doctrine\Tests\Common\Annotations\DummyAnnotation'); + $this->assertEquals('fieldHello', $dummyAnnot->dummyValue); + + $classAnnot = $reader->getClassAnnotation($class, 'Doctrine\Tests\Common\Annotations\DummyAnnotation'); + $this->assertEquals('hello', $classAnnot->dummyValue); + } + + public function testAnnotationsWithValidTargets() + { + $reader = $this->getReader(); + $class = new ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithValidAnnotationTarget'); + + $this->assertEquals(1,count($reader->getClassAnnotations($class))); + $this->assertEquals(1,count($reader->getPropertyAnnotations($class->getProperty('foo')))); + $this->assertEquals(1,count($reader->getMethodAnnotations($class->getMethod('someFunction')))); + $this->assertEquals(1,count($reader->getPropertyAnnotations($class->getProperty('nested')))); + } + + public function testAnnotationsWithVarType() + { + $reader = $this->getReader(); + $class = new ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithAnnotationWithVarType'); + + $this->assertEquals(1,count($fooAnnot = $reader->getPropertyAnnotations($class->getProperty('foo')))); + $this->assertEquals(1,count($barAnnot = $reader->getMethodAnnotations($class->getMethod('bar')))); + + $this->assertInternalType('string', $fooAnnot[0]->string); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', $barAnnot[0]->annotation); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage [Semantical Error] Annotation @AnnotationTargetPropertyMethod is not allowed to be declared on class Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtClass. You may only use this annotation on these code elements: METHOD, PROPERTY + */ + public function testClassWithInvalidAnnotationTargetAtClassDocBlock() + { + $reader = $this->getReader(); + $reader->getClassAnnotations(new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtClass')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage [Semantical Error] Annotation @AnnotationTargetClass is not allowed to be declared on property Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtProperty::$foo. You may only use this annotation on these code elements: CLASS + */ + public function testClassWithInvalidAnnotationTargetAtPropertyDocBlock() + { + $reader = $this->getReader(); + $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtProperty', 'foo')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage [Semantical Error] Annotation @AnnotationTargetAnnotation is not allowed to be declared on property Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtProperty::$bar. You may only use this annotation on these code elements: ANNOTATION + */ + public function testClassWithInvalidNestedAnnotationTargetAtPropertyDocBlock() + { + $reader = $this->getReader(); + $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtProperty', 'bar')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage [Semantical Error] Annotation @AnnotationTargetClass is not allowed to be declared on method Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtMethod::functionName(). You may only use this annotation on these code elements: CLASS + */ + public function testClassWithInvalidAnnotationTargetAtMethodDocBlock() + { + $reader = $this->getReader(); + $reader->getMethodAnnotations(new \ReflectionMethod('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtMethod', 'functionName')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 24 in class @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithTargetSyntaxError. + */ + public function testClassWithAnnotationWithTargetSyntaxErrorAtClassDocBlock() + { + $reader = $this->getReader(); + $reader->getClassAnnotations(new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithAnnotationWithTargetSyntaxError')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 24 in class @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithTargetSyntaxError. + */ + public function testClassWithAnnotationWithTargetSyntaxErrorAtPropertyDocBlock() + { + $reader = $this->getReader(); + $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithAnnotationWithTargetSyntaxError','foo')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 24 in class @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithTargetSyntaxError. + */ + public function testClassWithAnnotationWithTargetSyntaxErrorAtMethodDocBlock() + { + $reader = $this->getReader(); + $reader->getMethodAnnotations(new \ReflectionMethod('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithAnnotationWithTargetSyntaxError','bar')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage [Type Error] Attribute "string" of @AnnotationWithVarType declared on property Doctrine\Tests\Common\Annotations\Fixtures\ClassWithAnnotationWithVarType::$invalidProperty expects a(n) string, but got integer. + */ + public function testClassWithPropertyInvalidVarTypeError() + { + $reader = $this->getReader(); + $class = new ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithAnnotationWithVarType'); + + $reader->getPropertyAnnotations($class->getProperty('invalidProperty')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage [Type Error] Attribute "annotation" of @AnnotationWithVarType declared on method Doctrine\Tests\Common\Annotations\Fixtures\ClassWithAnnotationWithVarType::invalidMethod() expects a(n) Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll, but got an instance of Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation. + */ + public function testClassWithMethodInvalidVarTypeError() + { + $reader = $this->getReader(); + $class = new ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithAnnotationWithVarType'); + + $reader->getMethodAnnotations($class->getMethod('invalidMethod')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 18 in class Doctrine\Tests\Common\Annotations\DummyClassSyntaxError. + */ + public function testClassSyntaxErrorContext() + { + $reader = $this->getReader(); + $reader->getClassAnnotations(new \ReflectionClass('Doctrine\Tests\Common\Annotations\DummyClassSyntaxError')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 18 in method Doctrine\Tests\Common\Annotations\DummyClassMethodSyntaxError::foo(). + */ + public function testMethodSyntaxErrorContext() + { + $reader = $this->getReader(); + $reader->getMethodAnnotations(new \ReflectionMethod('Doctrine\Tests\Common\Annotations\DummyClassMethodSyntaxError', 'foo')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 18 in property Doctrine\Tests\Common\Annotations\DummyClassPropertySyntaxError::$foo. + */ + public function testPropertySyntaxErrorContext() + { + $reader = $this->getReader(); + $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\DummyClassPropertySyntaxError', 'foo')); + } + + /** + * @group regression + */ + public function testMultipleAnnotationsOnSameLine() + { + $reader = $this->getReader(); + $annots = $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\DummyClass2', 'id')); + $this->assertEquals(3, count($annots)); + } + + public function testNonAnnotationProblem() + { + $reader = $this->getReader(); + + $this->assertNotNull($annot = $reader->getPropertyAnnotation(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\DummyClassNonAnnotationProblem', 'foo'), $name = 'Doctrine\Tests\Common\Annotations\DummyAnnotation')); + $this->assertInstanceOf($name, $annot); + } + + public function testImportWithConcreteAnnotation() + { + $reader = $this->getReader(); + $property = new \ReflectionProperty('Doctrine\Tests\Common\Annotations\TestImportWithConcreteAnnotation', 'field'); + $annotations = $reader->getPropertyAnnotations($property); + $this->assertEquals(1, count($annotations)); + $this->assertNotNull($reader->getPropertyAnnotation($property, 'Doctrine\Tests\Common\Annotations\DummyAnnotation')); + } + + public function testImportWithInheritance() + { + $reader = $this->getReader(); + + $class = new TestParentClass(); + $ref = new \ReflectionClass($class); + + $childAnnotations = $reader->getPropertyAnnotations($ref->getProperty('child')); + $this->assertEquals(1, count($childAnnotations)); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Foo\Name', reset($childAnnotations)); + + $parentAnnotations = $reader->getPropertyAnnotations($ref->getProperty('parent')); + $this->assertEquals(1, count($parentAnnotations)); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Bar\Name', reset($parentAnnotations)); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage The annotation "@NameFoo" in property Doctrine\Tests\Common\Annotations\TestAnnotationNotImportedClass::$field was never imported. + */ + public function testImportDetectsNotImportedAnnotation() + { + $reader = $this->getReader(); + $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\TestAnnotationNotImportedClass', 'field')); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage The annotation "@Foo\Bar\Name" in property Doctrine\Tests\Common\Annotations\TestNonExistentAnnotationClass::$field was never imported. + */ + public function testImportDetectsNonExistentAnnotation() + { + $reader = $this->getReader(); + $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\TestNonExistentAnnotationClass', 'field')); + } + + public function testTopLevelAnnotation() + { + $reader = $this->getReader(); + $annotations = $reader->getPropertyAnnotations(new \ReflectionProperty('Doctrine\Tests\Common\Annotations\TestTopLevelAnnotationClass', 'field')); + + $this->assertEquals(1, count($annotations)); + $this->assertInstanceOf('\TopLevelAnnotation', reset($annotations)); + } + + public function testIgnoresAnnotationsNotPrefixedWithWhitespace() + { + $reader = $this->getReader(); + + $annotation = $reader->getClassAnnotation(new \ReflectionClass(new TestIgnoresNonAnnotationsClass()), 'Doctrine\Tests\Common\Annotations\Name'); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Name', $annotation); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage The class "Doctrine\Tests\Common\Annotations\Fixtures\NoAnnotation" is not annotated with @Annotation. Are you sure this class can be used as annotation? If so, then you need to add @Annotation to the _class_ doc comment of "Doctrine\Tests\Common\Annotations\Fixtures\NoAnnotation". If it is indeed no annotation, then you need to add @IgnoreAnnotation("NoAnnotation") to the _class_ doc comment of class Doctrine\Tests\Common\Annotations\Fixtures\InvalidAnnotationUsageClass. + */ + public function testErrorWhenInvalidAnnotationIsUsed() + { + $reader = $this->getReader(); + $ref = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\InvalidAnnotationUsageClass'); + $reader->getClassAnnotations($ref); + } + + public function testInvalidAnnotationUsageButIgnoredClass() + { + $reader = $this->getReader(); + $ref = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\InvalidAnnotationUsageButIgnoredClass'); + $annots = $reader->getClassAnnotations($ref); + + $this->assertEquals(2, count($annots)); + } + + /** + * @group DDC-1660 + * @group regression + */ + public function testInvalidAnnotationButIgnored() + { + $reader = $this->getReader(); + $class = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassDDC1660'); + + $this->assertTrue(class_exists('Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Version')); + $this->assertCount(0, $reader->getClassAnnotations($class)); + $this->assertCount(0, $reader->getMethodAnnotations($class->getMethod('bar'))); + $this->assertCount(0, $reader->getPropertyAnnotations($class->getProperty('foo'))); + } + + abstract protected function getReader(); +} + +/** + * @parseAnnotation("var") + * @author Johannes M. Schmitt + * + */ +class TestParseAnnotationClass +{ + /** + * @var + */ + private $field; +} + +/** + * @Name + * @author Johannes M. Schmitt + */ +class TestIgnoresNonAnnotationsClass +{ +} + +class TestTopLevelAnnotationClass +{ + /** + * @\TopLevelAnnotation + */ + private $field; +} + +class TestNonExistentAnnotationClass +{ + /** + * @Foo\Bar\Name + */ + private $field; +} + +class TestAnnotationNotImportedClass +{ + /** + * @NameFoo + */ + private $field; +} + +class TestChildClass +{ + /** + * @\Doctrine\Tests\Common\Annotations\Foo\Name(name = "foo") + */ + protected $child; +} + +class TestParentClass extends TestChildClass +{ + /** + * @\Doctrine\Tests\Common\Annotations\Bar\Name(name = "bar") + */ + private $parent; +} + +class TestImportWithConcreteAnnotation +{ + /** + * @DummyAnnotation(dummyValue = "bar") + */ + private $field; +} + +/** + * @ignoreAnnotation("var") + */ +class DummyClass2 { + /** + * @DummyId @DummyColumn(type="integer") @DummyGeneratedValue + * @var integer + */ + private $id; +} + +/** @Annotation */ +class DummyId extends \Doctrine\Common\Annotations\Annotation {} +/** @Annotation */ +class DummyColumn extends \Doctrine\Common\Annotations\Annotation { + public $type; +} +/** @Annotation */ +class DummyGeneratedValue extends \Doctrine\Common\Annotations\Annotation {} +/** @Annotation */ +class DummyAnnotation extends \Doctrine\Common\Annotations\Annotation { + public $dummyValue; +} +/** @Annotation */ +class DummyJoinColumn extends \Doctrine\Common\Annotations\Annotation { + public $name; + public $referencedColumnName; +} +/** @Annotation */ +class DummyJoinTable extends \Doctrine\Common\Annotations\Annotation { + public $name; + public $joinColumns; + public $inverseJoinColumns; +} + +/** + * @DummyAnnotation(@) + */ +class DummyClassSyntaxError +{ + +} + +class DummyClassMethodSyntaxError +{ + /** + * @DummyAnnotation(@) + */ + public function foo() + { + + } +} + +class DummyClassPropertySyntaxError +{ + /** + * @DummyAnnotation(@) + */ + public $foo; +} + +/** + * @ignoreAnnotation({"since", "var"}) + */ +class DummyClassNonAnnotationProblem +{ + /** + * @DummyAnnotation + * + * @var \Test + * @since 0.1 + */ + public $foo; +} + + +/** +* @DummyAnnotation Foo bar +*/ +class DummyClassWithEmail +{ + +} + +namespace Doctrine\Tests\Common\Annotations\Foo; + +/** @Annotation */ +class Name extends \Doctrine\Common\Annotations\Annotation +{ + public $name; +} + +namespace Doctrine\Tests\Common\Annotations\Bar; + +/** @Annotation */ +class Name extends \Doctrine\Common\Annotations\Annotation +{ + public $name; +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php new file mode 100644 index 0000000..d2cc667 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/AnnotationReaderTest.php @@ -0,0 +1,13 @@ +getMock('Doctrine\Common\Cache\Cache'); + $cache + ->expects($this->at(0)) + ->method('fetch') + ->with($this->equalTo($cacheKey)) + ->will($this->returnValue(array())) + ; + $cache + ->expects($this->at(1)) + ->method('fetch') + ->with($this->equalTo('[C]'.$cacheKey)) + ->will($this->returnValue(time() - 10)) + ; + $cache + ->expects($this->at(2)) + ->method('save') + ->with($this->equalTo($cacheKey)) + ; + $cache + ->expects($this->at(3)) + ->method('save') + ->with($this->equalTo('[C]'.$cacheKey)) + ; + + $reader = new CachedReader(new AnnotationReader(), $cache, true); + $route = new Route(); + $route->pattern = '/someprefix'; + $this->assertEquals(array($route), $reader->getClassAnnotations(new \ReflectionClass($name))); + } + + protected function getReader() + { + $this->cache = new ArrayCache(); + return new CachedReader(new AnnotationReader(), $this->cache); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DocLexerTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DocLexerTest.php new file mode 100644 index 0000000..03a55c8 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DocLexerTest.php @@ -0,0 +1,137 @@ +setInput("@Name"); + $this->assertNull($lexer->token); + $this->assertNull($lexer->lookahead); + + $this->assertTrue($lexer->moveNext()); + $this->assertNull($lexer->token); + $this->assertEquals('@', $lexer->lookahead['value']); + + $this->assertTrue($lexer->moveNext()); + $this->assertEquals('@', $lexer->token['value']); + $this->assertEquals('Name', $lexer->lookahead['value']); + + $this->assertFalse($lexer->moveNext()); + } + + public function testScannerTokenizesDocBlockWhitConstants() + { + $lexer = new DocLexer(); + $docblock = '@AnnotationWithConstants(PHP_EOL, ClassWithConstants::SOME_VALUE, \Doctrine\Tests\Common\Annotations\Fixtures\IntefaceWithConstants::SOME_VALUE)'; + + $tokens = array ( + array( + 'value' => '@', + 'position' => 0, + 'type' => DocLexer::T_AT, + ), + array( + 'value' => 'AnnotationWithConstants', + 'position' => 1, + 'type' => DocLexer::T_IDENTIFIER, + ), + array( + 'value' => '(', + 'position' => 24, + 'type' => DocLexer::T_OPEN_PARENTHESIS, + ), + array( + 'value' => 'PHP_EOL', + 'position' => 25, + 'type' => DocLexer::T_IDENTIFIER, + ), + array( + 'value' => ',', + 'position' => 32, + 'type' => DocLexer::T_COMMA, + ), + array( + 'value' => 'ClassWithConstants::SOME_VALUE', + 'position' => 34, + 'type' => DocLexer::T_IDENTIFIER, + ), + array( + 'value' => ',', + 'position' => 64, + 'type' => DocLexer::T_COMMA, + ), + array( + 'value' => '\\Doctrine\\Tests\\Common\\Annotations\\Fixtures\\IntefaceWithConstants::SOME_VALUE', + 'position' => 66, + 'type' => DocLexer::T_IDENTIFIER, + ), + array( + 'value' => ')', + 'position' => 143, + 'type' => DocLexer::T_CLOSE_PARENTHESIS, + ) + + ); + + $lexer->setInput($docblock); + + foreach ($tokens as $expected) { + $lexer->moveNext(); + $lookahead = $lexer->lookahead; + $this->assertEquals($expected['value'], $lookahead['value']); + $this->assertEquals($expected['type'], $lookahead['type']); + $this->assertEquals($expected['position'], $lookahead['position']); + } + + $this->assertFalse($lexer->moveNext()); + } + + + public function testScannerTokenizesDocBlockWhitInvalidIdentifier() + { + $lexer = new DocLexer(); + $docblock = '@Foo\3.42'; + + $tokens = array ( + array( + 'value' => '@', + 'position' => 0, + 'type' => DocLexer::T_AT, + ), + array( + 'value' => 'Foo', + 'position' => 1, + 'type' => DocLexer::T_IDENTIFIER, + ), + array( + 'value' => '\\', + 'position' => 4, + 'type' => DocLexer::T_NAMESPACE_SEPARATOR, + ), + array( + 'value' => 3.42, + 'position' => 5, + 'type' => DocLexer::T_FLOAT, + ) + ); + + $lexer->setInput($docblock); + + foreach ($tokens as $expected) { + $lexer->moveNext(); + $lookahead = $lexer->lookahead; + $this->assertEquals($expected['value'], $lookahead['value']); + $this->assertEquals($expected['type'], $lookahead['type']); + $this->assertEquals($expected['position'], $lookahead['position']); + } + + $this->assertFalse($lexer->moveNext()); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DocParserTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DocParserTest.php new file mode 100644 index 0000000..b14698f --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DocParserTest.php @@ -0,0 +1,1208 @@ +createTestParser(); + + // Nested arrays with nested annotations + $result = $parser->parse('@Name(foo={1,2, {"key"=@Name}})'); + $annot = $result[0]; + + $this->assertTrue($annot instanceof Name); + $this->assertNull($annot->value); + $this->assertEquals(3, count($annot->foo)); + $this->assertEquals(1, $annot->foo[0]); + $this->assertEquals(2, $annot->foo[1]); + $this->assertTrue(is_array($annot->foo[2])); + + $nestedArray = $annot->foo[2]; + $this->assertTrue(isset($nestedArray['key'])); + $this->assertTrue($nestedArray['key'] instanceof Name); + } + + public function testBasicAnnotations() + { + $parser = $this->createTestParser(); + + // Marker annotation + $result = $parser->parse("@Name"); + $annot = $result[0]; + $this->assertTrue($annot instanceof Name); + $this->assertNull($annot->value); + $this->assertNull($annot->foo); + + // Associative arrays + $result = $parser->parse('@Name(foo={"key1" = "value1"})'); + $annot = $result[0]; + $this->assertNull($annot->value); + $this->assertTrue(is_array($annot->foo)); + $this->assertTrue(isset($annot->foo['key1'])); + + // Numerical arrays + $result = $parser->parse('@Name({2="foo", 4="bar"})'); + $annot = $result[0]; + $this->assertTrue(is_array($annot->value)); + $this->assertEquals('foo', $annot->value[2]); + $this->assertEquals('bar', $annot->value[4]); + $this->assertFalse(isset($annot->value[0])); + $this->assertFalse(isset($annot->value[1])); + $this->assertFalse(isset($annot->value[3])); + + // Multiple values + $result = $parser->parse('@Name(@Name, @Name)'); + $annot = $result[0]; + + $this->assertTrue($annot instanceof Name); + $this->assertTrue(is_array($annot->value)); + $this->assertTrue($annot->value[0] instanceof Name); + $this->assertTrue($annot->value[1] instanceof Name); + + // Multiple types as values + $result = $parser->parse('@Name(foo="Bar", @Name, {"key1"="value1", "key2"="value2"})'); + $annot = $result[0]; + + $this->assertTrue($annot instanceof Name); + $this->assertTrue(is_array($annot->value)); + $this->assertTrue($annot->value[0] instanceof Name); + $this->assertTrue(is_array($annot->value[1])); + $this->assertEquals('value1', $annot->value[1]['key1']); + $this->assertEquals('value2', $annot->value[1]['key2']); + + // Complete docblock + $docblock = <<parse($docblock); + $this->assertEquals(1, count($result)); + $annot = $result[0]; + $this->assertTrue($annot instanceof Name); + $this->assertEquals("bar", $annot->foo); + $this->assertNull($annot->value); + } + + public function testNamespacedAnnotations() + { + $parser = new DocParser; + $parser->setIgnoreNotImportedAnnotations(true); + + $docblock = << + * @Doctrine\Tests\Common\Annotations\Name(foo="bar") + * @ignore + */ +DOCBLOCK; + + $result = $parser->parse($docblock); + $this->assertEquals(1, count($result)); + $annot = $result[0]; + $this->assertTrue($annot instanceof Name); + $this->assertEquals("bar", $annot->foo); + } + + /** + * @group debug + */ + public function testTypicalMethodDocBlock() + { + $parser = $this->createTestParser(); + + $docblock = <<parse($docblock); + $this->assertEquals(2, count($result)); + $this->assertTrue(isset($result[0])); + $this->assertTrue(isset($result[1])); + $annot = $result[0]; + $this->assertTrue($annot instanceof Name); + $this->assertEquals("bar", $annot->foo); + $marker = $result[1]; + $this->assertTrue($marker instanceof Marker); + } + + + public function testAnnotationWithoutConstructor() + { + $parser = $this->createTestParser(); + + + $docblock = <<parse($docblock); + $this->assertEquals(count($result), 1); + $annot = $result[0]; + + $this->assertNotNull($annot); + $this->assertTrue($annot instanceof SomeAnnotationClassNameWithoutConstructor); + + $this->assertNull($annot->name); + $this->assertNotNull($annot->data); + $this->assertEquals($annot->data, "Some data"); + + + + +$docblock = <<parse($docblock); + $this->assertEquals(count($result), 1); + $annot = $result[0]; + + $this->assertNotNull($annot); + $this->assertTrue($annot instanceof SomeAnnotationClassNameWithoutConstructor); + + $this->assertEquals($annot->name, "Some Name"); + $this->assertEquals($annot->data, "Some data"); + + + + +$docblock = <<parse($docblock); + $this->assertEquals(count($result), 1); + $annot = $result[0]; + + $this->assertEquals($annot->data, "Some data"); + $this->assertNull($annot->name); + + + $docblock = <<parse($docblock); + $this->assertEquals(count($result), 1); + $annot = $result[0]; + + $this->assertEquals($annot->name, "Some name"); + $this->assertNull($annot->data); + + $docblock = <<parse($docblock); + $this->assertEquals(count($result), 1); + $annot = $result[0]; + + $this->assertEquals($annot->data, "Some data"); + $this->assertNull($annot->name); + + + + $docblock = <<parse($docblock); + $this->assertEquals(count($result), 1); + $annot = $result[0]; + + $this->assertEquals($annot->name, "Some name"); + $this->assertEquals($annot->data, "Some data"); + + + $docblock = <<parse($docblock); + $this->assertEquals(count($result), 1); + $annot = $result[0]; + + $this->assertEquals($annot->name, "Some name"); + $this->assertEquals($annot->data, "Some data"); + + $docblock = <<parse($docblock); + $this->assertEquals(count($result), 1); + $this->assertTrue($result[0] instanceof SomeAnnotationClassNameWithoutConstructorAndProperties); + } + + public function testAnnotationTarget() + { + + $parser = new DocParser; + $parser->setImports(array( + '__NAMESPACE__' => 'Doctrine\Tests\Common\Annotations\Fixtures', + )); + $class = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithValidAnnotationTarget'); + + + $context = 'class ' . $class->getName(); + $docComment = $class->getDocComment(); + + $parser->setTarget(Target::TARGET_CLASS); + $this->assertNotNull($parser->parse($docComment,$context)); + + + $property = $class->getProperty('foo'); + $docComment = $property->getDocComment(); + $context = 'property ' . $class->getName() . "::\$" . $property->getName(); + + $parser->setTarget(Target::TARGET_PROPERTY); + $this->assertNotNull($parser->parse($docComment,$context)); + + + + $method = $class->getMethod('someFunction'); + $docComment = $property->getDocComment(); + $context = 'method ' . $class->getName() . '::' . $method->getName() . '()'; + + $parser->setTarget(Target::TARGET_METHOD); + $this->assertNotNull($parser->parse($docComment,$context)); + + + try { + $class = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtClass'); + $context = 'class ' . $class->getName(); + $docComment = $class->getDocComment(); + + $parser->setTarget(Target::TARGET_CLASS); + $parser->parse($class->getDocComment(),$context); + + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertNotNull($exc->getMessage()); + } + + + try { + + $class = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtMethod'); + $method = $class->getMethod('functionName'); + $docComment = $method->getDocComment(); + $context = 'method ' . $class->getName() . '::' . $method->getName() . '()'; + + $parser->setTarget(Target::TARGET_METHOD); + $parser->parse($docComment,$context); + + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertNotNull($exc->getMessage()); + } + + + try { + $class = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassWithInvalidAnnotationTargetAtProperty'); + $property = $class->getProperty('foo'); + $docComment = $property->getDocComment(); + $context = 'property ' . $class->getName() . "::\$" . $property->getName(); + + $parser->setTarget(Target::TARGET_PROPERTY); + $parser->parse($docComment,$context); + + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertNotNull($exc->getMessage()); + } + + } + + public function getAnnotationVarTypeProviderValid() + { + //({attribute name}, {attribute value}) + return array( + // mixed type + array('mixed', '"String Value"'), + array('mixed', 'true'), + array('mixed', 'false'), + array('mixed', '1'), + array('mixed', '1.2'), + array('mixed', '@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll'), + + // boolean type + array('boolean', 'true'), + array('boolean', 'false'), + + // alias for internal type boolean + array('bool', 'true'), + array('bool', 'false'), + + // integer type + array('integer', '0'), + array('integer', '1'), + array('integer', '123456789'), + array('integer', '9223372036854775807'), + + // alias for internal type double + array('float', '0.1'), + array('float', '1.2'), + array('float', '123.456'), + + // string type + array('string', '"String Value"'), + array('string', '"true"'), + array('string', '"123"'), + + // array type + array('array', '{@AnnotationExtendsAnnotationTargetAll}'), + array('array', '{@AnnotationExtendsAnnotationTargetAll,@AnnotationExtendsAnnotationTargetAll}'), + + array('arrayOfIntegers', '1'), + array('arrayOfIntegers', '{1}'), + array('arrayOfIntegers', '{1,2,3,4}'), + array('arrayOfAnnotations', '@AnnotationExtendsAnnotationTargetAll'), + array('arrayOfAnnotations', '{@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll}'), + array('arrayOfAnnotations', '{@AnnotationExtendsAnnotationTargetAll, @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll}'), + + // annotation instance + array('annotation', '@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll'), + array('annotation', '@AnnotationExtendsAnnotationTargetAll'), + ); + } + + public function getAnnotationVarTypeProviderInvalid() + { + //({attribute name}, {type declared type}, {attribute value} , {given type or class}) + return array( + // boolean type + array('boolean','boolean','1','integer'), + array('boolean','boolean','1.2','double'), + array('boolean','boolean','"str"','string'), + array('boolean','boolean','{1,2,3}','array'), + array('boolean','boolean','@Name', 'an instance of Doctrine\Tests\Common\Annotations\Name'), + + // alias for internal type boolean + array('bool','bool', '1','integer'), + array('bool','bool', '1.2','double'), + array('bool','bool', '"str"','string'), + array('bool','bool', '{"str"}','array'), + + // integer type + array('integer','integer', 'true','boolean'), + array('integer','integer', 'false','boolean'), + array('integer','integer', '1.2','double'), + array('integer','integer', '"str"','string'), + array('integer','integer', '{"str"}','array'), + array('integer','integer', '{1,2,3,4}','array'), + + // alias for internal type double + array('float','float', 'true','boolean'), + array('float','float', 'false','boolean'), + array('float','float', '123','integer'), + array('float','float', '"str"','string'), + array('float','float', '{"str"}','array'), + array('float','float', '{12.34}','array'), + array('float','float', '{1,2,3}','array'), + + // string type + array('string','string', 'true','boolean'), + array('string','string', 'false','boolean'), + array('string','string', '12','integer'), + array('string','string', '1.2','double'), + array('string','string', '{"str"}','array'), + array('string','string', '{1,2,3,4}','array'), + + // annotation instance + array('annotation','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', 'true','boolean'), + array('annotation','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', 'false','boolean'), + array('annotation','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', '12','integer'), + array('annotation','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', '1.2','double'), + array('annotation','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', '{"str"}','array'), + array('annotation','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', '{1,2,3,4}','array'), + array('annotation','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', '@Name','an instance of Doctrine\Tests\Common\Annotations\Name'), + ); + } + + public function getAnnotationVarTypeArrayProviderInvalid() + { + //({attribute name}, {type declared type}, {attribute value} , {given type or class}) + return array( + array('arrayOfIntegers','integer', 'true','boolean'), + array('arrayOfIntegers','integer', 'false','boolean'), + array('arrayOfIntegers','integer', '{true,true}','boolean'), + array('arrayOfIntegers','integer', '{1,true}','boolean'), + array('arrayOfIntegers','integer', '{1,2,1.2}','double'), + array('arrayOfIntegers','integer', '{1,2,"str"}','string'), + + + array('arrayOfAnnotations','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', 'true','boolean'), + array('arrayOfAnnotations','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', 'false','boolean'), + array('arrayOfAnnotations','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', '{@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll,true}','boolean'), + array('arrayOfAnnotations','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', '{@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll,true}','boolean'), + array('arrayOfAnnotations','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', '{@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll,1.2}','double'), + array('arrayOfAnnotations','Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll', '{@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll,@AnnotationExtendsAnnotationTargetAll,"str"}','string'), + ); + } + + /** + * @dataProvider getAnnotationVarTypeProviderValid + */ + public function testAnnotationWithVarType($attribute, $value) + { + $parser = $this->createTestParser(); + $context = 'property SomeClassName::$invalidProperty.'; + $docblock = sprintf('@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithVarType(%s = %s)',$attribute, $value); + $parser->setTarget(Target::TARGET_PROPERTY); + + $result = $parser->parse($docblock, $context); + + $this->assertTrue(sizeof($result) === 1); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithVarType', $result[0]); + $this->assertNotNull($result[0]->$attribute); + } + + /** + * @dataProvider getAnnotationVarTypeProviderInvalid + */ + public function testAnnotationWithVarTypeError($attribute,$type,$value,$given) + { + $parser = $this->createTestParser(); + $context = 'property SomeClassName::invalidProperty.'; + $docblock = sprintf('@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithVarType(%s = %s)',$attribute, $value); + $parser->setTarget(Target::TARGET_PROPERTY); + + try { + $parser->parse($docblock, $context); + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertContains("[Type Error] Attribute \"$attribute\" of @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithVarType declared on property SomeClassName::invalidProperty. expects a(n) $type, but got $given.", $exc->getMessage()); + } + } + + + /** + * @dataProvider getAnnotationVarTypeArrayProviderInvalid + */ + public function testAnnotationWithVarTypeArrayError($attribute,$type,$value,$given) + { + $parser = $this->createTestParser(); + $context = 'property SomeClassName::invalidProperty.'; + $docblock = sprintf('@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithVarType(%s = %s)',$attribute, $value); + $parser->setTarget(Target::TARGET_PROPERTY); + + try { + $parser->parse($docblock, $context); + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertContains("[Type Error] Attribute \"$attribute\" of @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithVarType declared on property SomeClassName::invalidProperty. expects either a(n) $type, or an array of {$type}s, but got $given.", $exc->getMessage()); + } + } + + /** + * @dataProvider getAnnotationVarTypeProviderValid + */ + public function testAnnotationWithAttributes($attribute, $value) + { + $parser = $this->createTestParser(); + $context = 'property SomeClassName::$invalidProperty.'; + $docblock = sprintf('@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithAttributes(%s = %s)',$attribute, $value); + $parser->setTarget(Target::TARGET_PROPERTY); + + $result = $parser->parse($docblock, $context); + + $this->assertTrue(sizeof($result) === 1); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithAttributes', $result[0]); + $getter = "get".ucfirst($attribute); + $this->assertNotNull($result[0]->$getter()); + } + + /** + * @dataProvider getAnnotationVarTypeProviderInvalid + */ + public function testAnnotationWithAttributesError($attribute,$type,$value,$given) + { + $parser = $this->createTestParser(); + $context = 'property SomeClassName::invalidProperty.'; + $docblock = sprintf('@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithAttributes(%s = %s)',$attribute, $value); + $parser->setTarget(Target::TARGET_PROPERTY); + + try { + $parser->parse($docblock, $context); + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertContains("[Type Error] Attribute \"$attribute\" of @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithAttributes declared on property SomeClassName::invalidProperty. expects a(n) $type, but got $given.", $exc->getMessage()); + } + } + + + /** + * @dataProvider getAnnotationVarTypeArrayProviderInvalid + */ + public function testAnnotationWithAttributesWithVarTypeArrayError($attribute,$type,$value,$given) + { + $parser = $this->createTestParser(); + $context = 'property SomeClassName::invalidProperty.'; + $docblock = sprintf('@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithAttributes(%s = %s)',$attribute, $value); + $parser->setTarget(Target::TARGET_PROPERTY); + + try { + $parser->parse($docblock, $context); + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertContains("[Type Error] Attribute \"$attribute\" of @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithAttributes declared on property SomeClassName::invalidProperty. expects either a(n) $type, or an array of {$type}s, but got $given.", $exc->getMessage()); + } + } + + public function testAnnotationWithRequiredAttributes() + { + $parser = $this->createTestParser(); + $context = 'property SomeClassName::invalidProperty.'; + $parser->setTarget(Target::TARGET_PROPERTY); + + + $docblock = '@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributes("Some Value", annot = @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation)'; + $result = $parser->parse($docblock); + + $this->assertTrue(sizeof($result) === 1); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributes', $result[0]); + $this->assertEquals("Some Value",$result[0]->getValue()); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation', $result[0]->getAnnot()); + + + $docblock = '@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributes("Some Value")'; + try { + $result = $parser->parse($docblock,$context); + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertContains('Attribute "annot" of @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributes declared on property SomeClassName::invalidProperty. expects a(n) Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation. This value should not be null.', $exc->getMessage()); + } + + $docblock = '@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributes(annot = @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation)'; + try { + $result = $parser->parse($docblock,$context); + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertContains('Attribute "value" of @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributes declared on property SomeClassName::invalidProperty. expects a(n) string. This value should not be null.', $exc->getMessage()); + } + + } + + public function testAnnotationWithRequiredAttributesWithoutContructor() + { + $parser = $this->createTestParser(); + $context = 'property SomeClassName::invalidProperty.'; + $parser->setTarget(Target::TARGET_PROPERTY); + + + $docblock = '@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributesWithoutContructor("Some Value", annot = @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation)'; + $result = $parser->parse($docblock); + + $this->assertTrue(sizeof($result) === 1); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributesWithoutContructor', $result[0]); + $this->assertEquals("Some Value", $result[0]->value); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation', $result[0]->annot); + + + $docblock = '@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributesWithoutContructor("Some Value")'; + try { + $result = $parser->parse($docblock,$context); + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertContains('Attribute "annot" of @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributesWithoutContructor declared on property SomeClassName::invalidProperty. expects a(n) Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation. This value should not be null.', $exc->getMessage()); + } + + $docblock = '@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributesWithoutContructor(annot = @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation)'; + try { + $result = $parser->parse($docblock,$context); + $this->fail(); + } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { + $this->assertContains('Attribute "value" of @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithRequiredAttributesWithoutContructor declared on property SomeClassName::invalidProperty. expects a(n) string. This value should not be null.', $exc->getMessage()); + } + + } + + public function getConstantsProvider() + { + $provider[] = array( + '@AnnotationWithConstants(PHP_EOL)', + PHP_EOL + ); + $provider[] = array( + '@AnnotationWithConstants(AnnotationWithConstants::INTEGER)', + AnnotationWithConstants::INTEGER + ); + $provider[] = array( + '@Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithConstants(AnnotationWithConstants::STRING)', + AnnotationWithConstants::STRING + ); + $provider[] = array( + '@AnnotationWithConstants(Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithConstants::FLOAT)', + AnnotationWithConstants::FLOAT + ); + $provider[] = array( + '@AnnotationWithConstants(ClassWithConstants::SOME_VALUE)', + ClassWithConstants::SOME_VALUE + ); + $provider[] = array( + '@AnnotationWithConstants(Doctrine\Tests\Common\Annotations\Fixtures\ClassWithConstants::SOME_VALUE)', + ClassWithConstants::SOME_VALUE + ); + $provider[] = array( + '@AnnotationWithConstants(IntefaceWithConstants::SOME_VALUE)', + IntefaceWithConstants::SOME_VALUE + ); + $provider[] = array( + '@AnnotationWithConstants(\Doctrine\Tests\Common\Annotations\Fixtures\IntefaceWithConstants::SOME_VALUE)', + IntefaceWithConstants::SOME_VALUE + ); + $provider[] = array( + '@AnnotationWithConstants({AnnotationWithConstants::STRING, AnnotationWithConstants::INTEGER, AnnotationWithConstants::FLOAT})', + array(AnnotationWithConstants::STRING, AnnotationWithConstants::INTEGER, AnnotationWithConstants::FLOAT) + ); + $provider[] = array( + '@AnnotationWithConstants({ + AnnotationWithConstants::STRING = AnnotationWithConstants::INTEGER + })', + array(AnnotationWithConstants::STRING => AnnotationWithConstants::INTEGER) + ); + $provider[] = array( + '@AnnotationWithConstants({ + Doctrine\Tests\Common\Annotations\Fixtures\IntefaceWithConstants::SOME_KEY = AnnotationWithConstants::INTEGER + })', + array(IntefaceWithConstants::SOME_KEY => AnnotationWithConstants::INTEGER) + ); + $provider[] = array( + '@AnnotationWithConstants({ + \Doctrine\Tests\Common\Annotations\Fixtures\IntefaceWithConstants::SOME_KEY = AnnotationWithConstants::INTEGER + })', + array(IntefaceWithConstants::SOME_KEY => AnnotationWithConstants::INTEGER) + ); + $provider[] = array( + '@AnnotationWithConstants({ + AnnotationWithConstants::STRING = AnnotationWithConstants::INTEGER, + ClassWithConstants::SOME_KEY = ClassWithConstants::SOME_VALUE, + Doctrine\Tests\Common\Annotations\Fixtures\ClassWithConstants::SOME_KEY = IntefaceWithConstants::SOME_VALUE + })', + array( + AnnotationWithConstants::STRING => AnnotationWithConstants::INTEGER, + ClassWithConstants::SOME_KEY => ClassWithConstants::SOME_VALUE, + ClassWithConstants::SOME_KEY => IntefaceWithConstants::SOME_VALUE + ) + ); + return $provider; + } + + /** + * @dataProvider getConstantsProvider + */ + public function testSupportClassConstants($docblock, $expected) + { + $parser = $this->createTestParser(); + $parser->setImports(array( + 'classwithconstants' => 'Doctrine\Tests\Common\Annotations\Fixtures\ClassWithConstants', + 'intefacewithconstants' => 'Doctrine\Tests\Common\Annotations\Fixtures\IntefaceWithConstants', + 'annotationwithconstants' => 'Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithConstants' + )); + + $result = $parser->parse($docblock); + $this->assertInstanceOf('\Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithConstants', $annotation = $result[0]); + $this->assertEquals($expected, $annotation->value); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage The annotation @SomeAnnotationClassNameWithoutConstructorAndProperties declared on does not accept any values, but got {"value":"Foo"}. + */ + public function testWithoutConstructorWhenIsNotDefaultValue() + { + $parser = $this->createTestParser(); + $docblock = <<setTarget(Target::TARGET_CLASS); + $parser->parse($docblock); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage The annotation @SomeAnnotationClassNameWithoutConstructorAndProperties declared on does not accept any values, but got {"value":"Foo"}. + */ + public function testWithoutConstructorWhenHasNoProperties() + { + $parser = $this->createTestParser(); + $docblock = <<setTarget(Target::TARGET_CLASS); + $parser->parse($docblock); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage Expected namespace separator or identifier, got ')' at position 24 in class @Doctrine\Tests\Common\Annotations\Fixtures\AnnotationWithTargetSyntaxError. + */ + public function testAnnotationTargetSyntaxError() + { + $parser = $this->createTestParser(); + $context = 'class ' . 'SomeClassName'; + $docblock = <<setTarget(Target::TARGET_CLASS); + $parser->parse($docblock,$context); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid Target "Foo". Available targets: [ALL, CLASS, METHOD, PROPERTY, ANNOTATION] + */ + public function testAnnotationWithInvalidTargetDeclarationError() + { + $parser = $this->createTestParser(); + $context = 'class ' . 'SomeClassName'; + $docblock = <<setTarget(Target::TARGET_CLASS); + $parser->parse($docblock,$context); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage @Target expects either a string value, or an array of strings, "NULL" given. + */ + public function testAnnotationWithTargetEmptyError() + { + $parser = $this->createTestParser(); + $context = 'class ' . 'SomeClassName'; + $docblock = <<setTarget(Target::TARGET_CLASS); + $parser->parse($docblock,$context); + } + + /** + * @group DDC-575 + */ + public function testRegressionDDC575() + { + $parser = $this->createTestParser(); + + $docblock = <<parse($docblock); + + $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Name", $result[0]); + + $docblock = <<parse($docblock); + + $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Name", $result[0]); + } + + /** + * @group DDC-77 + */ + public function testAnnotationWithoutClassIsIgnoredWithoutWarning() + { + $parser = new DocParser(); + $parser->setIgnoreNotImportedAnnotations(true); + $result = $parser->parse("@param"); + + $this->assertEquals(0, count($result)); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage Expected PlainValue, got ''' at position 10. + */ + public function testAnnotationDontAcceptSingleQuotes() + { + $parser = $this->createTestParser(); + $parser->parse("@Name(foo='bar')"); + } + + /** + * @group DCOM-41 + */ + public function testAnnotationDoesntThrowExceptionWhenAtSignIsNotFollowedByIdentifier() + { + $parser = new DocParser(); + $result = $parser->parse("'@'"); + + $this->assertEquals(0, count($result)); + } + + /** + * @group DCOM-41 + * @expectedException Doctrine\Common\Annotations\AnnotationException + */ + public function testAnnotationThrowsExceptionWhenAtSignIsNotFollowedByIdentifierInNestedAnnotation() + { + $parser = new DocParser(); + $result = $parser->parse("@Doctrine\Tests\Common\Annotations\Name(@')"); + } + + /** + * @group DCOM-56 + */ + public function testAutoloadAnnotation() + { + $this->assertFalse(class_exists('Doctrine\Tests\Common\Annotations\Fixture\Annotation\Autoload', false), 'Pre-condition: Doctrine\Tests\Common\Annotations\Fixture\Annotation\Autoload not allowed to be loaded.'); + + $parser = new DocParser(); + + AnnotationRegistry::registerAutoloadNamespace('Doctrine\Tests\Common\Annotations\Fixtures\Annotation', __DIR__ . '/../../../../'); + + $parser->setImports(array( + 'autoload' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Autoload', + )); + $annotations = $parser->parse('@Autoload'); + + $this->assertEquals(1, count($annotations)); + $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Autoload', $annotations[0]); + } + + public function createTestParser() + { + $parser = new DocParser(); + $parser->setIgnoreNotImportedAnnotations(true); + $parser->setImports(array( + 'name' => 'Doctrine\Tests\Common\Annotations\Name', + '__NAMESPACE__' => 'Doctrine\Tests\Common\Annotations', + )); + + return $parser; + } + + /** + * @group DDC-78 + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage Expected PlainValue, got ''' at position 10 in class \Doctrine\Tests\Common\Annotations\Name + */ + public function testSyntaxErrorWithContextDescription() + { + $parser = $this->createTestParser(); + $parser->parse("@Name(foo='bar')", "class \Doctrine\Tests\Common\Annotations\Name"); + } + + /** + * @group DDC-183 + */ + public function testSyntaxErrorWithUnknownCharacters() + { + $docblock = <<setInput(trim($docblock, '/ *')); + //var_dump($lexer); + + try { + $parser = $this->createTestParser(); + $result = $parser->parse($docblock); + } catch (Exception $e) { + $this->fail($e->getMessage()); + } + } + + /** + * @group DCOM-14 + */ + public function testIgnorePHPDocThrowTag() + { + $docblock = <<createTestParser(); + $result = $parser->parse($docblock); + } catch (Exception $e) { + $this->fail($e->getMessage()); + } + } + + /** + * @group DCOM-38 + */ + public function testCastInt() + { + $parser = $this->createTestParser(); + + $result = $parser->parse("@Name(foo=1234)"); + $annot = $result[0]; + $this->assertInternalType('int', $annot->foo); + } + + /** + * @group DCOM-38 + */ + public function testCastNegativeInt() + { + $parser = $this->createTestParser(); + + $result = $parser->parse("@Name(foo=-1234)"); + $annot = $result[0]; + $this->assertInternalType('int', $annot->foo); + } + + /** + * @group DCOM-38 + */ + public function testCastFloat() + { + $parser = $this->createTestParser(); + + $result = $parser->parse("@Name(foo=1234.345)"); + $annot = $result[0]; + $this->assertInternalType('float', $annot->foo); + } + + /** + * @group DCOM-38 + */ + public function testCastNegativeFloat() + { + $parser = $this->createTestParser(); + + $result = $parser->parse("@Name(foo=-1234.345)"); + $annot = $result[0]; + $this->assertInternalType('float', $annot->foo); + + $result = $parser->parse("@Marker(-1234.345)"); + $annot = $result[0]; + $this->assertInternalType('float', $annot->value); + } + + public function testReservedKeywordsInAnnotations() + { + $parser = $this->createTestParser(); + + $result = $parser->parse('@Doctrine\Tests\Common\Annotations\True'); + $this->assertTrue($result[0] instanceof True); + $result = $parser->parse('@Doctrine\Tests\Common\Annotations\False'); + $this->assertTrue($result[0] instanceof False); + $result = $parser->parse('@Doctrine\Tests\Common\Annotations\Null'); + $this->assertTrue($result[0] instanceof Null); + + $result = $parser->parse('@True'); + $this->assertTrue($result[0] instanceof True); + $result = $parser->parse('@False'); + $this->assertTrue($result[0] instanceof False); + $result = $parser->parse('@Null'); + $this->assertTrue($result[0] instanceof Null); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage [Creation Error] The annotation @SomeAnnotationClassNameWithoutConstructor declared on some class does not have a property named "invalidaProperty". Available properties: data, name + */ + public function testSetValuesExeption() + { + $docblock = <<createTestParser()->parse($docblock, 'some class'); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage [Syntax Error] Expected Doctrine\Common\Annotations\DocLexer::T_IDENTIFIER or Doctrine\Common\Annotations\DocLexer::T_TRUE or Doctrine\Common\Annotations\DocLexer::T_FALSE or Doctrine\Common\Annotations\DocLexer::T_NULL, got '3.42' at position 5. + */ + public function testInvalidIdentifierInAnnotation() + { + $parser = $this->createTestParser(); + $parser->parse('@Foo\3.42'); + } + + public function testTrailingCommaIsAllowed() + { + $parser = $this->createTestParser(); + + $annots = $parser->parse('@Name({ + "Foo", + "Bar", + })'); + $this->assertEquals(1, count($annots)); + $this->assertEquals(array('Foo', 'Bar'), $annots[0]->value); + } + + public function testDefaultAnnotationValueIsNotOverwritten() + { + $parser = $this->createTestParser(); + + $annots = $parser->parse('@Doctrine\Tests\Common\Annotations\Fixtures\Annotation\AnnotWithDefaultValue'); + $this->assertEquals(1, count($annots)); + $this->assertEquals('bar', $annots[0]->foo); + } + + public function testArrayWithColon() + { + $parser = $this->createTestParser(); + + $annots = $parser->parse('@Name({"foo": "bar"})'); + $this->assertEquals(1, count($annots)); + $this->assertEquals(array('foo' => 'bar'), $annots[0]->value); + } + + /** + * @expectedException Doctrine\Common\Annotations\AnnotationException + * @expectedExceptionMessage [Semantical Error] Couldn't find constant foo. + */ + public function testInvalidContantName() + { + $parser = $this->createTestParser(); + $parser->parse('@Name(foo: "bar")'); + } +} + +/** @Annotation */ +class SomeAnnotationClassNameWithoutConstructor +{ + public $data; + public $name; +} + +/** @Annotation */ +class SomeAnnotationWithConstructorWithoutParams +{ + function __construct() + { + $this->data = "Some data"; + } + public $data; + public $name; +} + +/** @Annotation */ +class SomeAnnotationClassNameWithoutConstructorAndProperties{} + +/** + * @Annotation + * @Target("Foo") + */ +class AnnotationWithInvalidTargetDeclaration{} + +/** + * @Annotation + * @Target + */ +class AnnotationWithTargetEmpty{} + +/** @Annotation */ +class AnnotationExtendsAnnotationTargetAll extends \Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll +{ +} + +/** @Annotation */ +class Name extends \Doctrine\Common\Annotations\Annotation { + public $foo; +} + +/** @Annotation */ +class Marker { + public $value; +} + +/** @Annotation */ +class True {} + +/** @Annotation */ +class False {} + +/** @Annotation */ +class Null {} + +namespace Doctrine\Tests\Common\Annotations\FooBar; + +/** @Annotation */ +class Name extends \Doctrine\Common\Annotations\Annotation { +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DummyClass.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DummyClass.php new file mode 100644 index 0000000..17223f6 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/DummyClass.php @@ -0,0 +1,48 @@ +cacheDir = sys_get_temp_dir() . "/annotations_". uniqid(); + @mkdir($this->cacheDir); + return new FileCacheReader(new AnnotationReader(), $this->cacheDir); + } + + public function tearDown() + { + foreach (glob($this->cacheDir.'/*.php') AS $file) { + unlink($file); + } + rmdir($this->cacheDir); + } + + /** + * @group DCOM-81 + */ + public function testAttemptToCreateAnnotationCacheDir() + { + $this->cacheDir = sys_get_temp_dir() . "/not_existed_dir_". uniqid(); + + $this->assertFalse(is_dir($this->cacheDir)); + + $cache = new FileCacheReader(new AnnotationReader(), $this->cacheDir); + + $this->assertTrue(is_dir($this->cacheDir)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/AnnotWithDefaultValue.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/AnnotWithDefaultValue.php new file mode 100644 index 0000000..44108e1 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/AnnotWithDefaultValue.php @@ -0,0 +1,10 @@ +roles = $values['value']; + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Template.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Template.php new file mode 100644 index 0000000..b507e60 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Template.php @@ -0,0 +1,14 @@ +name = isset($values['value']) ? $values['value'] : null; + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Version.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Version.php new file mode 100644 index 0000000..09ef031 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/Annotation/Version.php @@ -0,0 +1,11 @@ +"), + @Attribute("annotation", type = "Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll"), + @Attribute("arrayOfAnnotations", type = "array"), + }) + */ +final class AnnotationWithAttributes +{ + + public final function __construct(array $data) + { + foreach ($data as $key => $value) { + $this->$key = $value; + } + } + + private $mixed; + private $boolean; + private $bool; + private $float; + private $string; + private $integer; + private $array; + private $annotation; + private $arrayOfIntegers; + private $arrayOfAnnotations; + + /** + * @return mixed + */ + public function getMixed() + { + return $this->mixed; + } + + /** + * @return boolean + */ + public function getBoolean() + { + return $this->boolean; + } + + /** + * @return bool + */ + public function getBool() + { + return $this->bool; + } + + /** + * @return float + */ + public function getFloat() + { + return $this->float; + } + + /** + * @return string + */ + public function getString() + { + return $this->string; + } + + public function getInteger() + { + return $this->integer; + } + + /** + * @return array + */ + public function getArray() + { + return $this->array; + } + + /** + * @return Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAll + */ + public function getAnnotation() + { + return $this->annotation; + } + + /** + * @return array + */ + public function getArrayOfIntegers() + { + return $this->arrayOfIntegers; + } + + /** + * @return array + */ + public function getArrayOfAnnotations() + { + return $this->arrayOfAnnotations; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithConstants.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithConstants.php new file mode 100644 index 0000000..9c94558 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithConstants.php @@ -0,0 +1,20 @@ + $value) { + $this->$key = $value; + } + } + + /** + * @var string + */ + private $value; + + /** + * + * @var Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation + */ + private $annot; + + /** + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * @return Doctrine\Tests\Common\Annotations\Fixtures\AnnotationTargetAnnotation + */ + public function getAnnot() + { + return $this->annot; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithRequiredAttributesWithoutContructor.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithRequiredAttributesWithoutContructor.php new file mode 100644 index 0000000..bf458ee --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/AnnotationWithRequiredAttributesWithoutContructor.php @@ -0,0 +1,24 @@ + + */ + public $arrayOfIntegers; + + /** + * @var array + */ + public $arrayOfAnnotations; + +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassDDC1660.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassDDC1660.php new file mode 100644 index 0000000..4e652e1 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassDDC1660.php @@ -0,0 +1,30 @@ +events->filter(function ($item) use ($year, $month, $day) { + $leftDate = new \DateTime($year.'-'.$month.'-'.$day.' 00:00'); + $rigthDate = new \DateTime($year.'-'.$month.'-'.$day.' +1 day 00:00'); + return ( ( $leftDate <= $item->getDateStart() ) && ( $item->getDateStart() < $rigthDate ) ); + + } + ); + return $extractEvents; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithConstants.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithConstants.php new file mode 100644 index 0000000..055e245 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/ClassWithConstants.php @@ -0,0 +1,10 @@ + + */ +class Controller +{ + /** + * @Route("/", name="_demo") + * @Template() + */ + public function indexAction() + { + return array(); + } + + /** + * @Route("/hello/{name}", name="_demo_hello") + * @Template() + */ + public function helloAction($name) + { + return array('name' => $name); + } + + /** + * @Route("/contact", name="_demo_contact") + * @Template() + */ + public function contactAction() + { + $form = ContactForm::create($this->get('form.context'), 'contact'); + + $form->bind($this->container->get('request'), $form); + if ($form->isValid()) { + $form->send($this->get('mailer')); + + $this->get('session')->setFlash('notice', 'Message sent!'); + + return new RedirectResponse($this->generateUrl('_demo')); + } + + return array('form' => $form); + } + + /** + * Creates the ACL for the passed object identity + * + * @param ObjectIdentityInterface $oid + * @return void + */ + private function createObjectIdentity(ObjectIdentityInterface $oid) + { + $classId = $this->createOrRetrieveClassId($oid->getType()); + + $this->connection->executeQuery($this->getInsertObjectIdentitySql($oid->getIdentifier(), $classId, true)); + } + + /** + * Returns the primary key for the passed class type. + * + * If the type does not yet exist in the database, it will be created. + * + * @param string $classType + * @return integer + */ + private function createOrRetrieveClassId($classType) + { + if (false !== $id = $this->connection->executeQuery($this->getSelectClassIdSql($classType))->fetchColumn()) { + return $id; + } + + $this->connection->executeQuery($this->getInsertClassSql($classType)); + + return $this->connection->executeQuery($this->getSelectClassIdSql($classType))->fetchColumn(); + } + + /** + * Returns the primary key for the passed security identity. + * + * If the security identity does not yet exist in the database, it will be + * created. + * + * @param SecurityIdentityInterface $sid + * @return integer + */ + private function createOrRetrieveSecurityIdentityId(SecurityIdentityInterface $sid) + { + if (false !== $id = $this->connection->executeQuery($this->getSelectSecurityIdentityIdSql($sid))->fetchColumn()) { + return $id; + } + + $this->connection->executeQuery($this->getInsertSecurityIdentitySql($sid)); + + return $this->connection->executeQuery($this->getSelectSecurityIdentityIdSql($sid))->fetchColumn(); + } + + /** + * Deletes all ACEs for the given object identity primary key. + * + * @param integer $oidPK + * @return void + */ + private function deleteAccessControlEntries($oidPK) + { + $this->connection->executeQuery($this->getDeleteAccessControlEntriesSql($oidPK)); + } + + /** + * Deletes the object identity from the database. + * + * @param integer $pk + * @return void + */ + private function deleteObjectIdentity($pk) + { + $this->connection->executeQuery($this->getDeleteObjectIdentitySql($pk)); + } + + /** + * Deletes all entries from the relations table from the database. + * + * @param integer $pk + * @return void + */ + private function deleteObjectIdentityRelations($pk) + { + $this->connection->executeQuery($this->getDeleteObjectIdentityRelationsSql($pk)); + } + + /** + * This regenerates the ancestor table which is used for fast read access. + * + * @param AclInterface $acl + * @return void + */ + private function regenerateAncestorRelations(AclInterface $acl) + { + $pk = $acl->getId(); + $this->connection->executeQuery($this->getDeleteObjectIdentityRelationsSql($pk)); + $this->connection->executeQuery($this->getInsertObjectIdentityRelationSql($pk, $pk)); + + $parentAcl = $acl->getParentAcl(); + while (null !== $parentAcl) { + $this->connection->executeQuery($this->getInsertObjectIdentityRelationSql($pk, $parentAcl->getId())); + + $parentAcl = $parentAcl->getParentAcl(); + } + } + + /** + * This processes changes on an ACE related property (classFieldAces, or objectFieldAces). + * + * @param string $name + * @param array $changes + * @return void + */ + private function updateFieldAceProperty($name, array $changes) + { + $sids = new \SplObjectStorage(); + $classIds = new \SplObjectStorage(); + $currentIds = array(); + foreach ($changes[1] as $field => $new) { + for ($i=0,$c=count($new); $i<$c; $i++) { + $ace = $new[$i]; + + if (null === $ace->getId()) { + if ($sids->contains($ace->getSecurityIdentity())) { + $sid = $sids->offsetGet($ace->getSecurityIdentity()); + } else { + $sid = $this->createOrRetrieveSecurityIdentityId($ace->getSecurityIdentity()); + } + + $oid = $ace->getAcl()->getObjectIdentity(); + if ($classIds->contains($oid)) { + $classId = $classIds->offsetGet($oid); + } else { + $classId = $this->createOrRetrieveClassId($oid->getType()); + } + + $objectIdentityId = $name === 'classFieldAces' ? null : $ace->getAcl()->getId(); + + $this->connection->executeQuery($this->getInsertAccessControlEntrySql($classId, $objectIdentityId, $field, $i, $sid, $ace->getStrategy(), $ace->getMask(), $ace->isGranting(), $ace->isAuditSuccess(), $ace->isAuditFailure())); + $aceId = $this->connection->executeQuery($this->getSelectAccessControlEntryIdSql($classId, $objectIdentityId, $field, $i))->fetchColumn(); + $this->loadedAces[$aceId] = $ace; + + $aceIdProperty = new \ReflectionProperty('Symfony\Component\Security\Acl\Domain\Entry', 'id'); + $aceIdProperty->setAccessible(true); + $aceIdProperty->setValue($ace, intval($aceId)); + } else { + $currentIds[$ace->getId()] = true; + } + } + } + + foreach ($changes[0] as $old) { + for ($i=0,$c=count($old); $i<$c; $i++) { + $ace = $old[$i]; + + if (!isset($currentIds[$ace->getId()])) { + $this->connection->executeQuery($this->getDeleteAccessControlEntrySql($ace->getId())); + unset($this->loadedAces[$ace->getId()]); + } + } + } + } + + /** + * This processes changes on an ACE related property (classAces, or objectAces). + * + * @param string $name + * @param array $changes + * @return void + */ + private function updateAceProperty($name, array $changes) + { + list($old, $new) = $changes; + + $sids = new \SplObjectStorage(); + $classIds = new \SplObjectStorage(); + $currentIds = array(); + for ($i=0,$c=count($new); $i<$c; $i++) { + $ace = $new[$i]; + + if (null === $ace->getId()) { + if ($sids->contains($ace->getSecurityIdentity())) { + $sid = $sids->offsetGet($ace->getSecurityIdentity()); + } else { + $sid = $this->createOrRetrieveSecurityIdentityId($ace->getSecurityIdentity()); + } + + $oid = $ace->getAcl()->getObjectIdentity(); + if ($classIds->contains($oid)) { + $classId = $classIds->offsetGet($oid); + } else { + $classId = $this->createOrRetrieveClassId($oid->getType()); + } + + $objectIdentityId = $name === 'classAces' ? null : $ace->getAcl()->getId(); + + $this->connection->executeQuery($this->getInsertAccessControlEntrySql($classId, $objectIdentityId, null, $i, $sid, $ace->getStrategy(), $ace->getMask(), $ace->isGranting(), $ace->isAuditSuccess(), $ace->isAuditFailure())); + $aceId = $this->connection->executeQuery($this->getSelectAccessControlEntryIdSql($classId, $objectIdentityId, null, $i))->fetchColumn(); + $this->loadedAces[$aceId] = $ace; + + $aceIdProperty = new \ReflectionProperty($ace, 'id'); + $aceIdProperty->setAccessible(true); + $aceIdProperty->setValue($ace, intval($aceId)); + } else { + $currentIds[$ace->getId()] = true; + } + } + + for ($i=0,$c=count($old); $i<$c; $i++) { + $ace = $old[$i]; + + if (!isset($currentIds[$ace->getId()])) { + $this->connection->executeQuery($this->getDeleteAccessControlEntrySql($ace->getId())); + unset($this->loadedAces[$ace->getId()]); + } + } + } + + /** + * Persists the changes which were made to ACEs to the database. + * + * @param \SplObjectStorage $aces + * @return void + */ + private function updateAces(\SplObjectStorage $aces) + { + foreach ($aces as $ace) { + $propertyChanges = $aces->offsetGet($ace); + $sets = array(); + + if (isset($propertyChanges['mask'])) { + $sets[] = sprintf('mask = %d', $propertyChanges['mask'][1]); + } + if (isset($propertyChanges['strategy'])) { + $sets[] = sprintf('granting_strategy = %s', $this->connection->quote($propertyChanges['strategy'])); + } + if (isset($propertyChanges['aceOrder'])) { + $sets[] = sprintf('ace_order = %d', $propertyChanges['aceOrder'][1]); + } + if (isset($propertyChanges['auditSuccess'])) { + $sets[] = sprintf('audit_success = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditSuccess'][1])); + } + if (isset($propertyChanges['auditFailure'])) { + $sets[] = sprintf('audit_failure = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditFailure'][1])); + } + + $this->connection->executeQuery($this->getUpdateAccessControlEntrySql($ace->getId(), $sets)); + } + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/DifferentNamespacesPerFileWithClassAsFirst.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/DifferentNamespacesPerFileWithClassAsFirst.php new file mode 100644 index 0000000..bda2cc2 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/DifferentNamespacesPerFileWithClassAsFirst.php @@ -0,0 +1,15 @@ +test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test2() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test3() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test4() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test5() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test6() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test7() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test8() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + + } + + public function test9() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test10() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test11() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test12() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test13() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test14() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test15() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test16() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test17() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + + } + + public function test18() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test19() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test20() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test21() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test22() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test23() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test24() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test25() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test26() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test27() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + + } + + public function test28() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test29() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test30() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test31() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test32() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test33() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test34() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test35() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test36() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test37() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + + } + + public function test38() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test39() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NoAnnotation.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NoAnnotation.php new file mode 100644 index 0000000..1dae104 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/NoAnnotation.php @@ -0,0 +1,5 @@ +test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test2() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test3() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test4() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test5() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test6() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test7() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test8() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + + } + + public function test9() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test10() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test11() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test12() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test13() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test14() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test15() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test16() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test17() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + + } + + public function test18() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test19() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test20() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test21() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test22() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test23() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test24() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test25() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test26() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test27() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + + } + + public function test28() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test29() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test30() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test31() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test32() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test33() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test34() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test35() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test36() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test37() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + + } + + public function test38() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } + + public function test39() + { + echo $this->test1; + echo $this->test2; + echo $this->test3; + $array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + foreach ($array as $key => $value) { + echo $key . ' => ' . $value; + } + + $val = (string)self::TEST1; + $val .= (string)self::TEST2; + $val .= (string)self::TEST3; + $val .= (string)self::TEST4; + $val .= (string)self::TEST5; + $val .= (string)self::TEST6; + $val .= (string)self::TEST7; + $val .= (string)self::TEST8; + $val .= (string)self::TEST9; + + strtolower($val); + + return $val; + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/TestInterface.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/TestInterface.php new file mode 100644 index 0000000..58c5e6a --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Fixtures/TestInterface.php @@ -0,0 +1,13 @@ +getMethod(); + + $time = microtime(true); + for ($i=0,$c=500; $i<$c; $i++) { + $reader->getMethodAnnotations($method); + } + $time = microtime(true) - $time; + + $this->printResults('cached reader (in-memory)', $time, $c); + } + + /** + * @group performance + */ + public function testCachedReadPerformanceWithFileCache() + { + $method = $this->getMethod(); + + // prime cache + $reader = new FileCacheReader(new AnnotationReader(), sys_get_temp_dir()); + $reader->getMethodAnnotations($method); + + $time = microtime(true); + for ($i=0,$c=500; $i<$c; $i++) { + $reader = new FileCacheReader(new AnnotationReader(), sys_get_temp_dir()); + $reader->getMethodAnnotations($method); + clearstatcache(); + } + $time = microtime(true) - $time; + + $this->printResults('cached reader (file)', $time, $c); + } + + /** + * @group performance + */ + public function testReadPerformance() + { + $method = $this->getMethod(); + + $time = microtime(true); + for ($i=0,$c=150; $i<$c; $i++) { + $reader = new AnnotationReader(); + $reader->getMethodAnnotations($method); + } + $time = microtime(true) - $time; + + $this->printResults('reader', $time, $c); + } + + /** + * @group performance + */ + public function testDocParsePerformance() + { + $imports = array( + 'ignorephpdoc' => 'Annotations\Annotation\IgnorePhpDoc', + 'ignoreannotation' => 'Annotations\Annotation\IgnoreAnnotation', + 'route' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Route', + 'template' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Template', + '__NAMESPACE__' => 'Doctrine\Tests\Common\Annotations\Fixtures', + ); + $ignored = array( + 'access', 'author', 'copyright', 'deprecated', 'example', 'ignore', + 'internal', 'link', 'see', 'since', 'tutorial', 'version', 'package', + 'subpackage', 'name', 'global', 'param', 'return', 'staticvar', + 'static', 'var', 'throws', 'inheritdoc', + ); + + $method = $this->getMethod(); + $methodComment = $method->getDocComment(); + $classComment = $method->getDeclaringClass()->getDocComment(); + + $time = microtime(true); + for ($i=0,$c=200; $i<$c; $i++) { + $parser = new DocParser(); + $parser->setImports($imports); + $parser->setIgnoredAnnotationNames($ignored); + $parser->setIgnoreNotImportedAnnotations(true); + + $parser->parse($methodComment); + $parser->parse($classComment); + } + $time = microtime(true) - $time; + + $this->printResults('doc-parser', $time, $c); + } + + /** + * @group performance + */ + public function testDocLexerPerformance() + { + $method = $this->getMethod(); + $methodComment = $method->getDocComment(); + $classComment = $method->getDeclaringClass()->getDocComment(); + + $time = microtime(true); + for ($i=0,$c=500; $i<$c; $i++) { + $lexer = new DocLexer(); + $lexer->setInput($methodComment); + $lexer->setInput($classComment); + } + $time = microtime(true) - $time; + + $this->printResults('doc-lexer', $time, $c); + } + + /** + * @group performance + */ + public function testPhpParserPerformanceWithShortCut() + { + $class = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\NamespacedSingleClassLOC1000'); + + $time = microtime(true); + for ($i=0,$c=500; $i<$c; $i++) { + $parser = new PhpParser(); + $parser->parseClass($class); + } + $time = microtime(true) - $time; + + $this->printResults('doc-parser-with-short-cut', $time, $c); + } + + /** + * @group performance + */ + public function testPhpParserPerformanceWithoutShortCut() + { + $class = new \ReflectionClass('SingleClassLOC1000'); + + $time = microtime(true); + for ($i=0,$c=500; $i<$c; $i++) { + $parser = new PhpParser(); + $parser->parseClass($class); + } + $time = microtime(true) - $time; + + $this->printResults('doc-parser-without-short-cut', $time, $c); + } + + private function getMethod() + { + return new \ReflectionMethod('Doctrine\Tests\Common\Annotations\Fixtures\Controller', 'helloAction'); + } + + private function printResults($test, $time, $iterations) + { + if (0 == $iterations) { + throw new \InvalidArgumentException('$iterations cannot be zero.'); + } + + $title = $test." results:\n"; + $iterationsText = sprintf("Iterations: %d\n", $iterations); + $totalTime = sprintf("Total Time: %.3f s\n", $time); + $iterationTime = sprintf("Time per iteration: %.3f ms\n", $time/$iterations * 1000); + + $max = max(strlen($title), strlen($iterationTime)) - 1; + + echo "\n".str_repeat('-', $max)."\n"; + echo $title; + echo str_repeat('=', $max)."\n"; + echo $iterationsText; + echo $totalTime; + echo $iterationTime; + echo str_repeat('-', $max)."\n"; + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/PhpParserTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/PhpParserTest.php new file mode 100644 index 0000000..cf81116 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/PhpParserTest.php @@ -0,0 +1,194 @@ +assertEquals(array( + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'secure' => __NAMESPACE__ . '\Fixtures\Annotation\Secure', + ), $parser->parseClass($class)); + } + + public function testParseClassWithMultipleImportsInUseStatement() + { + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\MultipleImportsInUseStatement'); + $parser = new PhpParser(); + + $this->assertEquals(array( + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'secure' => __NAMESPACE__ . '\Fixtures\Annotation\Secure', + ), $parser->parseClass($class)); + } + + public function testParseClassWhenNotUserDefined() + { + $parser = new PhpParser(); + $this->assertEquals(array(), $parser->parseClass(new \ReflectionClass('\stdClass'))); + } + + public function testParseClassWhenClassIsNotNamespaced() + { + $parser = new PhpParser(); + $class = new ReflectionClass('\AnnotationsTestsFixturesNonNamespacedClass'); + + $this->assertEquals(array( + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'template' => __NAMESPACE__ . '\Fixtures\Annotation\Template', + ), $parser->parseClass($class)); + } + + public function testParseClassWhenClassIsInterface() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\TestInterface'); + + $this->assertEquals(array( + 'secure' => __NAMESPACE__ . '\Fixtures\Annotation\Secure', + ), $parser->parseClass($class)); + } + + public function testClassWithFullyQualifiedUseStatements() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\ClassWithFullyQualifiedUseStatements'); + + $this->assertEquals(array( + 'secure' => '\\' . __NAMESPACE__ . '\Fixtures\Annotation\Secure', + 'route' => '\\' . __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'template' => '\\' . __NAMESPACE__ . '\Fixtures\Annotation\Template', + ), $parser->parseClass($class)); + } + + public function testNamespaceAndClassCommentedOut() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\NamespaceAndClassCommentedOut'); + + $this->assertEquals(array( + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'template' => __NAMESPACE__ . '\Fixtures\Annotation\Template', + ), $parser->parseClass($class)); + } + + public function testEqualNamespacesPerFileWithClassAsFirst() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\EqualNamespacesPerFileWithClassAsFirst'); + + $this->assertEquals(array( + 'secure' => __NAMESPACE__ . '\Fixtures\Annotation\Secure', + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + ), $parser->parseClass($class)); + } + + public function testEqualNamespacesPerFileWithClassAsLast() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\EqualNamespacesPerFileWithClassAsLast'); + + $this->assertEquals(array( + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'template' => __NAMESPACE__ . '\Fixtures\Annotation\Template', + ), $parser->parseClass($class)); + } + + public function testDifferentNamespacesPerFileWithClassAsFirst() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\DifferentNamespacesPerFileWithClassAsFirst'); + + $this->assertEquals(array( + 'secure' => __NAMESPACE__ . '\Fixtures\Annotation\Secure', + ), $parser->parseClass($class)); + } + + public function testDifferentNamespacesPerFileWithClassAsLast() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\DifferentNamespacesPerFileWithClassAsLast'); + + $this->assertEquals(array( + 'template' => __NAMESPACE__ . '\Fixtures\Annotation\Template', + ), $parser->parseClass($class)); + } + + public function testGlobalNamespacesPerFileWithClassAsFirst() + { + $parser = new PhpParser(); + $class = new \ReflectionClass('\GlobalNamespacesPerFileWithClassAsFirst'); + + $this->assertEquals(array( + 'secure' => __NAMESPACE__ . '\Fixtures\Annotation\Secure', + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + ), $parser->parseClass($class)); + } + + public function testGlobalNamespacesPerFileWithClassAsLast() + { + $parser = new PhpParser(); + $class = new ReflectionClass('\GlobalNamespacesPerFileWithClassAsLast'); + + $this->assertEquals(array( + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'template' => __NAMESPACE__ . '\Fixtures\Annotation\Template', + ), $parser->parseClass($class)); + } + + public function testNamespaceWithClosureDeclaration() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\NamespaceWithClosureDeclaration'); + + $this->assertEquals(array( + 'secure' => __NAMESPACE__ . '\Fixtures\Annotation\Secure', + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'template' => __NAMESPACE__ . '\Fixtures\Annotation\Template', + ), $parser->parseClass($class)); + } + + public function testIfPointerResetsOnMultipleParsingTries() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\NamespaceWithClosureDeclaration'); + + $this->assertEquals(array( + 'secure' => __NAMESPACE__ . '\Fixtures\Annotation\Secure', + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'template' => __NAMESPACE__ . '\Fixtures\Annotation\Template', + ), $parser->parseClass($class)); + + $this->assertEquals(array( + 'secure' => __NAMESPACE__ . '\Fixtures\Annotation\Secure', + 'route' => __NAMESPACE__ . '\Fixtures\Annotation\Route', + 'template' => __NAMESPACE__ . '\Fixtures\Annotation\Template', + ), $parser->parseClass($class)); + } + + /** + * @group DCOM-97 + * @group regression + */ + public function testClassWithClosure() + { + $parser = new PhpParser(); + $class = new ReflectionClass(__NAMESPACE__ . '\Fixtures\ClassWithClosure'); + + $this->assertEquals(array( + 'annotationtargetall' => __NAMESPACE__ . '\Fixtures\AnnotationTargetAll', + 'annotationtargetannotation' => __NAMESPACE__ . '\Fixtures\AnnotationTargetAnnotation', + ), $parser->parseClass($class)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/SimpleAnnotationReaderTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/SimpleAnnotationReaderTest.php new file mode 100644 index 0000000..376539f --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/SimpleAnnotationReaderTest.php @@ -0,0 +1,97 @@ +getReader(); + $class = new \ReflectionClass('Doctrine\Tests\Common\Annotations\Fixtures\ClassDDC1660'); + + $this->assertTrue(class_exists('Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Version')); + $this->assertCount(1, $reader->getClassAnnotations($class)); + $this->assertCount(1, $reader->getMethodAnnotations($class->getMethod('bar'))); + $this->assertCount(1, $reader->getPropertyAnnotations($class->getProperty('foo'))); + } + + protected function getReader() + { + $reader = new SimpleAnnotationReader(); + $reader->addNamespace(__NAMESPACE__); + $reader->addNamespace(__NAMESPACE__ . '\Fixtures'); + $reader->addNamespace(__NAMESPACE__ . '\Fixtures\Annotation'); + + return $reader; + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM55Test.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM55Test.php new file mode 100644 index 0000000..a7b9e2f --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM55Test.php @@ -0,0 +1,65 @@ +getClassAnnotations($class); + } + + public function testAnnotation() + { + $class = new \ReflectionClass(__NAMESPACE__ . '\\DCOM55Consumer'); + $reader = new \Doctrine\Common\Annotations\AnnotationReader(); + $annots = $reader->getClassAnnotations($class); + + $this->assertEquals(1, count($annots)); + $this->assertInstanceOf(__NAMESPACE__.'\\DCOM55Annotation', $annots[0]); + } + + public function testParseAnnotationDocblocks() + { + $class = new \ReflectionClass(__NAMESPACE__ . '\\DCOM55Annotation'); + $reader = new \Doctrine\Common\Annotations\AnnotationReader(); + $annots = $reader->getClassAnnotations($class); + + $this->assertEquals(0, count($annots)); + } +} + +/** + * @Controller + */ +class Dummy +{ + +} + +/** + * @Annotation + */ +class DCOM55Annotation +{ + +} + +/** + * @DCOM55Annotation + */ +class DCOM55Consumer +{ + +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM58Entity.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM58Entity.php new file mode 100644 index 0000000..708bcc9 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM58Entity.php @@ -0,0 +1,8 @@ +getClassAnnotations(new \ReflectionClass(__NAMESPACE__."\MappedClass")); + + foreach ($result as $annot) { + $classAnnotations[get_class($annot)] = $annot; + } + + $this->assertTrue(!isset($classAnnotations['']), 'Class "xxx" is not a valid entity or mapped super class.'); + } + + public function testIssueGlobalNamespace() + { + $docblock = "@Entity"; + $parser = new \Doctrine\Common\Annotations\DocParser(); + $parser->setImports(array( + "__NAMESPACE__" =>"Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping" + )); + + $annots = $parser->parse($docblock); + + $this->assertEquals(1, count($annots)); + $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping\Entity", $annots[0]); + } + + public function testIssueNamespaces() + { + $docblock = "@Entity"; + $parser = new \Doctrine\Common\Annotations\DocParser(); + $parser->addNamespace("Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM"); + + $annots = $parser->parse($docblock); + + $this->assertEquals(1, count($annots)); + $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Entity", $annots[0]); + } + + public function testIssueMultipleNamespaces() + { + $docblock = "@Entity"; + $parser = new \Doctrine\Common\Annotations\DocParser(); + $parser->addNamespace("Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping"); + $parser->addNamespace("Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM"); + + $annots = $parser->parse($docblock); + + $this->assertEquals(1, count($annots)); + $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping\Entity", $annots[0]); + } + + public function testIssueWithNamespacesOrImports() + { + $docblock = "@Entity"; + $parser = new \Doctrine\Common\Annotations\DocParser(); + $annots = $parser->parse($docblock); + + $this->assertEquals(1, count($annots)); + $this->assertInstanceOf("Entity", $annots[0]); + $this->assertEquals(1, count($annots)); + } + + + public function testIssueSimpleAnnotationReader() + { + $reader = new \Doctrine\Common\Annotations\SimpleAnnotationReader(); + $reader->addNamespace('Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping'); + $annots = $reader->getClassAnnotations(new \ReflectionClass(__NAMESPACE__."\MappedClass")); + + $this->assertEquals(1, count($annots)); + $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping\Entity", $annots[0]); + } + +} + +/** + * @Entity + */ +class MappedClass +{ + +} + + +namespace Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM\Mapping; +/** +* @Annotation +*/ +class Entity +{ + +} + +namespace Doctrine\Tests\Common\Annotations\Ticket\Doctrine\ORM; +/** +* @Annotation +*/ +class Entity +{ + +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/TopLevelAnnotation.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/TopLevelAnnotation.php new file mode 100644 index 0000000..ff3ca37 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Annotations/TopLevelAnnotation.php @@ -0,0 +1,8 @@ +markTestSkipped('The ' . __CLASS__ .' requires the use of APC'); + } + } + + protected function _getCacheDriver() + { + return new ApcCache(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php new file mode 100644 index 0000000..6cad891 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/ArrayCacheTest.php @@ -0,0 +1,21 @@ +_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertNull($stats); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/CacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/CacheTest.php new file mode 100644 index 0000000..1bbc165 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/CacheTest.php @@ -0,0 +1,91 @@ +_getCacheDriver(); + + // Test save + $cache->save('test_key', 'testing this out'); + + // Test contains to test that save() worked + $this->assertTrue($cache->contains('test_key')); + + // Test fetch + $this->assertEquals('testing this out', $cache->fetch('test_key')); + + // Test delete + $cache->save('test_key2', 'test2'); + $cache->delete('test_key2'); + $this->assertFalse($cache->contains('test_key2')); + } + + public function testObjects() + { + $cache = $this->_getCacheDriver(); + + // Fetch/save test with objects (Is cache driver serializes/unserializes objects correctly ?) + $cache->save('test_object_key', new \ArrayObject()); + $this->assertTrue($cache->fetch('test_object_key') instanceof \ArrayObject); + } + + public function testDeleteAll() + { + $cache = $this->_getCacheDriver(); + $cache->save('test_key1', '1'); + $cache->save('test_key2', '2'); + $cache->deleteAll(); + + $this->assertFalse($cache->contains('test_key1')); + $this->assertFalse($cache->contains('test_key2')); + } + + public function testFlushAll() + { + $cache = $this->_getCacheDriver(); + $cache->save('test_key1', '1'); + $cache->save('test_key2', '2'); + $cache->flushAll(); + + $this->assertFalse($cache->contains('test_key1')); + $this->assertFalse($cache->contains('test_key2')); + } + + public function testNamespace() + { + $cache = $this->_getCacheDriver(); + $cache->setNamespace('test_'); + $cache->save('key1', 'test'); + + $this->assertTrue($cache->contains('key1')); + + $cache->setNamespace('test2_'); + + $this->assertFalse($cache->contains('key1')); + } + + /** + * @group DCOM-43 + */ + public function testGetStats() + { + $cache = $this->_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertArrayHasKey(Cache::STATS_HITS, $stats); + $this->assertArrayHasKey(Cache::STATS_MISSES, $stats); + $this->assertArrayHasKey(Cache::STATS_UPTIME, $stats); + $this->assertArrayHasKey(Cache::STATS_MEMORY_USAGE, $stats); + $this->assertArrayHasKey(Cache::STATS_MEMORY_AVAILIABLE, $stats); + } + + /** + * @return \Doctrine\Common\Cache\CacheProvider + */ + abstract protected function _getCacheDriver(); +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php new file mode 100644 index 0000000..f782e3c --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/FilesystemCacheTest.php @@ -0,0 +1,97 @@ +assertFalse(is_dir($dir)); + + $this->driver = new FilesystemCache($dir); + $this->assertTrue(is_dir($dir)); + + return $this->driver; + } + + public function testLifetime() + { + $cache = $this->_getCacheDriver(); + + // Test save + $cache->save('test_key', 'testing this out', 10); + + // Test contains to test that save() worked + $this->assertTrue($cache->contains('test_key')); + + // Test fetch + $this->assertEquals('testing this out', $cache->fetch('test_key')); + + // access private methods + $getFilename = new \ReflectionMethod($cache, 'getFilename'); + $getNamespacedId = new \ReflectionMethod($cache, 'getNamespacedId'); + + $getFilename->setAccessible(true); + $getNamespacedId->setAccessible(true); + + $id = $getNamespacedId->invoke($cache, 'test_key'); + $filename = $getFilename->invoke($cache, $id); + + $data = ''; + $lifetime = 0; + $resource = fopen($filename, "r"); + + if (false !== ($line = fgets($resource))) { + $lifetime = (integer) $line; + } + + while (false !== ($line = fgets($resource))) { + $data .= $line; + } + + $this->assertNotEquals(0, $lifetime, "previous lifetime could not be loaded"); + + // update lifetime + $lifetime = $lifetime - 20; + file_put_contents($filename, $lifetime . PHP_EOL . $data); + + // test expired data + $this->assertFalse($cache->contains('test_key')); + $this->assertFalse($cache->fetch('test_key')); + } + + public function testGetStats() + { + $cache = $this->_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertNull($stats); + } + + public function tearDown() + { + $dir = $this->driver->getDirectory(); + $ext = $this->driver->getExtension(); + $iterator = new \RecursiveDirectoryIterator($dir); + + foreach (new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST) as $file) { + if ($file->isFile()) { + @unlink($file->getRealPath()); + } else { + @rmdir($file->getRealPath()); + } + } + } + +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php new file mode 100644 index 0000000..36c180c --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/MemcacheCacheTest.php @@ -0,0 +1,45 @@ +_memcache = new \Memcache; + $ok = @$this->_memcache->connect('localhost', 11211); + if (!$ok) { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); + } + } else { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); + } + } + + public function testNoExpire() { + $cache = $this->_getCacheDriver(); + $cache->save('noexpire', 'value', 0); + sleep(1); + $this->assertTrue($cache->contains('noexpire'), 'Memcache provider should support no-expire'); + } + + public function testLongLifetime() + { + $cache = $this->_getCacheDriver(); + $cache->save('key', 'value', 30 * 24 * 3600 + 1); + $this->assertTrue($cache->contains('key'), 'Memcache provider should support TTL > 30 days'); + } + + protected function _getCacheDriver() + { + $driver = new MemcacheCache(); + $driver->setMemcache($this->_memcache); + return $driver; + } + +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php new file mode 100644 index 0000000..ecbe5a6 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/MemcachedCacheTest.php @@ -0,0 +1,48 @@ +memcached = new \Memcached(); + $this->memcached->setOption(\Memcached::OPT_COMPRESSION, false); + $this->memcached->addServer('127.0.0.1', 11211); + + $fh = @fsockopen('127.0.0.1', 11211); + if (!$fh) { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); + } + } else { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of memcache'); + } + } + + public function testNoExpire() { + $cache = $this->_getCacheDriver(); + $cache->save('noexpire', 'value', 0); + sleep(1); + $this->assertTrue($cache->contains('noexpire'), 'Memcache provider should support no-expire'); + } + + public function testLongLifetime() + { + $cache = $this->_getCacheDriver(); + $cache->save('key', 'value', 30 * 24 * 3600 + 1); + + $this->assertTrue($cache->contains('key'), 'Memcached provider should support TTL > 30 days'); + } + + protected function _getCacheDriver() + { + $driver = new MemcachedCache(); + $driver->setMemcached($this->memcached); + return $driver; + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php new file mode 100644 index 0000000..5085f46 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/PhpFileCacheTest.php @@ -0,0 +1,149 @@ +assertFalse(is_dir($dir)); + + $this->driver = new PhpFileCache($dir); + $this->assertTrue(is_dir($dir)); + + return $this->driver; + } + + public function testObjects() + { + $this->markTestSkipped('PhpFileCache does not support saving objects that dont implement __set_state()'); + } + + public function testLifetime() + { + $cache = $this->_getCacheDriver(); + + // Test save + $cache->save('test_key', 'testing this out', 10); + + // Test contains to test that save() worked + $this->assertTrue($cache->contains('test_key')); + + // Test fetch + $this->assertEquals('testing this out', $cache->fetch('test_key')); + + // access private methods + $getFilename = new \ReflectionMethod($cache, 'getFilename'); + $getNamespacedId = new \ReflectionMethod($cache, 'getNamespacedId'); + + $getFilename->setAccessible(true); + $getNamespacedId->setAccessible(true); + + $id = $getNamespacedId->invoke($cache, 'test_key'); + $path = $getFilename->invoke($cache, $id); + $value = include $path; + + // update lifetime + $value['lifetime'] = $value['lifetime'] - 20; + file_put_contents($path, 'assertFalse($cache->contains('test_key')); + $this->assertFalse($cache->fetch('test_key')); + } + + public function testImplementsSetState() + { + $cache = $this->_getCacheDriver(); + + // Test save + $cache->save('test_set_state', new SetStateClass(array(1,2,3))); + + //Test __set_state call + $this->assertCount(0, SetStateClass::$values); + + // Test fetch + $value = $cache->fetch('test_set_state'); + $this->assertInstanceOf('Doctrine\Tests\Common\Cache\SetStateClass', $value); + $this->assertEquals(array(1,2,3), $value->getValue()); + + //Test __set_state call + $this->assertCount(1, SetStateClass::$values); + + // Test contains + $this->assertTrue($cache->contains('test_set_state')); + } + + public function testNotImplementsSetState() + { + $cache = $this->_getCacheDriver(); + + $this->setExpectedException('InvalidArgumentException'); + $cache->save('test_not_set_state', new NotSetStateClass(array(1,2,3))); + } + + public function testGetStats() + { + $cache = $this->_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertNull($stats); + } + + public function tearDown() + { + if (!$this->driver) { + return; + } + + $dir = $this->driver->getDirectory(); + $ext = $this->driver->getExtension(); + $iterator = new \RecursiveDirectoryIterator($dir); + + foreach (new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST) as $file) { + if ($file->isFile()) { + @unlink($file->getRealPath()); + } else { + @rmdir($file->getRealPath()); + } + } + } + +} + +class NotSetStateClass +{ + private $value; + + public function __construct($value) + { + $this->value = $value; + } + + public function getValue() + { + return $this->value; + } +} + +class SetStateClass extends NotSetStateClass +{ + public static $values = array(); + + public static function __set_state($data) + { + self::$values = $data; + return new self($data['value']); + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php new file mode 100644 index 0000000..45bbc75 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/RedisCacheTest.php @@ -0,0 +1,30 @@ +_redis = new \Redis(); + $ok = @$this->_redis->connect('127.0.0.1'); + if (!$ok) { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of redis'); + } + } else { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of redis'); + } + } + + protected function _getCacheDriver() + { + $driver = new RedisCache(); + $driver->setRedis($this->_redis); + return $driver; + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php new file mode 100644 index 0000000..cb363df --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/WinCacheCacheTest.php @@ -0,0 +1,20 @@ +markTestSkipped('The ' . __CLASS__ .' requires the use of Wincache'); + } + } + + protected function _getCacheDriver() + { + return new WincacheCache(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/XcacheCacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/XcacheCacheTest.php new file mode 100644 index 0000000..6259848 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/XcacheCacheTest.php @@ -0,0 +1,20 @@ +markTestSkipped('The ' . __CLASS__ .' requires the use of xcache'); + } + } + + protected function _getCacheDriver() + { + return new XcacheCache(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/ZendDataCacheTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/ZendDataCacheTest.php new file mode 100644 index 0000000..cd66e15 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Cache/ZendDataCacheTest.php @@ -0,0 +1,28 @@ +markTestSkipped('The ' . __CLASS__ .' requires the use of Zend Data Cache which only works in apache2handler SAPI'); + } + } + + public function testGetStats() + { + $cache = $this->_getCacheDriver(); + $stats = $cache->getStats(); + + $this->assertNull($stats); + } + + protected function _getCacheDriver() + { + return new ZendDataCache(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest.php new file mode 100644 index 0000000..567cf91 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest.php @@ -0,0 +1,45 @@ +setIncludePath(__DIR__); + $classLoader->setFileExtension('.class.php'); + $classLoader->setNamespaceSeparator('_'); + + $this->assertTrue($classLoader->canLoadClass('ClassLoaderTest_ClassA')); + $this->assertTrue($classLoader->canLoadClass('ClassLoaderTest_ClassB')); + $this->assertTrue($classLoader->canLoadClass('ClassLoaderTest_ClassC')); + $this->assertFalse($classLoader->canLoadClass('OtherClass')); + $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassA'), true); + $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassB'), true); + $this->assertEquals($classLoader->loadClass('ClassLoaderTest_ClassC'), true); + } + + public function testClassExists() + { + $this->assertFalse(ClassLoader::classExists('ClassLoaderTest\ClassD')); + $badLoader = function($className) { + require __DIR__ . '/ClassLoaderTest/ClassD.php'; + return true; + }; + spl_autoload_register($badLoader); + $this->assertTrue(ClassLoader::classExists('ClassLoaderTest\ClassD')); + spl_autoload_unregister($badLoader); + } + + public function testGetClassLoader() + { + $cl = new ClassLoader('ClassLoaderTest', __DIR__); + $cl->register(); + $this->assertTrue(ClassLoader::getClassLoader('ClassLoaderTest\ClassD') instanceof \Doctrine\Common\ClassLoader); + $this->assertNull(ClassLoader::getClassLoader('This\Class\Does\Not\Exist')); + $cl->unregister(); + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest/ClassA.class.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest/ClassA.class.php new file mode 100644 index 0000000..8554654 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/ClassLoaderTest/ClassA.class.php @@ -0,0 +1,6 @@ +. + */ + +namespace Doctrine\Tests\Common\Collections; + +use Doctrine\Common\Collections\Expr\ClosureExpressionVisitor; +use Doctrine\Common\Collections\ExpressionBuilder; + +/** + * @group DDC-1637 + */ +class ClosureExpressionVisitorTest extends \PHPUnit_Framework_TestCase +{ + private $visitor; + private $builder; + + public function setUp() + { + $this->visitor = new ClosureExpressionVisitor(); + $this->builder = new ExpressionBuilder(); + } + + public function testWalkEqualsComparison() + { + $closure = $this->visitor->walkComparison($this->builder->eq("foo", 1)); + + $this->assertTrue($closure(new TestObject(1))); + $this->assertFalse($closure(new TestObject(2))); + } + + public function testWalkNotEqualsComparison() + { + $closure = $this->visitor->walkComparison($this->builder->neq("foo", 1)); + + $this->assertFalse($closure(new TestObject(1))); + $this->assertTrue($closure(new TestObject(2))); + } + + public function testWalkLessThanComparison() + { + $closure = $this->visitor->walkComparison($this->builder->lt("foo", 1)); + + $this->assertFalse($closure(new TestObject(1))); + $this->assertTrue($closure(new TestObject(0))); + } + + public function testWalkLessThanEqualsComparison() + { + $closure = $this->visitor->walkComparison($this->builder->lte("foo", 1)); + + $this->assertFalse($closure(new TestObject(2))); + $this->assertTrue($closure(new TestObject(1))); + $this->assertTrue($closure(new TestObject(0))); + } + + public function testWalkGreaterThanEqualsComparison() + { + $closure = $this->visitor->walkComparison($this->builder->gte("foo", 1)); + + $this->assertTrue($closure(new TestObject(2))); + $this->assertTrue($closure(new TestObject(1))); + $this->assertFalse($closure(new TestObject(0))); + } + + public function testWalkGreaterThanComparison() + { + $closure = $this->visitor->walkComparison($this->builder->gt("foo", 1)); + + $this->assertTrue($closure(new TestObject(2))); + $this->assertFalse($closure(new TestObject(1))); + $this->assertFalse($closure(new TestObject(0))); + } + + public function testWalkInComparison() + { + $closure = $this->visitor->walkComparison($this->builder->in("foo", array(1, 2, 3))); + + $this->assertTrue($closure(new TestObject(2))); + $this->assertTrue($closure(new TestObject(1))); + $this->assertFalse($closure(new TestObject(0))); + } + + public function testWalkNotInComparison() + { + $closure = $this->visitor->walkComparison($this->builder->notIn("foo", array(1, 2, 3))); + + $this->assertFalse($closure(new TestObject(1))); + $this->assertFalse($closure(new TestObject(2))); + $this->assertTrue($closure(new TestObject(0))); + $this->assertTrue($closure(new TestObject(4))); + } + + public function testWalkAndCompositeExpression() + { + $closure = $this->visitor->walkCompositeExpression( + $this->builder->andX( + $this->builder->eq("foo", 1), + $this->builder->eq("bar", 1) + ) + ); + + $this->assertTrue($closure(new TestObject(1, 1))); + $this->assertFalse($closure(new TestObject(1, 0))); + $this->assertFalse($closure(new TestObject(0, 1))); + $this->assertFalse($closure(new TestObject(0, 0))); + } + + public function testWalkOrCompositeExpression() + { + $closure = $this->visitor->walkCompositeExpression( + $this->builder->orX( + $this->builder->eq("foo", 1), + $this->builder->eq("bar", 1) + ) + ); + + $this->assertTrue($closure(new TestObject(1, 1))); + $this->assertTrue($closure(new TestObject(1, 0))); + $this->assertTrue($closure(new TestObject(0, 1))); + $this->assertFalse($closure(new TestObject(0, 0))); + } + + public function testSortByFieldAscending() + { + $objects = array(new TestObject("b"), new TestObject("a"), new TestObject("c")); + $sort = ClosureExpressionVisitor::sortByField("foo"); + + usort($objects, $sort); + + $this->assertEquals("a", $objects[0]->getFoo()); + $this->assertEquals("b", $objects[1]->getFoo()); + $this->assertEquals("c", $objects[2]->getFoo()); + } + + public function testSortByFieldDescending() + { + $objects = array(new TestObject("b"), new TestObject("a"), new TestObject("c")); + $sort = ClosureExpressionVisitor::sortByField("foo", -1); + + usort($objects, $sort); + + $this->assertEquals("c", $objects[0]->getFoo()); + $this->assertEquals("b", $objects[1]->getFoo()); + $this->assertEquals("a", $objects[2]->getFoo()); + } + + public function testSortDelegate() + { + $objects = array(new TestObject("a", "c"), new TestObject("a", "b"), new TestObject("a", "a")); + $sort = ClosureExpressionVisitor::sortByField("bar", 1); + $sort = ClosureExpressionVisitor::sortByField("foo", 1, $sort); + + usort($objects, $sort); + + $this->assertEquals("a", $objects[0]->getBar()); + $this->assertEquals("b", $objects[1]->getBar()); + $this->assertEquals("c", $objects[2]->getBar()); + } +} + +class TestObject +{ + private $foo; + private $bar; + + public function __construct($foo = null, $bar = null) + { + $this->foo = $foo; + $this->bar = $bar; + } + + public function getFoo() + { + return $this->foo; + } + + public function getBar() + { + return $this->bar; + } +} + diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/CollectionTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/CollectionTest.php new file mode 100644 index 0000000..280efa3 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/CollectionTest.php @@ -0,0 +1,251 @@ +_coll = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function testIssetAndUnset() + { + $this->assertFalse(isset($this->_coll[0])); + $this->_coll->add('testing'); + $this->assertTrue(isset($this->_coll[0])); + unset($this->_coll[0]); + $this->assertFalse(isset($this->_coll[0])); + } + + public function testToString() + { + $this->_coll->add('testing'); + $this->assertTrue(is_string((string) $this->_coll)); + } + + public function testRemovingNonExistentEntryReturnsNull() + { + $this->assertEquals(null, $this->_coll->remove('testing_does_not_exist')); + } + + public function testExists() + { + $this->_coll->add("one"); + $this->_coll->add("two"); + $exists = $this->_coll->exists(function($k, $e) { return $e == "one"; }); + $this->assertTrue($exists); + $exists = $this->_coll->exists(function($k, $e) { return $e == "other"; }); + $this->assertFalse($exists); + } + + public function testMap() + { + $this->_coll->add(1); + $this->_coll->add(2); + $res = $this->_coll->map(function($e) { return $e * 2; }); + $this->assertEquals(array(2, 4), $res->toArray()); + } + + public function testFilter() + { + $this->_coll->add(1); + $this->_coll->add("foo"); + $this->_coll->add(3); + $res = $this->_coll->filter(function($e) { return is_numeric($e); }); + $this->assertEquals(array(0 => 1, 2 => 3), $res->toArray()); + } + + public function testFirstAndLast() + { + $this->_coll->add('one'); + $this->_coll->add('two'); + + $this->assertEquals($this->_coll->first(), 'one'); + $this->assertEquals($this->_coll->last(), 'two'); + } + + public function testArrayAccess() + { + $this->_coll[] = 'one'; + $this->_coll[] = 'two'; + + $this->assertEquals($this->_coll[0], 'one'); + $this->assertEquals($this->_coll[1], 'two'); + + unset($this->_coll[0]); + $this->assertEquals($this->_coll->count(), 1); + } + + public function testContainsKey() + { + $this->_coll[5] = 'five'; + $this->assertTrue($this->_coll->containsKey(5)); + } + + public function testContains() + { + $this->_coll[0] = 'test'; + $this->assertTrue($this->_coll->contains('test')); + } + + public function testSearch() + { + $this->_coll[0] = 'test'; + $this->assertEquals(0, $this->_coll->indexOf('test')); + } + + public function testGet() + { + $this->_coll[0] = 'test'; + $this->assertEquals('test', $this->_coll->get(0)); + } + + public function testGetKeys() + { + $this->_coll[] = 'one'; + $this->_coll[] = 'two'; + $this->assertEquals(array(0, 1), $this->_coll->getKeys()); + } + + public function testGetValues() + { + $this->_coll[] = 'one'; + $this->_coll[] = 'two'; + $this->assertEquals(array('one', 'two'), $this->_coll->getValues()); + } + + public function testCount() + { + $this->_coll[] = 'one'; + $this->_coll[] = 'two'; + $this->assertEquals($this->_coll->count(), 2); + $this->assertEquals(count($this->_coll), 2); + } + + public function testForAll() + { + $this->_coll[] = 'one'; + $this->_coll[] = 'two'; + $this->assertEquals($this->_coll->forAll(function($k, $e) { return is_string($e); }), true); + $this->assertEquals($this->_coll->forAll(function($k, $e) { return is_array($e); }), false); + } + + public function testPartition() + { + $this->_coll[] = true; + $this->_coll[] = false; + $partition = $this->_coll->partition(function($k, $e) { return $e == true; }); + $this->assertEquals($partition[0][0], true); + $this->assertEquals($partition[1][0], false); + } + + public function testClear() + { + $this->_coll[] = 'one'; + $this->_coll[] = 'two'; + $this->_coll->clear(); + $this->assertEquals($this->_coll->isEmpty(), true); + } + + public function testRemove() + { + $this->_coll[] = 'one'; + $this->_coll[] = 'two'; + $el = $this->_coll->remove(0); + + $this->assertEquals('one', $el); + $this->assertEquals($this->_coll->contains('one'), false); + $this->assertNull($this->_coll->remove(0)); + } + + public function testRemoveElement() + { + $this->_coll[] = 'one'; + $this->_coll[] = 'two'; + + $this->assertTrue($this->_coll->removeElement('two')); + $this->assertFalse($this->_coll->contains('two')); + $this->assertFalse($this->_coll->removeElement('two')); + } + + public function testSlice() + { + $this->_coll[] = 'one'; + $this->_coll[] = 'two'; + $this->_coll[] = 'three'; + + $slice = $this->_coll->slice(0, 1); + $this->assertInternalType('array', $slice); + $this->assertEquals(array('one'), $slice); + + $slice = $this->_coll->slice(1); + $this->assertEquals(array(1 => 'two', 2 => 'three'), $slice); + + $slice = $this->_coll->slice(1, 1); + $this->assertEquals(array(1 => 'two'), $slice); + } + + public function fillMatchingFixture() + { + $std1 = new \stdClass(); + $std1->foo = "bar"; + $this->_coll[] = $std1; + + $std2 = new \stdClass(); + $std2->foo = "baz"; + $this->_coll[] = $std2; + } + + /** + * @group DDC-1637 + */ + public function testMatching() + { + $this->fillMatchingFixture(); + + $col = $this->_coll->matching(new Criteria(Criteria::expr()->eq("foo", "bar"))); + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $col); + $this->assertNotSame($col, $this->_coll); + $this->assertEquals(1, count($col)); + } + + /** + * @group DDC-1637 + */ + public function testMatchingOrdering() + { + $this->fillMatchingFixture(); + + $col = $this->_coll->matching(new Criteria(null, array('foo' => 'DESC'))); + + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $col); + $this->assertNotSame($col, $this->_coll); + $this->assertEquals(2, count($col)); + $this->assertEquals('baz', $col[0]->foo); + $this->assertEquals('bar', $col[1]->foo); + } + + /** + * @group DDC-1637 + */ + public function testMatchingSlice() + { + $this->fillMatchingFixture(); + + $col = $this->_coll->matching(new Criteria(null, null, 1, 1)); + + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $col); + $this->assertNotSame($col, $this->_coll); + $this->assertEquals(1, count($col)); + $this->assertEquals('baz', $col[0]->foo); + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/CriteriaTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/CriteriaTest.php new file mode 100644 index 0000000..03fb6ca --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/CriteriaTest.php @@ -0,0 +1,82 @@ +assertInstanceOf("Doctrine\Common\Collections\Criteria", $criteria); + } + + public function testConstructor() + { + $expr = new Comparison("field", "=", "value"); + $criteria = new Criteria($expr, array("foo" => "ASC"), 10, 20); + + $this->assertSame($expr, $criteria->getWhereExpression()); + $this->assertEquals(array("foo" => "ASC"), $criteria->getOrderings()); + $this->assertEquals(10, $criteria->getFirstResult()); + $this->assertEquals(20, $criteria->getMaxResults()); + } + + public function testWhere() + { + $expr = new Comparison("field", "=", "value"); + $criteria = new Criteria(); + + $criteria->where($expr); + + $this->assertSame($expr, $criteria->getWhereExpression()); + } + + public function testAndWhere() + { + $expr = new Comparison("field", "=", "value"); + $criteria = new Criteria(); + + $criteria->where($expr); + $expr = $criteria->getWhereExpression(); + $criteria->andWhere($expr); + + $where = $criteria->getWhereExpression(); + $this->assertInstanceOf('Doctrine\Common\Collections\Expr\CompositeExpression', $where); + + $this->assertEquals(CompositeExpression::TYPE_AND, $where->getType()); + $this->assertSame(array($expr, $expr), $where->getExpressionList()); + } + + public function testOrWhere() + { + $expr = new Comparison("field", "=", "value"); + $criteria = new Criteria(); + + $criteria->where($expr); + $expr = $criteria->getWhereExpression(); + $criteria->orWhere($expr); + + $where = $criteria->getWhereExpression(); + $this->assertInstanceOf('Doctrine\Common\Collections\Expr\CompositeExpression', $where); + + $this->assertEquals(CompositeExpression::TYPE_OR, $where->getType()); + $this->assertSame(array($expr, $expr), $where->getExpressionList()); + } + + public function testOrderings() + { + $criteria = Criteria::create() + ->orderBy(array("foo" => "ASC")); + + $this->assertEquals(array("foo" => "ASC"), $criteria->getOrderings()); + } + + public function testExpr() + { + $this->assertInstanceOf('Doctrine\Common\Collections\ExpressionBuilder', Criteria::expr()); + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/ExpressionBuilderTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/ExpressionBuilderTest.php new file mode 100644 index 0000000..68896b3 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Collections/ExpressionBuilderTest.php @@ -0,0 +1,114 @@ +builder = new ExpressionBuilder(); + } + + public function testAndX() + { + $expr = $this->builder->andX($this->builder->eq("a", "b")); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\CompositeExpression", $expr); + $this->assertEquals(CompositeExpression::TYPE_AND, $expr->getType()); + } + + public function testOrX() + { + $expr = $this->builder->orX($this->builder->eq("a", "b")); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\CompositeExpression", $expr); + $this->assertEquals(CompositeExpression::TYPE_OR, $expr->getType()); + } + + public function testInvalidAndXArgument() + { + $this->setExpectedException("RuntimeException"); + $this->builder->andX("foo"); + } + + public function testEq() + { + $expr = $this->builder->eq("a", "b"); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr); + $this->assertEquals(Comparison::EQ, $expr->getOperator()); + } + + public function testNeq() + { + $expr = $this->builder->neq("a", "b"); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr); + $this->assertEquals(Comparison::NEQ, $expr->getOperator()); + } + + public function testLt() + { + $expr = $this->builder->lt("a", "b"); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr); + $this->assertEquals(Comparison::LT, $expr->getOperator()); + } + + public function testGt() + { + $expr = $this->builder->gt("a", "b"); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr); + $this->assertEquals(Comparison::GT, $expr->getOperator()); + } + + public function testGte() + { + $expr = $this->builder->gte("a", "b"); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr); + $this->assertEquals(Comparison::GTE, $expr->getOperator()); + } + + public function testLte() + { + $expr = $this->builder->lte("a", "b"); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr); + $this->assertEquals(Comparison::LTE, $expr->getOperator()); + } + + public function testIn() + { + $expr = $this->builder->in("a", array("b")); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr); + $this->assertEquals(Comparison::IN, $expr->getOperator()); + } + + public function testNotIn() + { + $expr = $this->builder->notIn("a", array("b")); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr); + $this->assertEquals(Comparison::NIN, $expr->getOperator()); + } + + public function testIsNull() + { + $expr = $this->builder->isNull("a"); + + $this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr); + $this->assertEquals(Comparison::IS, $expr->getOperator()); + } +} + diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/DoctrineExceptionTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/DoctrineExceptionTest.php new file mode 100644 index 0000000..e69de29 diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/EventManagerTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/EventManagerTest.php new file mode 100644 index 0000000..2b11b20 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/EventManagerTest.php @@ -0,0 +1,88 @@ +_eventManager = new EventManager; + $this->_preFooInvoked = false; + $this->_postFooInvoked = false; + } + + public function testInitialState() + { + $this->assertEquals(array(), $this->_eventManager->getListeners()); + $this->assertFalse($this->_eventManager->hasListeners(self::preFoo)); + $this->assertFalse($this->_eventManager->hasListeners(self::postFoo)); + } + + public function testAddEventListener() + { + $this->_eventManager->addEventListener(array('preFoo', 'postFoo'), $this); + $this->assertTrue($this->_eventManager->hasListeners(self::preFoo)); + $this->assertTrue($this->_eventManager->hasListeners(self::postFoo)); + $this->assertEquals(1, count($this->_eventManager->getListeners(self::preFoo))); + $this->assertEquals(1, count($this->_eventManager->getListeners(self::postFoo))); + $this->assertEquals(2, count($this->_eventManager->getListeners())); + } + + public function testDispatchEvent() + { + $this->_eventManager->addEventListener(array('preFoo', 'postFoo'), $this); + $this->_eventManager->dispatchEvent(self::preFoo); + $this->assertTrue($this->_preFooInvoked); + $this->assertFalse($this->_postFooInvoked); + } + + public function testRemoveEventListener() + { + $this->_eventManager->addEventListener(array('preBar'), $this); + $this->assertTrue($this->_eventManager->hasListeners(self::preBar)); + $this->_eventManager->removeEventListener(array('preBar'), $this); + $this->assertFalse($this->_eventManager->hasListeners(self::preBar)); + } + + public function testAddEventSubscriber() + { + $eventSubscriber = new TestEventSubscriber(); + $this->_eventManager->addEventSubscriber($eventSubscriber); + $this->assertTrue($this->_eventManager->hasListeners(self::preFoo)); + $this->assertTrue($this->_eventManager->hasListeners(self::postFoo)); + } + + /* Listener methods */ + + public function preFoo(EventArgs $e) + { + $this->_preFooInvoked = true; + } + + public function postFoo(EventArgs $e) + { + $this->_postFooInvoked = true; + } +} + +class TestEventSubscriber implements \Doctrine\Common\EventSubscriber +{ + public function getSubscribedEvents() + { + return array('preFoo', 'postFoo'); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/ChainDriverTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/ChainDriverTest.php new file mode 100644 index 0000000..66ad762 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/ChainDriverTest.php @@ -0,0 +1,130 @@ +getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata'); + + $chain = new MappingDriverChain(); + + $driver1 = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $driver1->expects($this->never()) + ->method('loadMetadataForClass'); + $driver1->expectS($this->never()) + ->method('isTransient'); + + $driver2 = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $driver2->expects($this->at(0)) + ->method('loadMetadataForClass') + ->with($this->equalTo($className), $this->equalTo($classMetadata)); + $driver2->expects($this->at(1)) + ->method('isTransient') + ->with($this->equalTo($className)) + ->will($this->returnValue( true )); + + $chain->addDriver($driver1, 'Doctrine\Tests\Models\Company'); + $chain->addDriver($driver2, 'Doctrine\Tests\Common\Persistence\Mapping'); + + $chain->loadMetadataForClass($className, $classMetadata); + + $this->assertTrue( $chain->isTransient($className) ); + } + + public function testLoadMetadata_NoDelegatorFound_ThrowsMappingException() + { + $className = 'Doctrine\Tests\Common\Persistence\Mapping\DriverChainEntity'; + $classMetadata = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata'); + + $chain = new MappingDriverChain(); + + $this->setExpectedException('Doctrine\Common\Persistence\Mapping\MappingException'); + $chain->loadMetadataForClass($className, $classMetadata); + } + + public function testGatherAllClassNames() + { + $className = 'Doctrine\Tests\Common\Persistence\Mapping\DriverChainEntity'; + $classMetadata = $this->getMock('Doctrine\Common\Peristence\ClassMetadata'); + + $chain = new MappingDriverChain(); + + $driver1 = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $driver1->expects($this->once()) + ->method('getAllClassNames') + ->will($this->returnValue(array('Doctrine\Tests\Models\Company\Foo'))); + + $driver2 = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $driver2->expects($this->once()) + ->method('getAllClassNames') + ->will($this->returnValue(array('Doctrine\Tests\ORM\Mapping\Bar', 'Doctrine\Tests\ORM\Mapping\Baz', 'FooBarBaz'))); + + $chain->addDriver($driver1, 'Doctrine\Tests\Models\Company'); + $chain->addDriver($driver2, 'Doctrine\Tests\ORM\Mapping'); + + $this->assertEquals(array( + 'Doctrine\Tests\Models\Company\Foo', + 'Doctrine\Tests\ORM\Mapping\Bar', + 'Doctrine\Tests\ORM\Mapping\Baz' + ), $chain->getAllClassNames()); + } + + /** + * @group DDC-706 + */ + public function testIsTransient() + { + $driver1 = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $chain = new MappingDriverChain(); + $chain->addDriver($driver1, 'Doctrine\Tests\Models\CMS'); + + $this->assertTrue($chain->isTransient('stdClass'), "stdClass isTransient"); + } + + /** + * @group DDC-1412 + */ + public function testDefaultDriver() + { + $companyDriver = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $dafaultDriver = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $entityClassName = 'Doctrine\Tests\ORM\Mapping\DriverChainEntity'; + $managerClassName = 'Doctrine\Tests\Models\Company\CompanyManager'; + $chain = new MappingDriverChain(); + + $companyDriver->expects($this->never()) + ->method('loadMetadataForClass'); + $companyDriver->expects($this->once()) + ->method('isTransient') + ->with($this->equalTo($managerClassName)) + ->will($this->returnValue(false)); + + $dafaultDriver->expects($this->never()) + ->method('loadMetadataForClass'); + $dafaultDriver->expects($this->once()) + ->method('isTransient') + ->with($this->equalTo($entityClassName)) + ->will($this->returnValue(true)); + + $this->assertNull($chain->getDefaultDriver()); + + $chain->setDefaultDriver($dafaultDriver); + $chain->addDriver($companyDriver, 'Doctrine\Tests\Models\Company'); + + $this->assertSame($dafaultDriver, $chain->getDefaultDriver()); + + $this->assertTrue($chain->isTransient($entityClassName)); + $this->assertFalse($chain->isTransient($managerClassName)); + } +} + +class DriverChainEntity +{ + +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php new file mode 100644 index 0000000..bc1559a --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -0,0 +1,139 @@ +getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $metadata = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata'); + $this->cmf = new TestClassMetadataFactory($driver, $metadata); + } + + public function testGetCacheDriver() + { + $this->assertNull($this->cmf->getCacheDriver()); + $cache = new ArrayCache(); + $this->cmf->setCacheDriver($cache); + $this->assertSame($cache, $this->cmf->getCacheDriver()); + } + + public function testGetMetadataFor() + { + $metadata = $this->cmf->getMetadataFor('stdClass'); + + $this->assertInstanceOf('Doctrine\Common\Persistence\Mapping\ClassMetadata', $metadata); + $this->assertTrue($this->cmf->hasMetadataFor('stdClass')); + } + + public function testGetParentMetadata() + { + $metadata = $this->cmf->getMetadataFor(__NAMESPACE__ . '\ChildEntity'); + + $this->assertInstanceOf('Doctrine\Common\Persistence\Mapping\ClassMetadata', $metadata); + $this->assertTrue($this->cmf->hasMetadataFor(__NAMESPACE__ . '\ChildEntity')); + $this->assertTrue($this->cmf->hasMetadataFor(__NAMESPACE__ . '\RootEntity')); + } + + public function testGetCachedMetadata() + { + $metadata = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata'); + $cache = new ArrayCache(); + $cache->save(__NAMESPACE__. '\ChildEntity$CLASSMETADATA', $metadata); + + $this->cmf->setCacheDriver($cache); + + $loadedMetadata = $this->cmf->getMetadataFor(__NAMESPACE__ . '\ChildEntity'); + $this->assertSame($loadedMetadata, $metadata); + } + + public function testCacheGetMetadataFor() + { + $cache = new ArrayCache(); + $this->cmf->setCacheDriver($cache); + + $loadedMetadata = $this->cmf->getMetadataFor(__NAMESPACE__ . '\ChildEntity'); + + $this->assertSame($loadedMetadata, $cache->fetch(__NAMESPACE__. '\ChildEntity$CLASSMETADATA')); + } + + public function testGetAliasedMetadata() + { + $loadedMetadata = $this->cmf->getMetadataFor('prefix:ChildEntity'); + + $this->assertTrue($this->cmf->hasMetadataFor(__NAMESPACE__ . '\ChildEntity')); + $this->assertTrue($this->cmf->hasMetadataFor('prefix:ChildEntity')); + } +} + +class TestClassMetadataFactory extends AbstractClassMetadataFactory +{ + public $driver; + public $metadata; + + public function __construct($driver, $metadata) + { + $this->driver = $driver; + $this->metadata = $metadata; + } + + protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) + { + + } + + protected function getFqcnFromAlias($namespaceAlias, $simpleClassName) + { + return __NAMESPACE__ . '\\' . $simpleClassName; + } + + protected function initialize() + { + + } + + protected function newClassMetadataInstance($className) + { + return $this->metadata; + } + + protected function getDriver() + { + return $this->driver; + } + protected function wakeupReflection(ClassMetadata $class, ReflectionService $reflService) + { + } + + protected function initializeReflection(ClassMetadata $class, ReflectionService $reflService) + { + } + + protected function isEntity(ClassMetadata $class) + { + return true; + } +} + +class RootEntity +{ + +} + +class ChildEntity extends RootEntity +{ + +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/DefaultFileLocatorTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/DefaultFileLocatorTest.php new file mode 100644 index 0000000..37072de --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/DefaultFileLocatorTest.php @@ -0,0 +1,90 @@ +assertEquals(array($path), $locator->getPaths()); + + $locator = new DefaultFileLocator($path); + $this->assertEquals(array($path), $locator->getPaths()); + } + + public function testGetFileExtension() + { + $locator = new DefaultFileLocator(array(), ".yml"); + $this->assertEquals(".yml", $locator->getFileExtension()); + $locator->setFileExtension(".xml"); + $this->assertEquals(".xml", $locator->getFileExtension()); + } + + public function testUniquePaths() + { + $path = __DIR__ . "/_files"; + + $locator = new DefaultFileLocator(array($path, $path)); + $this->assertEquals(array($path), $locator->getPaths()); + } + + public function testFindMappingFile() + { + $path = __DIR__ . "/_files"; + + $locator = new DefaultFileLocator(array($path), ".yml"); + + $this->assertEquals(__DIR__ . '/_files' . DIRECTORY_SEPARATOR . 'stdClass.yml', $locator->findMappingFile('stdClass')); + } + + public function testFindMappingFileNotFound() + { + $path = __DIR__ . "/_files"; + + $locator = new DefaultFileLocator(array($path), ".yml"); + + $this->setExpectedException( + 'Doctrine\Common\Persistence\Mapping\MappingException', + "No mapping file found named 'stdClass2.yml' for class 'stdClass2'" + ); + $locator->findMappingFile('stdClass2'); + } + + public function testGetAllClassNames() + { + $path = __DIR__ . "/_files"; + + $locator = new DefaultFileLocator(array($path), ".yml"); + $classes = $locator->getAllClassNames(null); + sort($classes); + + $this->assertEquals(array('global', 'stdClass'), $classes); + $this->assertEquals(array('stdClass'), $locator->getAllClassNames("global")); + } + + public function testGetAllClassNamesNonMatchingFileExtension() + { + $path = __DIR__ . "/_files"; + + $locator = new DefaultFileLocator(array($path), ".xml"); + $this->assertEquals(array(), $locator->getAllClassNames("global")); + } + + public function testFileExists() + { + $path = __DIR__ . "/_files"; + + $locator = new DefaultFileLocator(array($path), ".yml"); + + $this->assertTrue($locator->fileExists("stdClass")); + $this->assertFalse($locator->fileExists("stdClass2")); + $this->assertTrue($locator->fileExists("global")); + $this->assertFalse($locator->fileExists("global2")); + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/FileDriverTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/FileDriverTest.php new file mode 100644 index 0000000..020c242 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/FileDriverTest.php @@ -0,0 +1,142 @@ +assertNull($driver->getGlobalBasename()); + + $driver->setGlobalBasename("global"); + $this->assertEquals("global", $driver->getGlobalBasename()); + } + + public function testGetElementFromGlobalFile() + { + $driver = new TestFileDriver($this->newLocator()); + $driver->setGlobalBasename("global"); + + $element = $driver->getElement('stdGlobal'); + + $this->assertEquals('stdGlobal', $element); + } + + public function testGetElementFromFile() + { + $locator = $this->newLocator(); + $locator->expects($this->once()) + ->method('findMappingFile') + ->with($this->equalTo('stdClass')) + ->will($this->returnValue(__DIR__ . '/_files/stdClass.yml')); + + $driver = new TestFileDriver($locator); + + $this->assertEquals('stdClass', $driver->getElement('stdClass')); + } + + public function testGetAllClassNamesGlobalBasename() + { + $driver = new TestFileDriver($this->newLocator()); + $driver->setGlobalBasename("global"); + + $classNames = $driver->getAllClassNames(); + + $this->assertEquals(array('stdGlobal', 'stdGlobal2'), $classNames); + } + + public function testGetAllClassNamesFromMappingFile() + { + $locator = $this->newLocator(); + $locator->expects($this->any()) + ->method('getAllClassNames') + ->with($this->equalTo(null)) + ->will($this->returnValue(array('stdClass'))); + $driver = new TestFileDriver($locator); + + $classNames = $driver->getAllClassNames(); + + $this->assertEquals(array('stdClass'), $classNames); + } + + public function testGetAllClassNamesBothSources() + { + $locator = $this->newLocator(); + $locator->expects($this->any()) + ->method('getAllClassNames') + ->with($this->equalTo('global')) + ->will($this->returnValue(array('stdClass'))); + $driver = new TestFileDriver($locator); + $driver->setGlobalBasename("global"); + + $classNames = $driver->getAllClassNames(); + + $this->assertEquals(array('stdGlobal', 'stdGlobal2', 'stdClass'), $classNames); + } + + public function testIsNotTransient() + { + $locator = $this->newLocator(); + $locator->expects($this->once()) + ->method('fileExists') + ->with($this->equalTo('stdClass')) + ->will($this->returnValue( true )); + + $driver = new TestFileDriver($locator); + $driver->setGlobalBasename("global"); + + $this->assertFalse($driver->isTransient('stdClass')); + $this->assertFalse($driver->isTransient('stdGlobal')); + $this->assertFalse($driver->isTransient('stdGlobal2')); + } + + public function testIsTransient() + { + $locator = $this->newLocator(); + $locator->expects($this->once()) + ->method('fileExists') + ->with($this->equalTo('stdClass2')) + ->will($this->returnValue( false )); + + $driver = new TestFileDriver($locator); + + $this->assertTrue($driver->isTransient('stdClass2')); + } + + public function testNonLocatorFallback() + { + $driver = new TestFileDriver(__DIR__ . '/_files', '.yml'); + $this->assertTrue($driver->isTransient('stdClass2')); + $this->assertFalse($driver->isTransient('stdClass')); + } + + private function newLocator() + { + $locator = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\FileLocator'); + $locator->expects($this->any())->method('getFileExtension')->will($this->returnValue('.yml')); + $locator->expects($this->any())->method('getPaths')->will($this->returnValue(array(__DIR__ . "/_files"))); + return $locator; + } +} + +class TestFileDriver extends FileDriver +{ + protected function loadMappingFile($file) + { + if (strpos($file, "global.yml") !== false) { + return array('stdGlobal' => 'stdGlobal', 'stdGlobal2' => 'stdGlobal2'); + } + return array('stdClass' => 'stdClass'); + } + + public function loadMetadataForClass($className, ClassMetadata $metadata) + { + + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/PHPDriverTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/PHPDriverTest.php new file mode 100644 index 0000000..8fc4d80 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/PHPDriverTest.php @@ -0,0 +1,18 @@ +getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata'); + $metadata->expects($this->once())->method('getFieldNames'); + + $driver = new PHPDriver(array(__DIR__ . "/_files")); + $driver->loadMetadataForClass('TestEntity', $metadata); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/RuntimeReflectionServiceTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/RuntimeReflectionServiceTest.php new file mode 100644 index 0000000..5f06cad --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/RuntimeReflectionServiceTest.php @@ -0,0 +1,70 @@ +. + */ + +namespace Doctrine\Tests\Common\Persistence\Mapping; + +use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService; + +/** + * @group DCOM-93 + */ +class RuntimeReflectionServiceTest extends \PHPUnit_Framework_TestCase +{ + private $reflectionService; + + public function setUp() + { + $this->reflectionService = new RuntimeReflectionService(); + } + + public function testShortname() + { + $this->assertEquals("RuntimeReflectionServiceTest", $this->reflectionService->getClassShortName(__CLASS__)); + } + + public function testClassNamespaceName() + { + $this->assertEquals("Doctrine\Tests\Common\Persistence\Mapping", $this->reflectionService->getClassNamespace(__CLASS__)); + } + + public function testGetParentClasses() + { + $classes = $this->reflectionService->getParentClasses(__CLASS__); + $this->assertTrue(count($classes) >= 1, "The test class ".__CLASS__." should have at least one parent."); + } + + public function testGetReflectionClass() + { + $class = $this->reflectionService->getClass(__CLASS__); + $this->assertInstanceOf("ReflectionClass", $class); + } + + public function testGetMethods() + { + $this->assertTrue($this->reflectionService->hasPublicMethod(__CLASS__, "testGetMethods")); + $this->assertFalse($this->reflectionService->hasPublicMethod(__CLASS__, "testGetMethods2")); + } + + public function testGetAccessibleProperty() + { + $reflProp = $this->reflectionService->getAccessibleProperty(__CLASS__, "reflectionService"); + $this->assertInstanceOf("ReflectionProperty", $reflProp); + } +} + diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticPHPDriverTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticPHPDriverTest.php new file mode 100644 index 0000000..9f1c568 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticPHPDriverTest.php @@ -0,0 +1,35 @@ +getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata'); + $metadata->expects($this->once())->method('getFieldNames'); + + $driver = new StaticPHPDriver(array(__DIR__)); + $driver->loadMetadataForClass(__NAMESPACE__ . '\\TestEntity', $metadata); + } + + public function testGetAllClassNames() + { + $driver = new StaticPHPDriver(array(__DIR__)); + $classNames = $driver->getAllClassNames(); + + $this->assertContains( + 'Doctrine\Tests\Common\Persistence\Mapping\TestEntity', $classNames); + } +} + +class TestEntity +{ + static public function loadMetadata($metadata) + { + $metadata->getFieldNames(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticReflectionServiceTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticReflectionServiceTest.php new file mode 100644 index 0000000..ffce6d4 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/StaticReflectionServiceTest.php @@ -0,0 +1,70 @@ +. + */ + +namespace Doctrine\Tests\Common\Persistence\Mapping; + +use Doctrine\Common\Persistence\Mapping\StaticReflectionService; + +/** + * @group DCOM-93 + */ +class StaticReflectionServiceTest extends \PHPUnit_Framework_TestCase +{ + private $reflectionService; + + public function setUp() + { + $this->reflectionService = new StaticReflectionService(); + } + + public function testShortname() + { + $this->assertEquals("StaticReflectionServiceTest", $this->reflectionService->getClassShortName(__CLASS__)); + } + + public function testClassNamespaceName() + { + $this->assertEquals("Doctrine\Tests\Common\Persistence\Mapping", $this->reflectionService->getClassNamespace(__CLASS__)); + } + + public function testGetParentClasses() + { + $classes = $this->reflectionService->getParentClasses(__CLASS__); + $this->assertTrue(count($classes) == 0, "The test class ".__CLASS__." should have no parents according to static reflection."); + } + + public function testGetReflectionClass() + { + $class = $this->reflectionService->getClass(__CLASS__); + $this->assertNull($class); + } + + public function testGetMethods() + { + $this->assertTrue($this->reflectionService->hasPublicMethod(__CLASS__, "testGetMethods")); + $this->assertFalse($this->reflectionService->hasPublicMethod(__CLASS__, "testGetMethods2")); + } + + public function testGetAccessibleProperty() + { + $reflProp = $this->reflectionService->getAccessibleProperty(__CLASS__, "reflectionService"); + $this->assertNull($reflProp); + } +} + diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/SymfonyFileLocatorTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/SymfonyFileLocatorTest.php new file mode 100644 index 0000000..b51162e --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/SymfonyFileLocatorTest.php @@ -0,0 +1,88 @@ + $prefix)); + $this->assertEquals(array($path), $locator->getPaths()); + + $locator = new SymfonyFileLocator(array($path => $prefix)); + $this->assertEquals(array($path), $locator->getPaths()); + } + + public function testGetPrefixes() + { + $path = __DIR__ . "/_files"; + $prefix = "Foo"; + + $locator = new SymfonyFileLocator(array($path => $prefix)); + $this->assertEquals(array($path => $prefix), $locator->getNamespacePrefixes()); + } + + public function testGetFileExtension() + { + $locator = new SymfonyFileLocator(array(), ".yml"); + $this->assertEquals(".yml", $locator->getFileExtension()); + $locator->setFileExtension(".xml"); + $this->assertEquals(".xml", $locator->getFileExtension()); + } + + public function testFileExists() + { + $path = __DIR__ . "/_files"; + $prefix = "Foo"; + + $locator = new SymfonyFileLocator(array($path => $prefix), ".yml"); + + $this->assertTrue($locator->fileExists("Foo\stdClass")); + $this->assertTrue($locator->fileExists("Foo\global")); + $this->assertFalse($locator->fileExists("Foo\stdClass2")); + $this->assertFalse($locator->fileExists("Foo\global2")); + } + + public function testGetAllClassNames() + { + $path = __DIR__ . "/_files"; + $prefix = "Foo"; + + $locator = new SymfonyFileLocator(array($path => $prefix), ".yml"); + $classes = $locator->getAllClassNames(null); + sort($classes); + + $this->assertEquals(array("Foo\\global", "Foo\\stdClass"), $classes); + $this->assertEquals(array("Foo\\stdClass"), $locator->getAllClassNames("global")); + } + + public function testFindMappingFile() + { + $path = __DIR__ . "/_files"; + $prefix = "Foo"; + + $locator = new SymfonyFileLocator(array($path => $prefix), ".yml"); + + $this->assertEquals(__DIR__ . "/_files/stdClass.yml", $locator->findMappingFile("Foo\\stdClass")); + } + + public function testFindMappingFileNotFound() + { + $path = __DIR__ . "/_files"; + $prefix = "Foo"; + + $locator = new SymfonyFileLocator(array($path => $prefix), ".yml"); + + $this->setExpectedException( + "Doctrine\Common\Persistence\Mapping\MappingException", + "No mapping file found named '".__DIR__."/_files/stdClass2.yml' for class 'Foo\stdClass2'." + ); + $locator->findMappingFile("Foo\\stdClass2"); + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/TestEntity.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/TestEntity.php new file mode 100644 index 0000000..d0e9976 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/TestEntity.php @@ -0,0 +1,3 @@ +getFieldNames(); \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/global.yml b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/global.yml new file mode 100644 index 0000000..30d74d2 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/global.yml @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/stdClass.yml b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/stdClass.yml new file mode 100644 index 0000000..30d74d2 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/Mapping/_files/stdClass.yml @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/PersistentObjectTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/PersistentObjectTest.php new file mode 100644 index 0000000..a0f77b5 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Persistence/PersistentObjectTest.php @@ -0,0 +1,247 @@ +cm = new TestObjectMetadata; + $this->om = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); + $this->om->expects($this->any())->method('getClassMetadata') + ->will($this->returnValue($this->cm)); + $this->object = new TestObject; + PersistentObject::setObjectManager($this->om); + $this->object->injectObjectManager($this->om, $this->cm); + } + + public function testGetObjectManager() + { + $this->assertSame($this->om, PersistentObject::getObjectManager()); + } + + public function testNonMatchingObjectManager() + { + $this->setExpectedException('RuntimeException'); + $om = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); + $this->object->injectObjectManager($om, $this->cm); + } + + public function testGetField() + { + $this->assertEquals('beberlei', $this->object->getName()); + } + + public function testSetField() + { + $this->object->setName("test"); + $this->assertEquals("test", $this->object->getName()); + } + + public function testGetIdentifier() + { + $this->assertEquals(1, $this->object->getId()); + } + + public function testSetIdentifier() + { + $this->setExpectedException('BadMethodCallException'); + $this->object->setId(2); + } + + public function testSetUnknownField() + { + $this->setExpectedException('BadMethodCallException'); + $this->object->setUnknown("test"); + } + + public function testGetUnknownField() + { + $this->setExpectedException('BadMethodCallException'); + $this->object->getUnknown(); + } + + public function testGetToOneAssociation() + { + $this->assertNull($this->object->getParent()); + } + + public function testSetToOneAssociation() + { + $parent = new TestObject(); + $this->object->setParent($parent); + $this->assertSame($parent, $this->object->getParent($parent)); + } + + public function testSetInvalidToOneAssocation() + { + $parent = new \stdClass(); + + $this->setExpectedException('InvalidArgumentException'); + $this->object->setParent($parent); + } + + public function testSetToOneAssociationNull() + { + $parent = new TestObject(); + $this->object->setParent($parent); + $this->object->setParent(null); + $this->assertNull($this->object->getParent()); + } + + public function testAddToManyAssocation() + { + $child = new TestObject(); + $this->object->addChildren($child); + + $this->assertSame($this->object, $child->getParent()); + $this->assertEquals(1, count($this->object->getChildren())); + + $child = new TestObject(); + $this->object->addChildren($child); + + $this->assertEquals(2, count($this->object->getChildren())); + } + + public function testAddInvalidToManyAssocation() + { + $this->setExpectedException('InvalidArgumentException'); + $this->object->addChildren(new \stdClass()); + } + + public function testNoObjectManagerSet() + { + PersistentObject::setObjectManager(null); + $child = new TestObject(); + + $this->setExpectedException('RuntimeException'); + $child->setName("test"); + } + + public function testInvalidMethod() + { + $this->setExpectedException('BadMethodCallException'); + $this->object->asdf(); + } + + public function testAddInvalidCollection() + { + $this->setExpectedException('BadMethodCallException'); + $this->object->addAsdf(new \stdClass()); + } +} + +class TestObject extends PersistentObject +{ + protected $id = 1; + protected $name = 'beberlei'; + protected $parent; + protected $children; +} + +class TestObjectMetadata implements ClassMetadata +{ + + public function getAssociationMappedByTargetField($assocName) + { + $assoc = array('children' => 'parent'); + return $assoc[$assocName]; + } + + public function getAssociationNames() + { + return array('parent', 'children'); + } + + public function getAssociationTargetClass($assocName) + { + return __NAMESPACE__ . '\TestObject'; + } + + public function getFieldNames() + { + return array('id', 'name'); + } + + public function getIdentifier() + { + return array('id'); + } + + public function getName() + { + return __NAMESPACE__ . '\TestObject'; + } + + public function getReflectionClass() + { + return new \ReflectionClass($this->getName()); + } + + public function getTypeOfField($fieldName) + { + $types = array('id' => 'integer', 'name' => 'string'); + return $types[$fieldName]; + } + + public function hasAssociation($fieldName) + { + return in_array($fieldName, array('parent', 'children')); + } + + public function hasField($fieldName) + { + return in_array($fieldName, array('id', 'name')); + } + + public function isAssociationInverseSide($assocName) + { + return ($assocName === 'children'); + } + + public function isCollectionValuedAssociation($fieldName) + { + return ($fieldName === 'children'); + } + + public function isIdentifier($fieldName) + { + return $fieldName === 'id'; + } + + public function isSingleValuedAssociation($fieldName) + { + return $fieldName === 'parent'; + } + + public function getIdentifierValues($entity) + { + + } + + public function getIdentifierFieldNames() + { + + } + + public function initializeReflection(ReflectionService $reflService) + { + + } + + public function wakeupReflection(ReflectionService $reflService) + { + + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/DeeperNamespaceParent.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/DeeperNamespaceParent.php new file mode 100644 index 0000000..72faa77 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/DeeperNamespaceParent.php @@ -0,0 +1,7 @@ + array($testsRoot), + ); + $noParentClassName = 'Doctrine\\Tests\\Common\\Reflection\\NoParent'; + $staticReflectionParser = new StaticReflectionParser($noParentClassName, new Psr0FindFile($paths)); + $declaringClassName = $staticReflectionParser->getStaticReflectionParserForDeclaringClass('property', 'test')->getClassName(); + $this->assertEquals($noParentClassName, $declaringClassName); + + $className = 'Doctrine\\Tests\\Common\\Reflection\\FullyClassifiedParent'; + $staticReflectionParser = new StaticReflectionParser($className, new Psr0FindFile($paths)); + $declaringClassName = $staticReflectionParser->getStaticReflectionParserForDeclaringClass('property', 'test')->getClassName(); + $this->assertEquals($noParentClassName, $declaringClassName); + + $className = 'Doctrine\\Tests\\Common\\Reflection\\SameNamespaceParent'; + $staticReflectionParser = new StaticReflectionParser($className, new Psr0FindFile($paths)); + $declaringClassName = $staticReflectionParser->getStaticReflectionParserForDeclaringClass('property', 'test')->getClassName(); + $this->assertEquals($noParentClassName, $declaringClassName); + + $dummyParentClassName = 'Doctrine\\Tests\\Common\\Reflection\\Dummies\\NoParent'; + + $className = 'Doctrine\\Tests\\Common\\Reflection\\DeeperNamespaceParent'; + $staticReflectionParser = new StaticReflectionParser($className, new Psr0FindFile($paths)); + $declaringClassName = $staticReflectionParser->getStaticReflectionParserForDeclaringClass('property', 'test')->getClassName(); + $this->assertEquals($dummyParentClassName, $declaringClassName); + + $className = 'Doctrine\\Tests\\Common\\Reflection\\UseParent'; + $staticReflectionParser = new StaticReflectionParser($className, new Psr0FindFile($paths)); + $declaringClassName = $staticReflectionParser->getStaticReflectionParserForDeclaringClass('property', 'test')->getClassName(); + $this->assertEquals($dummyParentClassName, $declaringClassName); + + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/UseParent.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/UseParent.php new file mode 100644 index 0000000..dd512d4 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Reflection/UseParent.php @@ -0,0 +1,9 @@ +assertEquals($expectedClassName, ClassUtils::getRealClass($className)); + } + + /** + * @dataProvider dataGetClass + */ + public function testGetClass( $className, $expectedClassName ) + { + $object = new $className(); + $this->assertEquals($expectedClassName, ClassUtils::getClass($object)); + } + + public function testGetParentClass() + { + $parentClass = ClassUtils::getParentClass( 'MyProject\Proxies\__CG__\OtherProject\Proxies\__CG__\Doctrine\Tests\Common\Util\ChildObject' ); + $this->assertEquals('stdClass', $parentClass); + } + + public function testGenerateProxyClassName() + { + $this->assertEquals( 'Proxies\__CG__\stdClass', ClassUtils::generateProxyClassName( 'stdClass', 'Proxies' ) ); + } + + /** + * @dataProvider dataGetClass + */ + public function testNewReflectionClass( $className, $expectedClassName ) + { + $reflClass = ClassUtils::newReflectionClass( $className ); + $this->assertEquals( $expectedClassName, $reflClass->getName() ); + } + + /** + * @dataProvider dataGetClass + */ + public function testNewReflectionObject( $className, $expectedClassName ) + { + $object = new $className; + $reflClass = ClassUtils::newReflectionObject( $object ); + $this->assertEquals( $expectedClassName, $reflClass->getName() ); + } + } + + class ChildObject extends \stdClass + { + } +} + +namespace MyProject\Proxies\__CG__ +{ + class stdClass extends \stdClass + { + } +} + +namespace MyProject\Proxies\__CG__\Doctrine\Tests\Common\Util +{ + class ChildObject extends \Doctrine\Tests\Common\Util\ChildObject + { + } +} + +namespace MyProject\Proxies\__CG__\OtherProject\Proxies\__CG__ +{ + class stdClass extends \MyProject\Proxies\__CG__\stdClass + { + } +} + +namespace MyProject\Proxies\__CG__\OtherProject\Proxies\__CG__\Doctrine\Tests\Common\Util +{ + class ChildObject extends \MyProject\Proxies\__CG__\Doctrine\Tests\Common\Util\ChildObject + { + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/Common/Util/DebugTest.php b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Util/DebugTest.php new file mode 100644 index 0000000..b4e9eed --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/Common/Util/DebugTest.php @@ -0,0 +1,27 @@ +foo = "bar"; + $obj->bar = 1234; + + $var = Debug::export($obj, 2); + $this->assertEquals( "stdClass", $var->__CLASS__ ); + } + + public function testExportDateTime() + { + $obj = new \DateTime( "2010-10-10 10:10:10" ); + + $var = Debug::export( $obj, 2 ); + $this->assertEquals( "DateTime", $var->__CLASS__ ); + } +} diff --git a/vendor/doctrine/common/tests/Doctrine/Tests/DoctrineTestCase.php b/vendor/doctrine/common/tests/Doctrine/Tests/DoctrineTestCase.php new file mode 100644 index 0000000..e8323d2 --- /dev/null +++ b/vendor/doctrine/common/tests/Doctrine/Tests/DoctrineTestCase.php @@ -0,0 +1,10 @@ + + */ +class NativePhpunitTask extends Task +{ + private $test; + private $testfile; + private $testdirectory; + private $configuration = null; + private $coverageClover = null; + private $junitlogfile = null; + private $haltonfailure = true; + private $haltonerror = true; + + public function setTestdirectory($directory) { + $this->testdirectory = $directory; + } + + public function setTest($test) { + $this->test = $test; + } + + public function setTestfile($testfile) { + $this->testfile = $testfile; + } + + public function setJunitlogfile($junitlogfile) { + if (strlen($junitlogfile) == 0) { + $junitlogfile = NULL; + } + + $this->junitlogfile = $junitlogfile; + } + + public function setConfiguration($configuration) { + if (strlen($configuration) == 0) { + $configuration = NULL; + } + + $this->configuration = $configuration; + } + + public function setCoverageClover($coverageClover) { + if (strlen($coverageClover) == 0) { + $coverageClover = NULL; + } + + $this->coverageClover = $coverageClover; + } + + public function setHaltonfailure($haltonfailures) { + $this->haltonfailure = $haltonfailures; + } + + public function setHaltonerror($haltonerrors) { + $this->haltonerror = $haltonerrors; + } + + public function init() + { + require_once "PHPUnit/Runner/Version.php"; + $version = PHPUnit_Runner_Version::id(); + + if (version_compare($version, '3.4.0') < 0) { + throw new BuildException("NativePHPUnitTask requires PHPUnit version >= 3.2.0", $this->getLocation()); + } + + require_once 'PHPUnit/Util/Filter.php'; + + // point PHPUnit_MAIN_METHOD define to non-existing method + if (!defined('PHPUnit_MAIN_METHOD')) { + define('PHPUnit_MAIN_METHOD', 'PHPUnitTask::undefined'); + } + } + + public function main() + { + if (!is_dir(realpath($this->testdirectory))) { + throw new BuildException("NativePHPUnitTask requires a Test Directory path given, '".$this->testdirectory."' given."); + } + set_include_path(realpath($this->testdirectory) . PATH_SEPARATOR . get_include_path()); + + $printer = new NativePhpunitPrinter(); + + $arguments = array( + 'configuration' => $this->configuration, + 'coverageClover' => $this->coverageClover, + 'junitLogfile' => $this->junitlogfile, + 'printer' => $printer, + ); + + $runner = new PHPUnit_TextUI_TestRunner(); + $suite = $runner->getTest($this->test, $this->testfile, true); + + try { + $result = $runner->doRun($suite, $arguments); + /* @var $result PHPUnit_Framework_TestResult */ + + if ( ($this->haltonfailure && $result->failureCount() > 0) || ($this->haltonerror && $result->errorCount() > 0) ) { + throw new BuildException("PHPUnit: ".$result->failureCount()." Failures and ".$result->errorCount()." Errors, ". + "last failure message: ".$printer->getMessages()); + } + + $this->log("PHPUnit Success: ".count($result->passed())." tests passed, no ". + "failures (".$result->skippedCount()." skipped, ".$result->notImplementedCount()." not implemented)"); + + // Hudson for example doesn't like the backslash in class names + if (file_exists($this->coverageClover)) { + $this->log("Generated Clover Coverage XML to: ".$this->coverageClover); + $content = file_get_contents($this->coverageClover); + $content = str_replace("\\", ".", $content); + file_put_contents($this->coverageClover, $content); + unset($content); + } + + } catch(\Exception $e) { + throw new BuildException("NativePhpunitTask failed: ".$e->getMessage()); + } + } +} + +class NativePhpunitPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener +{ + private $_messages = array(); + + public function write($buffer) + { + // do nothing + } + + public function getMessages() + { + return $this->_messages; + } + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->_messages[] = "Test ERROR: ".$test->getName().": ".$e->getMessage(); + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + $this->_messages[] = "Test FAILED: ".$test->getName().": ".$e->getMessage(); + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + + } + + /** + * A test suite started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + + } + + /** + * A test suite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + + } +} diff --git a/vendor/doctrine/common/tests/README.markdown b/vendor/doctrine/common/tests/README.markdown new file mode 100644 index 0000000..e6f1703 --- /dev/null +++ b/vendor/doctrine/common/tests/README.markdown @@ -0,0 +1,27 @@ +# Running the Doctrine 2 Testsuite + +## Running tests + +Execute PHPUnit in the root folder of your doctrine-common clone. + + phpunit + +## Testing Lock-Support + +The Lock support in Doctrine 2 is tested using Gearman, which allows to run concurrent tasks in parallel. +Install Gearman with PHP as follows: + +1. Go to http://www.gearman.org and download the latest Gearman Server +2. Compile it and then call ldconfig +3. Start it up "gearmand -vvvv" +4. Install pecl/gearman by calling "gearman-beta" + +You can then go into tests/ and start up two workers: + + php Doctrine/Tests/ORM/Functional/Locking/LockAgentWorker.php + +Then run the locking test-suite: + + phpunit --configuration Doctrine/Tests/ORM/Functional/Locking/GearmanLockTest.php + +This can run considerable time, because it is using sleep() to test for the timing ranges of locks. \ No newline at end of file diff --git a/vendor/doctrine/dbal/.gitignore b/vendor/doctrine/dbal/.gitignore new file mode 100644 index 0000000..a9b57aa --- /dev/null +++ b/vendor/doctrine/dbal/.gitignore @@ -0,0 +1,6 @@ +build/ +logs/ +reports/ +dist/ +download/ +lib/Doctrine/Common/ diff --git a/vendor/doctrine/dbal/.gitmodules b/vendor/doctrine/dbal/.gitmodules new file mode 100644 index 0000000..00dc3fa --- /dev/null +++ b/vendor/doctrine/dbal/.gitmodules @@ -0,0 +1,9 @@ +[submodule "lib/vendor/doctrine-common"] + path = lib/vendor/doctrine-common + url = git://github.com/doctrine/common.git +[submodule "lib/vendor/Symfony/Component/Console"] + path = lib/vendor/Symfony/Component/Console + url = git://github.com/symfony/Console.git +[submodule "lib/vendor/doctrine-build-common"] + path = lib/vendor/doctrine-build-common + url = git://github.com/doctrine/doctrine-build-common.git diff --git a/vendor/doctrine/dbal/.travis.yml b/vendor/doctrine/dbal/.travis.yml new file mode 100644 index 0000000..da89c60 --- /dev/null +++ b/vendor/doctrine/dbal/.travis.yml @@ -0,0 +1,22 @@ +language: php + +php: + - 5.3 + - 5.4 +env: + - DB=mysql + - DB=pgsql + - DB=sqlite + - DB=mysqli + +before_script: + - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS doctrine_tests;' -U postgres; fi" + - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS doctrine_tests_tmp;' -U postgres; fi" + - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests;' -U postgres; fi" + - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests_tmp;' -U postgres; fi" + - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS doctrine_tests_tmp;create database IF NOT EXISTS doctrine_tests;'; fi" + - sh -c "if [ '$DB' = 'mysqli' ]; then mysql -e 'create database IF NOT EXISTS doctrine_tests_tmp;create database IF NOT EXISTS doctrine_tests;'; fi" + - git submodule update --init + +script: phpunit --configuration tests/travis/$DB.travis.xml + diff --git a/vendor/doctrine/dbal/LICENSE b/vendor/doctrine/dbal/LICENSE new file mode 100644 index 0000000..4a91f0b --- /dev/null +++ b/vendor/doctrine/dbal/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2012 Doctrine Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/doctrine/dbal/README.md b/vendor/doctrine/dbal/README.md new file mode 100644 index 0000000..c88f9e6 --- /dev/null +++ b/vendor/doctrine/dbal/README.md @@ -0,0 +1,14 @@ +# Doctrine DBAL + +Powerful database abstraction layer with many features for database schema introspection, schema management and PDO abstraction. + +* Master: [![Build Status](https://secure.travis-ci.org/doctrine/dbal.png?branch=master)](http://travis-ci.org/doctrine/dbal) +* 2.2: [![Build Status](https://secure.travis-ci.org/doctrine/dbal.png?branch=2.2)](http://travis-ci.org/doctrine/dbal) +* 2.1.x: [![Build Status](https://secure.travis-ci.org/doctrine/dbal.png?branch=2.1.x)](http://travis-ci.org/doctrine/dbal) + +## More resources: + +* [Website](http://www.doctrine-project.org) +* [Documentation](http://www.doctrine-project.org/projects/dbal/current/docs/en) +* [Issue Tracker](http://www.doctrine-project.org/jira/browse/DBAL) +* [Downloads](http://github.com/doctrine/dbal/downloads) diff --git a/vendor/doctrine/dbal/UPGRADE b/vendor/doctrine/dbal/UPGRADE new file mode 100644 index 0000000..36ca80e --- /dev/null +++ b/vendor/doctrine/dbal/UPGRADE @@ -0,0 +1,148 @@ +# Upgrade to 2.3 + +## Oracle Session Init now sets Numeric Character + +Before 2.3 the Oracle Session Init did not care about the numeric character of the Session. +This could lead to problems on non english locale systems that required a comma as a floating +point seperator in Oracle. Since 2.3, using the Oracle Session Init on connection start the +client session will be altered to set the numeric character to ".,": + + ALTER SESSION SET NLS_NUMERIC_CHARACTERS = '.,' + +See [DBAL-345](http://www.doctrine-project.org/jira/browse/DBAL-345) for more details. + +## Doctrine\DBAL\Connection and Doctrine\DBAL\Statement + +The query related methods including but not limited to executeQuery, exec, query, and executeUpdate +now wrap the driver exceptions such as PDOException with DBALException to add more debugging +information such as the executed SQL statement, and any bound parameters. + +If you want to retrieve the driver specific exception, you can retrieve it by calling the +``getPrevious()`` method on DBALException. + +Before: + + catch(\PDOException $ex) { + // ... + } + +After: + + catch(\Doctrine\DBAL\DBALException $ex) { + $pdoException = $ex->getPrevious(); + // ... + } + +## Doctrine\DBAL\Connection#setCharsetSQL() removed + +This method only worked on MySQL and it is considered unsafe on MySQL to use SET NAMES UTF-8 instead +of setting the charset directly on connection already. Replace this behavior with the +connection charset option: + +Before: + + $conn = DriverManager::getConnection(array(..)); + $conn->setCharset('UTF8'); + +After: + + $conn = DriverManager::getConnection(array('charset' => 'UTF8', ..)); + +## Doctrine\DBAL\Schema\Table#renameColumn() removed + +Doctrine\DBAL\Schema\Table#renameColumn() was removed, because it drops and recreates +the column instead. There is no fix available, because a schema diff +cannot reliably detect if a column was renamed or one column was created +and another one dropped. + +You should use explicit SQL ALTER TABLE statements to change columns names. + +## Schema Filter paths + +The Filter Schema assets expression is not wrapped in () anymore for the regexp automatically. + +Before: + + $config->setFilterSchemaAssetsExpression('foo'); + +After: + + $config->setFilterSchemaAssetsExpression('(foo)'); + +## Creating MySQL Tables now defaults to UTF-8 + +If you are creating a new MySQL Table through the Doctrine API, charset/collate are +now set to 'utf8'/'utf8_unicode_ci' by default. Previously the MySQL server defaults were used. + +# Upgrade to 2.2 + +## Doctrine\DBAL\Connection#insert and Doctrine\DBAL\Connnection#update + +Both methods now accept an optional last parameter $types with binding types of the values passed. +This can potentially break child classes that have overwritten one of these methods. + +## Doctrine\DBAL\Connection#executeQuery + +Doctrine\DBAL\Connection#executeQuery() got a new last parameter "QueryCacheProfile $qcp" + +## Doctrine\DBAL\Driver\Statement split + +The Driver statement was split into a ResultStatement and the normal statement extending from it. +This seperates the configuration and the retrieval API from a statement. + +## MsSql Platform/SchemaManager renamed + +The MsSqlPlatform was renamed to SQLServerPlatform, the MsSqlSchemaManager was renamed +to SQLServerSchemaManager. + +## Cleanup SQLServer Platform version mess + +DBAL 2.1 and before were actually only compatible to SQL Server 2008, not earlier versions. +Still other parts of the platform did use old features instead of newly introduced datatypes +in SQL Server 2005. Starting with DBAL 2.2 you can pick the Doctrine abstraction exactly +matching your SQL Server version. + +The PDO SqlSrv driver now uses the new `SQLServer2008Platform` as default platform. +This platform uses new features of SQL Server as of version 2008. This also includes a switch +in the used fields for "text" and "blob" field types to: + + "text" => "VARCHAR(MAX)" + "blob" => "VARBINARY(MAX)" + +Additionally `SQLServerPlatform` in DBAL 2.1 and before used "DATE", "TIME" and "DATETIME2" for dates. +This types are only available since version 2008 and the introduction of an explicit +SQLServer 2008 platform makes this dependency explicit. + +An `SQLServer2005Platform` was also introduced to differentiate the features between +versions 2003, earlier and 2005. + +With this change the `SQLServerPlatform` now throws an exception for using limit queries +with an offset, since SQLServer 2003 and lower do not support this feature. + +To use the old SQL Server Platform, because you are using SQL Server 2003 and below use +the following configuration code: + + use Doctrine\DBAL\DriverManager; + use Doctrine\DBAL\Platforms\SQLServerPlatform; + use Doctrine\DBAL\Platforms\SQLServer2005Platform; + + // You are using SQL Server 2003 or earlier + $conn = DriverManager::getConnection(array( + 'driver' => 'pdo_sqlsrv', + 'platform' => new SQLServerPlatform() + // .. additional parameters + )); + + // You are using SQL Server 2005 + $conn = DriverManager::getConnection(array( + 'driver' => 'pdo_sqlsrv', + 'platform' => new SQLServer2005Platform() + // .. additional parameters + )); + + // You are using SQL Server 2008 + $conn = DriverManager::getConnection(array( + 'driver' => 'pdo_sqlsrv', + // 2008 is default platform + // .. additional parameters + )); diff --git a/vendor/doctrine/dbal/bin/doctrine-dbal b/vendor/doctrine/dbal/bin/doctrine-dbal new file mode 100644 index 0000000..7ca0142 --- /dev/null +++ b/vendor/doctrine/dbal/bin/doctrine-dbal @@ -0,0 +1,4 @@ +#!/usr/bin/env php +register(); + +$classLoader = new \Doctrine\Common\ClassLoader('Symfony', 'Doctrine'); +$classLoader->register(); + +$configFile = getcwd() . DIRECTORY_SEPARATOR . 'cli-config.php'; + +$helperSet = null; +if (file_exists($configFile)) { + if ( ! is_readable($configFile)) { + trigger_error( + 'Configuration file [' . $configFile . '] does not have read permission.', E_ERROR + ); + } + + require $configFile; + + foreach ($GLOBALS as $helperSetCandidate) { + if ($helperSetCandidate instanceof \Symfony\Component\Console\Helper\HelperSet) { + $helperSet = $helperSetCandidate; + break; + } + } +} + +$helperSet = ($helperSet) ?: new \Symfony\Component\Console\Helper\HelperSet(); + +$cli = new \Symfony\Component\Console\Application('Doctrine Command Line Interface', Doctrine\DBAL\Version::VERSION); +$cli->setCatchExceptions(true); +$cli->setHelperSet($helperSet); +$cli->addCommands(array( + // DBAL Commands + new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(), + new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(), + new \Doctrine\DBAL\Tools\Console\Command\ReservedWordsCommand(), + +)); +$cli->run(); \ No newline at end of file diff --git a/vendor/doctrine/dbal/bin/doctrine.php b/vendor/doctrine/dbal/bin/doctrine.php new file mode 100644 index 0000000..cd3184d --- /dev/null +++ b/vendor/doctrine/dbal/bin/doctrine.php @@ -0,0 +1,42 @@ +register(); + +$classLoader = new \Doctrine\Common\ClassLoader('Symfony'); +$classLoader->register(); + +$configFile = getcwd() . DIRECTORY_SEPARATOR . 'cli-config.php'; + +$helperSet = null; +if (file_exists($configFile)) { + if ( ! is_readable($configFile)) { + trigger_error( + 'Configuration file [' . $configFile . '] does not have read permission.', E_ERROR + ); + } + + require $configFile; + + foreach ($GLOBALS as $helperSetCandidate) { + if ($helperSetCandidate instanceof \Symfony\Component\Console\Helper\HelperSet) { + $helperSet = $helperSetCandidate; + break; + } + } +} + +$helperSet = ($helperSet) ?: new \Symfony\Component\Console\Helper\HelperSet(); + +$cli = new \Symfony\Component\Console\Application('Doctrine Command Line Interface', Doctrine\DBAL\Version::VERSION); +$cli->setCatchExceptions(true); +$cli->setHelperSet($helperSet); +$cli->addCommands(array( + // DBAL Commands + new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(), + new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(), + +)); +$cli->run(); diff --git a/vendor/doctrine/dbal/build.properties b/vendor/doctrine/dbal/build.properties new file mode 100644 index 0000000..12b5e8f --- /dev/null +++ b/vendor/doctrine/dbal/build.properties @@ -0,0 +1,10 @@ +# Project Name +project.name=DoctrineDBAL + +# Dependency minimum versions +dependencies.common=2.0.1 +dependencies.sfconsole=2.0.0 + +# Version class and file +project.version_class = Doctrine\DBAL\Version +project.version_file = lib/Doctrine/DBAL/Version.php diff --git a/vendor/doctrine/dbal/build.xml b/vendor/doctrine/dbal/build.xml new file mode 100644 index 0000000..0fb05ff --- /dev/null +++ b/vendor/doctrine/dbal/build.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${project.name} + Doctrine Database Abstraction Layer + pear.doctrine-project.org + The Doctrine DBAL package is the database abstraction layer used to power the ORM package. + + + + + LGPL + + + - + + + + + + + script + Doctrine/Common/ + Doctrine/Symfony/ + + + + + + + diff --git a/vendor/doctrine/dbal/composer.json b/vendor/doctrine/dbal/composer.json new file mode 100644 index 0000000..f500996 --- /dev/null +++ b/vendor/doctrine/dbal/composer.json @@ -0,0 +1,26 @@ +{ + "name": "doctrine/dbal", + "type": "library","version":"2.3.0", + "description": "Database Abstraction Layer", + "keywords": ["dbal", "database", "persistence", "queryobject"], + "homepage": "http://www.doctrine-project.org", + "license": "MIT", + "authors": [ + {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, + {"name": "Roman Borschel", "email": "roman@code-factory.org"}, + {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, + {"name": "Jonathan Wage", "email": "jonwage@gmail.com"} + ], + "require": { + "php": ">=5.3.2", + "doctrine/common": "2.3.*" + }, + "autoload": { + "psr-0": { "Doctrine\\DBAL": "lib/" } + }, + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + } +} diff --git a/vendor/doctrine/dbal/docs/design/AZURE_FEDERATIONS.md b/vendor/doctrine/dbal/docs/design/AZURE_FEDERATIONS.md new file mode 100644 index 0000000..99d7e3c --- /dev/null +++ b/vendor/doctrine/dbal/docs/design/AZURE_FEDERATIONS.md @@ -0,0 +1,94 @@ +# Azure Federations + +Implementing Federations inside a new Doctrine Sharding Extension. Some extensions to the DBAL and ORM core have to be done to get this working. + +1. DBAL (Database Abstraction Layer) + +* Add support for Database Schema Operations + * CREATE FEDERATION + * CREATE TABLE ... FEDERATED ON + * Add support to create a multi-tenent schema from any given schema +* Add API to pick a shard based on distribution key and atomic value +* Add API to ask about federations, federation members and so on. +* Add Sharding Abstraction + * If a shard is picked via distribution key and atomic value fire queries against this only + * Or query the global database. + +2. ORM (Object-Relational Mapper) + +* Federation Key has to be part of the clustered index of the table + * Test with a pure Multi-Tenent App with Filtering = ON (TaskList) + * Test with sharded app (Weather) + +## Implementation Details + +SQL Azure requires one and exactly one clustered index. It makes no difference if the primary key +or any other key is the clustered index. Sharding requires an external ID generation (no auto-increment) +such as GUIDs. GUIDs have negative properties with regard to clustered index performance, so that +typically you would add a "created" timestamp for example that holds the clustered index instead +of making the GUID a clustered index. + +## Example API: + + @@@ php + 'tcp:dbname.database.windows.net', + 'sharding' => array( + 'federationName' => 'Orders_Federation', + 'distributionKey' => 'CustID', + 'distributionType' => 'integer', + 'filteringEnabled' => false, + ), + // ... + ); + + $conn = DriverManager::getConnection($dbParams); + $shardManager = $conn->getShardManager(); + + // Example 1: query against root database + $sql = "SELECT * FROM Products"; + $rows = $conn->executeQuery($sql); + + // Example 2: query against the selected shard with CustomerId = 100 + $aCustomerID = 100; + $shardManager->selectShard($aCustomerID); // Using Default federationName and distributionKey + // Query: "USE FEDERATION Orders_Federation (CustID = $aCustomerID) WITH RESET, FILTERING OFF;" + + $sql = "SELECT * FROM Customers"; + $rows = $conn->executeQuery($sql); + + // Example 3: Reset API to root database again + $shardManager->selectGlobal(); + +## ID Generation + +With sharding all the ids have to be generated for global uniqueness. There are three strategies for this. + +1. Use GUIDs as described here http://blogs.msdn.com/b/cbiyikoglu/archive/2011/06/20/id-generation-in-federations-identity-sequences-and-guids-uniqueidentifier.aspx +2. Having a central table that is accessed with a second connection to generate sequential ids +3. Using natural keys from the domain. + +The second approach has the benefit of having numerical primary keys, however also a central failure location. The third strategy can seldom be used, because the domains dont allow this. Identity columns cannot be used at all. + + @@@ php + 'dbname.database.windows.net', + // ... + ); + $conn = DriverManager::getConnection($dbParams); + + $idGenerator = new TableHiLoIdGenerator($conn, 'id_table_name', $multiplicator = 1); + // only once, create this table + $idGenerator->createTable(); + + $nextId = $idGenerator->generateId('for_table_name'); + $nextOtherId = $idGenerator->generateId('for_other_table'); + +The connection for the table generator has to be a different one than the one used for the main app to avoid transaction clashes. diff --git a/vendor/doctrine/dbal/docs/design/SHARDING.md b/vendor/doctrine/dbal/docs/design/SHARDING.md new file mode 100644 index 0000000..24e6cef --- /dev/null +++ b/vendor/doctrine/dbal/docs/design/SHARDING.md @@ -0,0 +1,74 @@ +# Doctrine Shards + +Doctrine Extension to support horizontal sharding in the Doctrine ORM. + +## Idea + +Implement sharding inside Doctrine at a level that is as unobtrusive to the developer as possible. + +Problems to tackle: + +1. Where to send INSERT statements? +2. How to generate primary keys? +3. How to pick shards for update, delete statements? +4. How to pick shards for select operations? +5. How to merge select queries that span multiple shards? +6. How to handle/prevent multi-shard queries that cannot be merged (GROUP BY)? +7. How to handle non-sharded data? (static metadata tables for example) +8. How to handle multiple connections? +9. Implementation on the DBAL or ORM level? + +## Roadmap + +Version 1: DBAL 2.3 (Multi-Tenant Apps) + + 1. ID Generation support (in DBAL + ORM done) + 2. Multi-Tenant Support: Either pick a global metadata database or exactly one shard. + 3. Fan-out queries over all shards (or a subset) by result appending + +Version 2: ORM related (complex): + + 4. ID resolving (Pick shard for a new ID) + 5. Query resolving (Pick shards a query should send to) + 6. Shard resolving (Pick shards an ID could be on) + 7. Transactions + 8. Read Only objects + +## Technical Requirements for Database Schemas + +Sharded tables require the sharding-distribution key as one of their columns. This will affect your code compared to a normalized db-schema. If you have a Blog <-> BlogPost <-> PostComments entity setup sharded by `blog_id` then even the PostComment table needs this column, even if an "unsharded", normalized DB-Schema does not need this information. + +## Implementation Details + +Assumptions: + +* For querying you either want to query ALL or just exactly one shard. +* IDs for ALL sharded tables have to be unique across all shards. +* Non-shareded data is replicated between all shards. They redundantly keep the information available. This is necessary so join queries on shards to reference data work. +* If you retrieve an object A from a shard, then all references and collections of this object reside on the same shard. +* The database schema on all shards is the same (or compatible) + +### SQL Azure Federations + +SQL Azure is a special case, points 1, 2, 3, 4, 7 and 8 are partly handled on the database level. This makes it a perfect test-implementation for just the subset of features in points 5-6. However there need to be a way to configure SchemaTool to generate the correct Schema on SQL Azure. + +* SELECT Operations: The most simple assumption is to always query all shards unless the user specifies otherwise explicitly. +* Queries can be merged in PHP code, this obviously does not work for DISTINCT, GROUP BY and ORDER BY queries. + +### Generic Sharding + +More features are necessary to implement sharding on the PHP level, independent from database support: + +1. Configuration of multiple connections, one connection = one shard. +2. Primary Key Generation mechanisms (UUID, central table, sequence emulation) + +## Primary Use-Cases + +1. Multi-Tenant Applications + +These are easier to support as you have some value to determine the shard id for the whole request very early on. +Here also queries can always be limited to a single shard. + +2. Scale-Out by some attribute (Round-Robin?) + +This strategy requires access to multiple shards in a single request based on the data accessed. diff --git a/vendor/doctrine/dbal/docs/examples/sharding/README.md b/vendor/doctrine/dbal/docs/examples/sharding/README.md new file mode 100644 index 0000000..3680e54 --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/README.md @@ -0,0 +1,26 @@ +# Sharding with SQLAzure Example + +This example demonstrates Sharding with SQL Azure Federations. + +## Requirements + +1. Windows Azure Account +2. SQL Azure Database +3. Composer for dependencies + +## Install + + composer install + +Change "examples/sharding/bootstrap.php" to contain Database connection. + +## Order to execute Scripts + +1. create_schema.php +2. view_federation_members.php +3. insert_data.php +4. split_federation.php +5. insert_data_after_split.php +6. query_filtering_off.php +7. query_filtering_on.php + diff --git a/vendor/doctrine/dbal/docs/examples/sharding/bootstrap.php b/vendor/doctrine/dbal/docs/examples/sharding/bootstrap.php new file mode 100644 index 0000000..fe174f1 --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/bootstrap.php @@ -0,0 +1,26 @@ + 'SalesDB', + 'host' => 'tcp:dbname.windows.net', + 'user' => 'user@dbname', + 'password' => 'XXX', + 'sharding' => array( + 'federationName' => 'Orders_Federation', + 'distributionKey' => 'CustId', + 'distributionType' => 'integer', + ) +); + +if ($config['host'] == "tcp:dbname.windows.net") { + die("You have to change the configuration to your Azure account.\n"); +} + +$conn = DriverManager::getConnection($config); +$shardManager = new SQLAzureShardManager($conn); + diff --git a/vendor/doctrine/dbal/docs/examples/sharding/composer.json b/vendor/doctrine/dbal/docs/examples/sharding/composer.json new file mode 100644 index 0000000..214f922 --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/composer.json @@ -0,0 +1,6 @@ +{ + "require": { + "doctrine/dbal": "*", + "doctrine/shards": "0.3" + } +} diff --git a/vendor/doctrine/dbal/docs/examples/sharding/create_schema.php b/vendor/doctrine/dbal/docs/examples/sharding/create_schema.php new file mode 100644 index 0000000..ac6b66c --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/create_schema.php @@ -0,0 +1,51 @@ +createTable('Products'); +$products->addColumn('ProductID', 'integer'); +$products->addColumn('SupplierID', 'integer'); +$products->addColumn('ProductName', 'string'); +$products->addColumn('Price', 'decimal', array('scale' => 2, 'precision' => 12)); +$products->setPrimaryKey(array('ProductID')); +$products->addOption('azure.federated', true); + +$customers = $schema->createTable('Customers'); +$customers->addColumn('CustomerID', 'integer'); +$customers->addColumn('CompanyName', 'string'); +$customers->addColumn('FirstName', 'string'); +$customers->addColumn('LastName', 'string'); +$customers->setPrimaryKey(array('CustomerID')); +$customers->addOption('azure.federated', true); +$customers->addOption('azure.federatedOnColumnName', 'CustomerID'); + +$orders = $schema->createTable('Orders'); +$orders->addColumn('CustomerID', 'integer'); +$orders->addColumn('OrderID', 'integer'); +$orders->addColumn('OrderDate', 'datetime'); +$orders->setPrimaryKey(array('CustomerID', 'OrderID')); +$orders->addOption('azure.federated', true); +$orders->addOption('azure.federatedOnColumnName', 'CustomerID'); + +$orderItems = $schema->createTable('OrderItems'); +$orderItems->addColumn('CustomerID', 'integer'); +$orderItems->addColumn('OrderID', 'integer'); +$orderItems->addColumn('ProductID', 'integer'); +$orderItems->addColumn('Quantity', 'integer'); +$orderItems->setPrimaryKey(array('CustomerID', 'OrderID', 'ProductID')); +$orderItems->addOption('azure.federated', true); +$orderItems->addOption('azure.federatedOnColumnName', 'CustomerID'); + +// Create the Schema + Federation: +$synchronizer = new SQLAzureSchemaSynchronizer($conn, $shardManager); + +// Or jut look at the SQL: +echo implode("\n", $synchronizer->getCreateSchema($schema)); + +$synchronizer->createSchema($schema); + diff --git a/vendor/doctrine/dbal/docs/examples/sharding/insert_data.php b/vendor/doctrine/dbal/docs/examples/sharding/insert_data.php new file mode 100644 index 0000000..57aeda6 --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/insert_data.php @@ -0,0 +1,132 @@ +selectShard(0); + +$conn->insert("Products", array( + "ProductID" => 386, + "SupplierID" => 1001, + "ProductName" => 'Titanium Extension Bracket Left Hand', + "Price" => 5.25, +)); +$conn->insert("Products", array( + "ProductID" => 387, + "SupplierID" => 1001, + "ProductName" => 'Titanium Extension Bracket Right Hand', + "Price" => 5.25, +)); +$conn->insert("Products", array( + "ProductID" => 388, + "SupplierID" => 1001, + "ProductName" => 'Fusion Generator Module 5 kV', + "Price" => 10.50, +)); +$conn->insert("Products", array( + "ProductID" => 389, + "SupplierID" => 1001, + "ProductName" => 'Bypass Filter 400 MHz Low Pass', + "Price" => 10.50, +)); + +$conn->insert("Customers", array( + 'CustomerID' => 10, + 'CompanyName' => 'Van Nuys', + 'FirstName' => 'Catherine', + 'LastName' => 'Abel', +)); +$conn->insert("Customers", array( + 'CustomerID' => 20, + 'CompanyName' => 'Abercrombie', + 'FirstName' => 'Kim', + 'LastName' => 'Branch', +)); +$conn->insert("Customers", array( + 'CustomerID' => 30, + 'CompanyName' => 'Contoso', + 'FirstName' => 'Frances', + 'LastName' => 'Adams', +)); +$conn->insert("Customers", array( + 'CustomerID' => 40, + 'CompanyName' => 'A. Datum Corporation', + 'FirstName' => 'Mark', + 'LastName' => 'Harrington', +)); +$conn->insert("Customers", array( + 'CustomerID' => 50, + 'CompanyName' => 'Adventure Works', + 'FirstName' => 'Keith', + 'LastName' => 'Harris', +)); +$conn->insert("Customers", array( + 'CustomerID' => 60, + 'CompanyName' => 'Alpine Ski House', + 'FirstName' => 'Wilson', + 'LastName' => 'Pais', +)); +$conn->insert("Customers", array( + 'CustomerID' => 70, + 'CompanyName' => 'Baldwin Museum of Science', + 'FirstName' => 'Roger', + 'LastName' => 'Harui', +)); +$conn->insert("Customers", array( + 'CustomerID' => 80, + 'CompanyName' => 'Blue Yonder Airlines', + 'FirstName' => 'Pilar', + 'LastName' => 'Pinilla', +)); +$conn->insert("Customers", array( + 'CustomerID' => 90, + 'CompanyName' => 'City Power & Light', + 'FirstName' => 'Kari', + 'LastName' => 'Hensien', +)); +$conn->insert("Customers", array( + 'CustomerID' => 100, + 'CompanyName' => 'Coho Winery', + 'FirstName' => 'Peter', + 'LastName' => 'Brehm', +)); + +$conn->executeUpdate(" + DECLARE @orderId INT + + DECLARE @customerId INT + + SET @orderId = 10 + SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Hensien' and FirstName = 'Kari' + + INSERT INTO Orders (CustomerId, OrderId, OrderDate) + VALUES (@customerId, @orderId, GetDate()) + + INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) + VALUES (@customerId, @orderId, 388, 4) + + SET @orderId = 20 + SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Harui' and FirstName = 'Roger' + + INSERT INTO Orders (CustomerId, OrderId, OrderDate) + VALUES (@customerId, @orderId, GetDate()) + + INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) + VALUES (@customerId, @orderId, 389, 2) + + SET @orderId = 30 + SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Brehm' and FirstName = 'Peter' + + INSERT INTO Orders (CustomerId, OrderId, OrderDate) + VALUES (@customerId, @orderId, GetDate()) + + INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) + VALUES (@customerId, @orderId, 387, 3) + + SET @orderId = 40 + SELECT @customerId = CustomerId FROM Customers WHERE LastName = 'Pais' and FirstName = 'Wilson' + + INSERT INTO Orders (CustomerId, OrderId, OrderDate) + VALUES (@customerId, @orderId, GetDate()) + + INSERT INTO OrderItems (CustomerID, OrderID, ProductID, Quantity) + VALUES (@customerId, @orderId, 388, 1)"); diff --git a/vendor/doctrine/dbal/docs/examples/sharding/insert_data_aftersplit.php b/vendor/doctrine/dbal/docs/examples/sharding/insert_data_aftersplit.php new file mode 100644 index 0000000..312e90b --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/insert_data_aftersplit.php @@ -0,0 +1,27 @@ +selectShard($newCustomerId); + +$conn->insert("Customers", array( + "CustomerID" => $newCustomerId, + "CompanyName" => "Microsoft", + "FirstName" => "Brian", + "LastName" => "Swan", +)); + +$conn->insert("Orders", array( + "CustomerID" => 55, + "OrderID" => 37, + "OrderDate" => date('Y-m-d H:i:s'), +)); + +$conn->insert("OrderItems", array( + "CustomerID" => 55, + "OrderID" => 37, + "ProductID" => 387, + "Quantity" => 1, +)); diff --git a/vendor/doctrine/dbal/docs/examples/sharding/query_filtering_off.php b/vendor/doctrine/dbal/docs/examples/sharding/query_filtering_off.php new file mode 100644 index 0000000..c0b24fa --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/query_filtering_off.php @@ -0,0 +1,8 @@ +selectShard(0); + +$data = $conn->fetchAll('SELECT * FROM Customers'); +print_r($data); diff --git a/vendor/doctrine/dbal/docs/examples/sharding/query_filtering_on.php b/vendor/doctrine/dbal/docs/examples/sharding/query_filtering_on.php new file mode 100644 index 0000000..e7d9e14 --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/query_filtering_on.php @@ -0,0 +1,9 @@ +setFilteringEnabled(true); +$shardManager->selectShard(55); + +$data = $conn->fetchAll('SELECT * FROM Customers'); +print_r($data); diff --git a/vendor/doctrine/dbal/docs/examples/sharding/split_federation.php b/vendor/doctrine/dbal/docs/examples/sharding/split_federation.php new file mode 100644 index 0000000..ff681ed --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/split_federation.php @@ -0,0 +1,5 @@ +splitFederation(60); diff --git a/vendor/doctrine/dbal/docs/examples/sharding/view_federation_members.php b/vendor/doctrine/dbal/docs/examples/sharding/view_federation_members.php new file mode 100644 index 0000000..497e4df --- /dev/null +++ b/vendor/doctrine/dbal/docs/examples/sharding/view_federation_members.php @@ -0,0 +1,8 @@ +getShards(); +foreach ($shards as $shard) { + print_r($shard); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ArrayStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ArrayStatement.php new file mode 100644 index 0000000..8ad167b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ArrayStatement.php @@ -0,0 +1,103 @@ +. + */ + +namespace Doctrine\DBAL\Cache; + +use Doctrine\DBAL\Driver\ResultStatement; +use PDO; + +class ArrayStatement implements \IteratorAggregate, ResultStatement +{ + private $data; + private $columnCount = 0; + private $num = 0; + private $defaultFetchMode = PDO::FETCH_BOTH; + + public function __construct(array $data) + { + $this->data = $data; + if (count($data)) { + $this->columnCount = count($data[0]); + } + } + + public function closeCursor() + { + unset ($this->data); + } + + public function columnCount() + { + return $this->columnCount; + } + + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + if ($arg2 !== null || $arg3 !== null) { + throw new \InvalidArgumentException("Caching layer does not support 2nd/3rd argument to setFetchMode()"); + } + + $this->defaultFetchMode = $fetchMode; + } + + public function getIterator() + { + $data = $this->fetchAll(); + return new \ArrayIterator($data); + } + + public function fetch($fetchMode = null) + { + if (isset($this->data[$this->num])) { + $row = $this->data[$this->num++]; + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + if ($fetchMode === PDO::FETCH_ASSOC) { + return $row; + } else if ($fetchMode === PDO::FETCH_NUM) { + return array_values($row); + } else if ($fetchMode === PDO::FETCH_BOTH) { + return array_merge($row, array_values($row)); + } else if ($fetchMode === PDO::FETCH_COLUMN) { + return reset($row); + } else { + throw new \InvalidArgumentException("Invalid fetch-style given for fetching result."); + } + } + return false; + } + + public function fetchAll($fetchMode = null) + { + $rows = array(); + while ($row = $this->fetch($fetchMode)) { + $rows[] = $row; + } + return $rows; + } + + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(PDO::FETCH_NUM); + if (!isset($row[$columnIndex])) { + // TODO: verify this is correct behavior + return false; + } + return $row[$columnIndex]; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/CacheException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/CacheException.php new file mode 100644 index 0000000..dd27477 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/CacheException.php @@ -0,0 +1,37 @@ +. + */ + +namespace Doctrine\DBAL\Cache; + +/** + * @author Benjamin Eberlei + * @since 2.2 + */ +class CacheException extends \Doctrine\DBAL\DBALException +{ + static public function noCacheKey() + { + return new self("No cache key was set."); + } + + static public function noResultDriverConfigured() + { + return new self("Trying to cache a query but no result driver is configured."); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/QueryCacheProfile.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/QueryCacheProfile.php new file mode 100644 index 0000000..54c34b9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/QueryCacheProfile.php @@ -0,0 +1,131 @@ +. + */ + +namespace Doctrine\DBAL\Cache; + +use Doctrine\Common\Cache\Cache; + +/** + * Query Cache Profile handles the data relevant for query caching. + * + * It is a value object, setter methods return NEW instances. + * + * @author Benjamin Eberlei + */ +class QueryCacheProfile +{ + /** + * @var Cache + */ + private $resultCacheDriver; + /** + * @var int + */ + private $lifetime = 0; + /** + * @var string + */ + private $cacheKey; + + /** + * @param int $lifetime + * @param string $cacheKey + * @param Cache $resultCache + */ + public function __construct($lifetime = 0, $cacheKey = null, Cache $resultCache = null) + { + $this->lifetime = $lifetime; + $this->cacheKey = $cacheKey; + $this->resultCacheDriver = $resultCache; + } + + /** + * @return Cache + */ + public function getResultCacheDriver() + { + return $this->resultCacheDriver; + } + + /** + * @return int + */ + public function getLifetime() + { + return $this->lifetime; + } + + /** + * @return string + */ + public function getCacheKey() + { + if ($this->cacheKey === null) { + throw CacheException::noCacheKey(); + } + return $this->cacheKey; + } + + /** + * Generate the real cache key from query, params and types. + * + * @param string $query + * @param array $params + * @param array $types + * @return array + */ + public function generateCacheKeys($query, $params, $types) + { + $realCacheKey = $query . "-" . serialize($params) . "-" . serialize($types); + // should the key be automatically generated using the inputs or is the cache key set? + if ($this->cacheKey === null) { + $cacheKey = sha1($realCacheKey); + } else { + $cacheKey = $this->cacheKey; + } + return array($cacheKey, $realCacheKey); + } + + /** + * @param Cache $cache + * @return QueryCacheProfile + */ + public function setResultCacheDriver(Cache $cache) + { + return new QueryCacheProfile($this->lifetime, $this->cacheKey, $cache); + } + + /** + * @param string|null $cacheKey + * @return QueryCacheProfile + */ + public function setCacheKey($cacheKey) + { + return new QueryCacheProfile($this->lifetime, $cacheKey, $this->resultCacheDriver); + } + + /** + * @param int $lifetime + * @return QueryCacheProfile + */ + public function setLifetime($lifetime) + { + return new QueryCacheProfile($lifetime, $this->cacheKey, $this->resultCacheDriver); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php new file mode 100644 index 0000000..f118e7c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php @@ -0,0 +1,239 @@ +. + */ + +namespace Doctrine\DBAL\Cache; + +use Doctrine\DBAL\Driver\Statement; +use Doctrine\DBAL\Driver\ResultStatement; +use Doctrine\DBAL\Connection; +use Doctrine\Common\Cache\Cache; +use PDO; + +/** + * Cache statement for SQL results. + * + * A result is saved in multiple cache keys, there is the originally specified + * cache key which is just pointing to result rows by key. The following things + * have to be ensured: + * + * 1. lifetime of the original key has to be longer than that of all the individual rows keys + * 2. if any one row key is missing the query has to be re-executed. + * + * Also you have to realize that the cache will load the whole result into memory at once to ensure 2. + * This means that the memory usage for cached results might increase by using this feature. + */ +class ResultCacheStatement implements \IteratorAggregate, ResultStatement +{ + /** + * @var \Doctrine\Common\Cache\Cache + */ + private $resultCache; + + /** + * + * @var string + */ + private $cacheKey; + + /** + * @var string + */ + private $realKey; + + /** + * @var int + */ + private $lifetime; + + /** + * @var Doctrine\DBAL\Driver\Statement + */ + private $statement; + + /** + * Did we reach the end of the statement? + * + * @var bool + */ + private $emptied = false; + + /** + * @var array + */ + private $data; + + /** + * @var int + */ + private $defaultFetchMode = PDO::FETCH_BOTH; + + /** + * @param Statement $stmt + * @param Cache $resultCache + * @param string $cacheKey + * @param string $realKey + * @param int $lifetime + */ + public function __construct(Statement $stmt, Cache $resultCache, $cacheKey, $realKey, $lifetime) + { + $this->statement = $stmt; + $this->resultCache = $resultCache; + $this->cacheKey = $cacheKey; + $this->realKey = $realKey; + $this->lifetime = $lifetime; + } + + /** + * Closes the cursor, enabling the statement to be executed again. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function closeCursor() + { + $this->statement->closeCursor(); + if ($this->emptied && $this->data !== null) { + $data = $this->resultCache->fetch($this->cacheKey); + if ( ! $data) { + $data = array(); + } + $data[$this->realKey] = $this->data; + + $this->resultCache->save($this->cacheKey, $data, $this->lifetime); + unset($this->data); + } + } + + /** + * columnCount + * Returns the number of columns in the result set + * + * @return integer Returns the number of columns in the result set represented + * by the PDOStatement object. If there is no result set, + * this method should return 0. + */ + public function columnCount() + { + return $this->statement->columnCount(); + } + + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->defaultFetchMode = $fetchMode; + } + + public function getIterator() + { + $data = $this->fetchAll(); + return new \ArrayIterator($data); + } + + /** + * fetch + * + * @see Query::HYDRATE_* constants + * @param integer $fetchMode Controls how the next row will be returned to the caller. + * This value must be one of the Query::HYDRATE_* constants, + * defaulting to Query::HYDRATE_BOTH + * + * @return mixed + */ + public function fetch($fetchMode = null) + { + if ($this->data === null) { + $this->data = array(); + } + + $row = $this->statement->fetch(PDO::FETCH_ASSOC); + if ($row) { + $this->data[] = $row; + + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + + if ($fetchMode == PDO::FETCH_ASSOC) { + return $row; + } else if ($fetchMode == PDO::FETCH_NUM) { + return array_values($row); + } else if ($fetchMode == PDO::FETCH_BOTH) { + return array_merge($row, array_values($row)); + } else if ($fetchMode == PDO::FETCH_COLUMN) { + return reset($row); + } else { + throw new \InvalidArgumentException("Invalid fetch-style given for caching result."); + } + } + $this->emptied = true; + return false; + } + + /** + * Returns an array containing all of the result set rows + * + * @param integer $fetchMode Controls how the next row will be returned to the caller. + * This value must be one of the Query::HYDRATE_* constants, + * defaulting to Query::HYDRATE_BOTH + * + * @return array + */ + public function fetchAll($fetchMode = null) + { + $rows = array(); + while ($row = $this->fetch($fetchMode)) { + $rows[] = $row; + } + return $rows; + } + + /** + * fetchColumn + * Returns a single column from the next row of a + * result set or FALSE if there are no more rows. + * + * @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. If no + * value is supplied, PDOStatement->fetchColumn() + * fetches the first column. + * + * @return string returns a single column in the next row of a result set. + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(PDO::FETCH_NUM); + if (!isset($row[$columnIndex])) { + // TODO: verify this is correct behavior + return false; + } + return $row[$columnIndex]; + } + + /** + * rowCount + * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement + * executed by the corresponding object. + * + * If the last SQL statement executed by the associated Statement object was a SELECT statement, + * some databases may return the number of rows returned by that statement. However, + * this behaviour is not guaranteed for all databases and should not be + * relied on for portable applications. + * + * @return integer Returns the number of rows. + */ + public function rowCount() + { + return $this->statement->rowCount(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Configuration.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Configuration.php new file mode 100644 index 0000000..53f7b5e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Configuration.php @@ -0,0 +1,113 @@ +. + */ + +namespace Doctrine\DBAL; + +use Doctrine\DBAL\Logging\SQLLogger; +use Doctrine\Common\Cache\Cache; + +/** + * Configuration container for the Doctrine DBAL. + * + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @internal When adding a new configuration option just write a getter/setter + * pair and add the option to the _attributes array with a proper default value. + */ +class Configuration +{ + /** + * The attributes that are contained in the configuration. + * Values are default values. + * + * @var array + */ + protected $_attributes = array(); + + /** + * Sets the SQL logger to use. Defaults to NULL which means SQL logging is disabled. + * + * @param SQLLogger $logger + */ + public function setSQLLogger(SQLLogger $logger = null) + { + $this->_attributes['sqlLogger'] = $logger; + } + + /** + * Gets the SQL logger that is used. + * + * @return SQLLogger + */ + public function getSQLLogger() + { + return isset($this->_attributes['sqlLogger']) ? + $this->_attributes['sqlLogger'] : null; + } + + /** + * Gets the cache driver implementation that is used for query result caching. + * + * @return \Doctrine\Common\Cache\Cache + */ + public function getResultCacheImpl() + { + return isset($this->_attributes['resultCacheImpl']) ? + $this->_attributes['resultCacheImpl'] : null; + } + + /** + * Sets the cache driver implementation that is used for query result caching. + * + * @param \Doctrine\Common\Cache\Cache $cacheImpl + */ + public function setResultCacheImpl(Cache $cacheImpl) + { + $this->_attributes['resultCacheImpl'] = $cacheImpl; + } + + /** + * Filter schema assets expression. + * + * Only include tables/sequences matching the filter expression regexp in + * schema instances generated for the active connection when calling + * {AbstractSchemaManager#createSchema()}. + * + * @param string $filterExpression + */ + public function setFilterSchemaAssetsExpression($filterExpression) + { + $this->_attributes['filterSchemaAssetsExpression'] = $filterExpression; + } + + /** + * Return filter schema assets expression. + * + * @return string|null + */ + public function getFilterSchemaAssetsExpression() + { + if (isset($this->_attributes['filterSchemaAssetsExpression'])) { + return $this->_attributes['filterSchemaAssetsExpression']; + } + return null; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php new file mode 100644 index 0000000..80efa94 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php @@ -0,0 +1,1308 @@ +. + */ + +namespace Doctrine\DBAL; + +use PDO, Closure, Exception, + Doctrine\DBAL\Types\Type, + Doctrine\DBAL\Driver\Connection as DriverConnection, + Doctrine\Common\EventManager, + Doctrine\DBAL\DBALException, + Doctrine\DBAL\Cache\ResultCacheStatement, + Doctrine\DBAL\Cache\QueryCacheProfile, + Doctrine\DBAL\Cache\ArrayStatement, + Doctrine\DBAL\Cache\CacheException; + +/** + * A wrapper around a Doctrine\DBAL\Driver\Connection that adds features like + * events, transaction isolation levels, configuration, emulated transaction nesting, + * lazy connecting and more. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Konsta Vesterinen + * @author Lukas Smith (MDB2 library) + * @author Benjamin Eberlei + */ +class Connection implements DriverConnection +{ + /** + * Constant for transaction isolation level READ UNCOMMITTED. + */ + const TRANSACTION_READ_UNCOMMITTED = 1; + + /** + * Constant for transaction isolation level READ COMMITTED. + */ + const TRANSACTION_READ_COMMITTED = 2; + + /** + * Constant for transaction isolation level REPEATABLE READ. + */ + const TRANSACTION_REPEATABLE_READ = 3; + + /** + * Constant for transaction isolation level SERIALIZABLE. + */ + const TRANSACTION_SERIALIZABLE = 4; + + /** + * Represents an array of ints to be expanded by Doctrine SQL parsing. + * + * @var int + */ + const PARAM_INT_ARRAY = 101; + + /** + * Represents an array of strings to be expanded by Doctrine SQL parsing. + * + * @var int + */ + const PARAM_STR_ARRAY = 102; + + /** + * Offset by which PARAM_* constants are detected as arrays of the param type. + * + * @var int + */ + const ARRAY_PARAM_OFFSET = 100; + + /** + * The wrapped driver connection. + * + * @var \Doctrine\DBAL\Driver\Connection + */ + protected $_conn; + + /** + * @var \Doctrine\DBAL\Configuration + */ + protected $_config; + + /** + * @var \Doctrine\Common\EventManager + */ + protected $_eventManager; + + /** + * @var \Doctrine\DBAL\Query\Expression\ExpressionBuilder + */ + protected $_expr; + + /** + * Whether or not a connection has been established. + * + * @var boolean + */ + private $_isConnected = false; + + /** + * The transaction nesting level. + * + * @var integer + */ + private $_transactionNestingLevel = 0; + + /** + * The currently active transaction isolation level. + * + * @var integer + */ + private $_transactionIsolationLevel; + + /** + * If nested transations should use savepoints + * + * @var integer + */ + private $_nestTransactionsWithSavepoints; + + /** + * The parameters used during creation of the Connection instance. + * + * @var array + */ + private $_params = array(); + + /** + * The DatabasePlatform object that provides information about the + * database platform used by the connection. + * + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + protected $_platform; + + /** + * The schema manager. + * + * @var \Doctrine\DBAL\Schema\AbstractSchemaManager + */ + protected $_schemaManager; + + /** + * The used DBAL driver. + * + * @var \Doctrine\DBAL\Driver + */ + protected $_driver; + + /** + * Flag that indicates whether the current transaction is marked for rollback only. + * + * @var boolean + */ + private $_isRollbackOnly = false; + + private $_defaultFetchMode = PDO::FETCH_ASSOC; + + /** + * Initializes a new instance of the Connection class. + * + * @param array $params The connection parameters. + * @param Driver $driver + * @param Configuration $config + * @param EventManager $eventManager + */ + public function __construct(array $params, Driver $driver, Configuration $config = null, + EventManager $eventManager = null) + { + $this->_driver = $driver; + $this->_params = $params; + + if (isset($params['pdo'])) { + $this->_conn = $params['pdo']; + $this->_isConnected = true; + } + + // Create default config and event manager if none given + if ( ! $config) { + $config = new Configuration(); + } + + if ( ! $eventManager) { + $eventManager = new EventManager(); + } + + $this->_config = $config; + $this->_eventManager = $eventManager; + + $this->_expr = new Query\Expression\ExpressionBuilder($this); + + if ( ! isset($params['platform'])) { + $this->_platform = $driver->getDatabasePlatform(); + } else if ($params['platform'] instanceof Platforms\AbstractPlatform) { + $this->_platform = $params['platform']; + } else { + throw DBALException::invalidPlatformSpecified(); + } + + $this->_platform->setEventManager($eventManager); + + $this->_transactionIsolationLevel = $this->_platform->getDefaultTransactionIsolationLevel(); + } + + /** + * Gets the parameters used during instantiation. + * + * @return array $params + */ + public function getParams() + { + return $this->_params; + } + + /** + * Gets the name of the database this Connection is connected to. + * + * @return string $database + */ + public function getDatabase() + { + return $this->_driver->getDatabase($this); + } + + /** + * Gets the hostname of the currently connected database. + * + * @return string + */ + public function getHost() + { + return isset($this->_params['host']) ? $this->_params['host'] : null; + } + + /** + * Gets the port of the currently connected database. + * + * @return mixed + */ + public function getPort() + { + return isset($this->_params['port']) ? $this->_params['port'] : null; + } + + /** + * Gets the username used by this connection. + * + * @return string + */ + public function getUsername() + { + return isset($this->_params['user']) ? $this->_params['user'] : null; + } + + /** + * Gets the password used by this connection. + * + * @return string + */ + public function getPassword() + { + return isset($this->_params['password']) ? $this->_params['password'] : null; + } + + /** + * Gets the DBAL driver instance. + * + * @return \Doctrine\DBAL\Driver + */ + public function getDriver() + { + return $this->_driver; + } + + /** + * Gets the Configuration used by the Connection. + * + * @return \Doctrine\DBAL\Configuration + */ + public function getConfiguration() + { + return $this->_config; + } + + /** + * Gets the EventManager used by the Connection. + * + * @return \Doctrine\Common\EventManager + */ + public function getEventManager() + { + return $this->_eventManager; + } + + /** + * Gets the DatabasePlatform for the connection. + * + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getDatabasePlatform() + { + return $this->_platform; + } + + /** + * Gets the ExpressionBuilder for the connection. + * + * @return \Doctrine\DBAL\Query\Expression\ExpressionBuilder + */ + public function getExpressionBuilder() + { + return $this->_expr; + } + + /** + * Establishes the connection with the database. + * + * @return boolean TRUE if the connection was successfully established, FALSE if + * the connection is already open. + */ + public function connect() + { + if ($this->_isConnected) return false; + + $driverOptions = isset($this->_params['driverOptions']) ? + $this->_params['driverOptions'] : array(); + $user = isset($this->_params['user']) ? $this->_params['user'] : null; + $password = isset($this->_params['password']) ? + $this->_params['password'] : null; + + $this->_conn = $this->_driver->connect($this->_params, $user, $password, $driverOptions); + $this->_isConnected = true; + + if ($this->_eventManager->hasListeners(Events::postConnect)) { + $eventArgs = new Event\ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + } + + return true; + } + + /** + * setFetchMode + * + * @param integer $fetchMode + */ + public function setFetchMode($fetchMode) + { + $this->_defaultFetchMode = $fetchMode; + } + + /** + * Prepares and executes an SQL query and returns the first row of the result + * as an associative array. + * + * @param string $statement The SQL query. + * @param array $params The query parameters. + * @return array + */ + public function fetchAssoc($statement, array $params = array()) + { + return $this->executeQuery($statement, $params)->fetch(PDO::FETCH_ASSOC); + } + + /** + * Prepares and executes an SQL query and returns the first row of the result + * as a numerically indexed array. + * + * @param string $statement sql query to be executed + * @param array $params prepared statement params + * @return array + */ + public function fetchArray($statement, array $params = array()) + { + return $this->executeQuery($statement, $params)->fetch(PDO::FETCH_NUM); + } + + /** + * Prepares and executes an SQL query and returns the value of a single column + * of the first row of the result. + * + * @param string $statement sql query to be executed + * @param array $params prepared statement params + * @param int $colnum 0-indexed column number to retrieve + * @return mixed + */ + public function fetchColumn($statement, array $params = array(), $colnum = 0) + { + return $this->executeQuery($statement, $params)->fetchColumn($colnum); + } + + /** + * Whether an actual connection to the database is established. + * + * @return boolean + */ + public function isConnected() + { + return $this->_isConnected; + } + + /** + * Checks whether a transaction is currently active. + * + * @return boolean TRUE if a transaction is currently active, FALSE otherwise. + */ + public function isTransactionActive() + { + return $this->_transactionNestingLevel > 0; + } + + /** + * Executes an SQL DELETE statement on a table. + * + * @param string $tableName The name of the table on which to delete. + * @param array $identifier The deletion criteria. An associative array containing column-value pairs. + * @return integer The number of affected rows. + */ + public function delete($tableName, array $identifier) + { + $this->connect(); + + $criteria = array(); + + foreach (array_keys($identifier) as $columnName) { + $criteria[] = $columnName . ' = ?'; + } + + $query = 'DELETE FROM ' . $tableName . ' WHERE ' . implode(' AND ', $criteria); + + return $this->executeUpdate($query, array_values($identifier)); + } + + /** + * Closes the connection. + * + * @return void + */ + public function close() + { + unset($this->_conn); + + $this->_isConnected = false; + } + + /** + * Sets the transaction isolation level. + * + * @param integer $level The level to set. + * @return integer + */ + public function setTransactionIsolation($level) + { + $this->_transactionIsolationLevel = $level; + + return $this->executeUpdate($this->_platform->getSetTransactionIsolationSQL($level)); + } + + /** + * Gets the currently active transaction isolation level. + * + * @return integer The current transaction isolation level. + */ + public function getTransactionIsolation() + { + return $this->_transactionIsolationLevel; + } + + /** + * Executes an SQL UPDATE statement on a table. + * + * @param string $tableName The name of the table to update. + * @param array $data + * @param array $identifier The update criteria. An associative array containing column-value pairs. + * @param array $types Types of the merged $data and $identifier arrays in that order. + * @return integer The number of affected rows. + */ + public function update($tableName, array $data, array $identifier, array $types = array()) + { + $this->connect(); + $set = array(); + foreach ($data as $columnName => $value) { + $set[] = $columnName . ' = ?'; + } + + $params = array_merge(array_values($data), array_values($identifier)); + + $sql = 'UPDATE ' . $tableName . ' SET ' . implode(', ', $set) + . ' WHERE ' . implode(' = ? AND ', array_keys($identifier)) + . ' = ?'; + + return $this->executeUpdate($sql, $params, $types); + } + + /** + * Inserts a table row with specified data. + * + * @param string $tableName The name of the table to insert data into. + * @param array $data An associative array containing column-value pairs. + * @param array $types Types of the inserted data. + * @return integer The number of affected rows. + */ + public function insert($tableName, array $data, array $types = array()) + { + $this->connect(); + + // column names are specified as array keys + $cols = array(); + $placeholders = array(); + + foreach ($data as $columnName => $value) { + $cols[] = $columnName; + $placeholders[] = '?'; + } + + $query = 'INSERT INTO ' . $tableName + . ' (' . implode(', ', $cols) . ')' + . ' VALUES (' . implode(', ', $placeholders) . ')'; + + return $this->executeUpdate($query, array_values($data), $types); + } + + /** + * Quote a string so it can be safely used as a table or column name, even if + * it is a reserved name. + * + * Delimiting style depends on the underlying database platform that is being used. + * + * NOTE: Just because you CAN use quoted identifiers does not mean + * you SHOULD use them. In general, they end up causing way more + * problems than they solve. + * + * @param string $str The name to be quoted. + * @return string The quoted name. + */ + public function quoteIdentifier($str) + { + return $this->_platform->quoteIdentifier($str); + } + + /** + * Quotes a given input parameter. + * + * @param mixed $input Parameter to be quoted. + * @param string $type Type of the parameter. + * @return string The quoted parameter. + */ + public function quote($input, $type = null) + { + $this->connect(); + + list($value, $bindingType) = $this->getBindingInfo($input, $type); + return $this->_conn->quote($value, $bindingType); + } + + /** + * Prepares and executes an SQL query and returns the result as an associative array. + * + * @param string $sql The SQL query. + * @param array $params The query parameters. + * @return array + */ + public function fetchAll($sql, array $params = array()) + { + return $this->executeQuery($sql, $params)->fetchAll(); + } + + /** + * Prepares an SQL statement. + * + * @param string $statement The SQL statement to prepare. + * @return \Doctrine\DBAL\Driver\Statement The prepared statement. + */ + public function prepare($statement) + { + $this->connect(); + + try { + $stmt = new Statement($statement, $this); + } catch (\Exception $ex) { + throw DBALException::driverExceptionDuringQuery($ex, $statement); + } + + $stmt->setFetchMode($this->_defaultFetchMode); + + return $stmt; + } + + /** + * Executes an, optionally parameterized, SQL query. + * + * If the query is parameterized, a prepared statement is used. + * If an SQLLogger is configured, the execution is logged. + * + * @param string $query The SQL query to execute. + * @param array $params The parameters to bind to the query, if any. + * @param array $types The types the previous parameters are in. + * @param QueryCacheProfile $qcp + * @return \Doctrine\DBAL\Driver\Statement The executed statement. + * @internal PERF: Directly prepares a driver statement, not a wrapper. + */ + public function executeQuery($query, array $params = array(), $types = array(), QueryCacheProfile $qcp = null) + { + if ($qcp !== null) { + return $this->executeCacheQuery($query, $params, $types, $qcp); + } + + $this->connect(); + + $logger = $this->_config->getSQLLogger(); + if ($logger) { + $logger->startQuery($query, $params, $types); + } + + try { + if ($params) { + list($query, $params, $types) = SQLParserUtils::expandListParameters($query, $params, $types); + + $stmt = $this->_conn->prepare($query); + if ($types) { + $this->_bindTypedValues($stmt, $params, $types); + $stmt->execute(); + } else { + $stmt->execute($params); + } + } else { + $stmt = $this->_conn->query($query); + } + } catch (\Exception $ex) { + throw DBALException::driverExceptionDuringQuery($ex, $query, $this->resolveParams($params, $types)); + } + + $stmt->setFetchMode($this->_defaultFetchMode); + + if ($logger) { + $logger->stopQuery(); + } + + return $stmt; + } + + /** + * Execute a caching query and + * + * @param string $query + * @param array $params + * @param array $types + * @param QueryCacheProfile $qcp + * @return \Doctrine\DBAL\Driver\ResultStatement + */ + public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qcp) + { + $resultCache = $qcp->getResultCacheDriver() ?: $this->_config->getResultCacheImpl(); + if ( ! $resultCache) { + throw CacheException::noResultDriverConfigured(); + } + + list($cacheKey, $realKey) = $qcp->generateCacheKeys($query, $params, $types); + + // fetch the row pointers entry + if ($data = $resultCache->fetch($cacheKey)) { + // is the real key part of this row pointers map or is the cache only pointing to other cache keys? + if (isset($data[$realKey])) { + $stmt = new ArrayStatement($data[$realKey]); + } else if (array_key_exists($realKey, $data)) { + $stmt = new ArrayStatement(array()); + } + } + + if (!isset($stmt)) { + $stmt = new ResultCacheStatement($this->executeQuery($query, $params, $types), $resultCache, $cacheKey, $realKey, $qcp->getLifetime()); + } + + $stmt->setFetchMode($this->_defaultFetchMode); + + return $stmt; + } + + /** + * Executes an, optionally parameterized, SQL query and returns the result, + * applying a given projection/transformation function on each row of the result. + * + * @param string $query The SQL query to execute. + * @param array $params The parameters, if any. + * @param Closure $mapper The transformation function that is applied on each row. + * The function receives a single paramater, an array, that + * represents a row of the result set. + * @return mixed The projected result of the query. + */ + public function project($query, array $params, Closure $function) + { + $result = array(); + $stmt = $this->executeQuery($query, $params ?: array()); + + while ($row = $stmt->fetch()) { + $result[] = $function($row); + } + + $stmt->closeCursor(); + + return $result; + } + + /** + * Executes an SQL statement, returning a result set as a Statement object. + * + * @param string $statement + * @param integer $fetchType + * @return \Doctrine\DBAL\Driver\Statement + */ + public function query() + { + $this->connect(); + + $args = func_get_args(); + + $logger = $this->_config->getSQLLogger(); + if ($logger) { + $logger->startQuery($args[0]); + } + + try { + $statement = call_user_func_array(array($this->_conn, 'query'), $args); + } catch (\Exception $ex) { + throw DBALException::driverExceptionDuringQuery($ex, func_get_arg(0)); + } + + $statement->setFetchMode($this->_defaultFetchMode); + + if ($logger) { + $logger->stopQuery(); + } + + return $statement; + } + + /** + * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters + * and returns the number of affected rows. + * + * This method supports PDO binding types as well as DBAL mapping types. + * + * @param string $query The SQL query. + * @param array $params The query parameters. + * @param array $types The parameter types. + * @return integer The number of affected rows. + * @internal PERF: Directly prepares a driver statement, not a wrapper. + */ + public function executeUpdate($query, array $params = array(), array $types = array()) + { + $this->connect(); + + $logger = $this->_config->getSQLLogger(); + if ($logger) { + $logger->startQuery($query, $params, $types); + } + + try { + if ($params) { + list($query, $params, $types) = SQLParserUtils::expandListParameters($query, $params, $types); + + $stmt = $this->_conn->prepare($query); + if ($types) { + $this->_bindTypedValues($stmt, $params, $types); + $stmt->execute(); + } else { + $stmt->execute($params); + } + $result = $stmt->rowCount(); + } else { + $result = $this->_conn->exec($query); + } + } catch (\Exception $ex) { + throw DBALException::driverExceptionDuringQuery($ex, $query, $this->resolveParams($params, $types)); + } + + if ($logger) { + $logger->stopQuery(); + } + + return $result; + } + + /** + * Execute an SQL statement and return the number of affected rows. + * + * @param string $statement + * @return integer The number of affected rows. + */ + public function exec($statement) + { + $this->connect(); + + $logger = $this->_config->getSQLLogger(); + if ($logger) { + $logger->startQuery($statement); + } + + try { + $result = $this->_conn->exec($statement); + } catch (\Exception $ex) { + throw DBALException::driverExceptionDuringQuery($ex, $statement); + } + + if ($logger) { + $logger->stopQuery(); + } + + return $result; + } + + /** + * Returns the current transaction nesting level. + * + * @return integer The nesting level. A value of 0 means there's no active transaction. + */ + public function getTransactionNestingLevel() + { + return $this->_transactionNestingLevel; + } + + /** + * Fetch the SQLSTATE associated with the last database operation. + * + * @return integer The last error code. + */ + public function errorCode() + { + $this->connect(); + return $this->_conn->errorCode(); + } + + /** + * Fetch extended error information associated with the last database operation. + * + * @return array The last error information. + */ + public function errorInfo() + { + $this->connect(); + return $this->_conn->errorInfo(); + } + + /** + * Returns the ID of the last inserted row, or the last value from a sequence object, + * depending on the underlying driver. + * + * Note: This method may not return a meaningful or consistent result across different drivers, + * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY + * columns or sequences. + * + * @param string $seqName Name of the sequence object from which the ID should be returned. + * @return string A string representation of the last inserted ID. + */ + public function lastInsertId($seqName = null) + { + $this->connect(); + return $this->_conn->lastInsertId($seqName); + } + + /** + * Executes a function in a transaction. + * + * The function gets passed this Connection instance as an (optional) parameter. + * + * If an exception occurs during execution of the function or transaction commit, + * the transaction is rolled back and the exception re-thrown. + * + * @param Closure $func The function to execute transactionally. + */ + public function transactional(Closure $func) + { + $this->beginTransaction(); + try { + $func($this); + $this->commit(); + } catch (Exception $e) { + $this->rollback(); + throw $e; + } + } + + /** + * Set if nested transactions should use savepoints + * + * @param boolean $nestTransactionsWithSavepoints + * @return void + */ + public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints) + { + if ($this->_transactionNestingLevel > 0) { + throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction(); + } + + if ( ! $this->_platform->supportsSavepoints()) { + throw ConnectionException::savepointsNotSupported(); + } + + $this->_nestTransactionsWithSavepoints = $nestTransactionsWithSavepoints; + } + + /** + * Get if nested transactions should use savepoints + * + * @return boolean + */ + public function getNestTransactionsWithSavepoints() + { + return $this->_nestTransactionsWithSavepoints; + } + + /** + * Returns the savepoint name to use for nested transactions are false if they are not supported + * "savepointFormat" parameter is not set + * + * @return mixed a string with the savepoint name or false + */ + protected function _getNestedTransactionSavePointName() + { + return 'DOCTRINE2_SAVEPOINT_'.$this->_transactionNestingLevel; + } + + /** + * Starts a transaction by suspending auto-commit mode. + * + * @return void + */ + public function beginTransaction() + { + $this->connect(); + + ++$this->_transactionNestingLevel; + + $logger = $this->_config->getSQLLogger(); + + if ($this->_transactionNestingLevel == 1) { + if ($logger) { + $logger->startQuery('"START TRANSACTION"'); + } + $this->_conn->beginTransaction(); + if ($logger) { + $logger->stopQuery(); + } + } else if ($this->_nestTransactionsWithSavepoints) { + if ($logger) { + $logger->startQuery('"SAVEPOINT"'); + } + $this->createSavepoint($this->_getNestedTransactionSavePointName()); + if ($logger) { + $logger->stopQuery(); + } + } + } + + /** + * Commits the current transaction. + * + * @return void + * @throws ConnectionException If the commit failed due to no active transaction or + * because the transaction was marked for rollback only. + */ + public function commit() + { + if ($this->_transactionNestingLevel == 0) { + throw ConnectionException::noActiveTransaction(); + } + if ($this->_isRollbackOnly) { + throw ConnectionException::commitFailedRollbackOnly(); + } + + $this->connect(); + + $logger = $this->_config->getSQLLogger(); + + if ($this->_transactionNestingLevel == 1) { + if ($logger) { + $logger->startQuery('"COMMIT"'); + } + $this->_conn->commit(); + if ($logger) { + $logger->stopQuery(); + } + } else if ($this->_nestTransactionsWithSavepoints) { + if ($logger) { + $logger->startQuery('"RELEASE SAVEPOINT"'); + } + $this->releaseSavepoint($this->_getNestedTransactionSavePointName()); + if ($logger) { + $logger->stopQuery(); + } + } + + --$this->_transactionNestingLevel; + } + + /** + * Cancel any database changes done during the current transaction. + * + * this method can be listened with onPreTransactionRollback and onTransactionRollback + * eventlistener methods + * + * @throws ConnectionException If the rollback operation failed. + */ + public function rollBack() + { + if ($this->_transactionNestingLevel == 0) { + throw ConnectionException::noActiveTransaction(); + } + + $this->connect(); + + $logger = $this->_config->getSQLLogger(); + + if ($this->_transactionNestingLevel == 1) { + if ($logger) { + $logger->startQuery('"ROLLBACK"'); + } + $this->_transactionNestingLevel = 0; + $this->_conn->rollback(); + $this->_isRollbackOnly = false; + if ($logger) { + $logger->stopQuery(); + } + } else if ($this->_nestTransactionsWithSavepoints) { + if ($logger) { + $logger->startQuery('"ROLLBACK TO SAVEPOINT"'); + } + $this->rollbackSavepoint($this->_getNestedTransactionSavePointName()); + --$this->_transactionNestingLevel; + if ($logger) { + $logger->stopQuery(); + } + } else { + $this->_isRollbackOnly = true; + --$this->_transactionNestingLevel; + } + } + + /** + * createSavepoint + * creates a new savepoint + * + * @param string $savepoint name of a savepoint to set + * @return void + */ + public function createSavepoint($savepoint) + { + if ( ! $this->_platform->supportsSavepoints()) { + throw ConnectionException::savepointsNotSupported(); + } + + $this->_conn->exec($this->_platform->createSavePoint($savepoint)); + } + + /** + * releaseSavePoint + * releases given savepoint + * + * @param string $savepoint name of a savepoint to release + * @return void + */ + public function releaseSavepoint($savepoint) + { + if ( ! $this->_platform->supportsSavepoints()) { + throw ConnectionException::savepointsNotSupported(); + } + + if ($this->_platform->supportsReleaseSavepoints()) { + $this->_conn->exec($this->_platform->releaseSavePoint($savepoint)); + } + } + + /** + * rollbackSavePoint + * releases given savepoint + * + * @param string $savepoint name of a savepoint to rollback to + * @return void + */ + public function rollbackSavepoint($savepoint) + { + if ( ! $this->_platform->supportsSavepoints()) { + throw ConnectionException::savepointsNotSupported(); + } + + $this->_conn->exec($this->_platform->rollbackSavePoint($savepoint)); + } + + /** + * Gets the wrapped driver connection. + * + * @return \Doctrine\DBAL\Driver\Connection + */ + public function getWrappedConnection() + { + $this->connect(); + + return $this->_conn; + } + + /** + * Gets the SchemaManager that can be used to inspect or change the + * database schema through the connection. + * + * @return \Doctrine\DBAL\Schema\AbstractSchemaManager + */ + public function getSchemaManager() + { + if ( ! $this->_schemaManager) { + $this->_schemaManager = $this->_driver->getSchemaManager($this); + } + + return $this->_schemaManager; + } + + /** + * Marks the current transaction so that the only possible + * outcome for the transaction to be rolled back. + * + * @throws ConnectionException If no transaction is active. + */ + public function setRollbackOnly() + { + if ($this->_transactionNestingLevel == 0) { + throw ConnectionException::noActiveTransaction(); + } + $this->_isRollbackOnly = true; + } + + /** + * Check whether the current transaction is marked for rollback only. + * + * @return boolean + * @throws ConnectionException If no transaction is active. + */ + public function isRollbackOnly() + { + if ($this->_transactionNestingLevel == 0) { + throw ConnectionException::noActiveTransaction(); + } + return $this->_isRollbackOnly; + } + + /** + * Converts a given value to its database representation according to the conversion + * rules of a specific DBAL mapping type. + * + * @param mixed $value The value to convert. + * @param string $type The name of the DBAL mapping type. + * @return mixed The converted value. + */ + public function convertToDatabaseValue($value, $type) + { + return Type::getType($type)->convertToDatabaseValue($value, $this->_platform); + } + + /** + * Converts a given value to its PHP representation according to the conversion + * rules of a specific DBAL mapping type. + * + * @param mixed $value The value to convert. + * @param string $type The name of the DBAL mapping type. + * @return mixed The converted type. + */ + public function convertToPHPValue($value, $type) + { + return Type::getType($type)->convertToPHPValue($value, $this->_platform); + } + + /** + * Binds a set of parameters, some or all of which are typed with a PDO binding type + * or DBAL mapping type, to a given statement. + * + * @param string $stmt The statement to bind the values to. + * @param array $params The map/list of named/positional parameters. + * @param array $types The parameter types (PDO binding types or DBAL mapping types). + * @internal Duck-typing used on the $stmt parameter to support driver statements as well as + * raw PDOStatement instances. + */ + private function _bindTypedValues($stmt, array $params, array $types) + { + // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO. + if (is_int(key($params))) { + // Positional parameters + $typeOffset = array_key_exists(0, $types) ? -1 : 0; + $bindIndex = 1; + foreach ($params as $value) { + $typeIndex = $bindIndex + $typeOffset; + if (isset($types[$typeIndex])) { + $type = $types[$typeIndex]; + list($value, $bindingType) = $this->getBindingInfo($value, $type); + $stmt->bindValue($bindIndex, $value, $bindingType); + } else { + $stmt->bindValue($bindIndex, $value); + } + ++$bindIndex; + } + } else { + // Named parameters + foreach ($params as $name => $value) { + if (isset($types[$name])) { + $type = $types[$name]; + list($value, $bindingType) = $this->getBindingInfo($value, $type); + $stmt->bindValue($name, $value, $bindingType); + } else { + $stmt->bindValue($name, $value); + } + } + } + } + + /** + * Gets the binding type of a given type. The given type can be a PDO or DBAL mapping type. + * + * @param mixed $value The value to bind + * @param mixed $type The type to bind (PDO or DBAL) + * @return array [0] => the (escaped) value, [1] => the binding type + */ + private function getBindingInfo($value, $type) + { + if (is_string($type)) { + $type = Type::getType($type); + } + if ($type instanceof Type) { + $value = $type->convertToDatabaseValue($value, $this->_platform); + $bindingType = $type->getBindingType(); + } else { + $bindingType = $type; // PDO::PARAM_* constants + } + return array($value, $bindingType); + } + + /** + * Resolves the parameters to a format which can be displayed. + * + * @internal This is a purely internal method. If you rely on this method, you are advised to + * copy/paste the code as this method may change, or be removed without prior notice. + * + * @param array $params + * @param array $types + * + * @return array + */ + public function resolveParams(array $params, array $types) + { + $resolvedParams = array(); + + // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO. + if (is_int(key($params))) { + // Positional parameters + $typeOffset = array_key_exists(0, $types) ? -1 : 0; + $bindIndex = 1; + foreach ($params as $value) { + $typeIndex = $bindIndex + $typeOffset; + if (isset($types[$typeIndex])) { + $type = $types[$typeIndex]; + list($value,) = $this->getBindingInfo($value, $type); + $resolvedParams[$bindIndex] = $value; + } else { + $resolvedParams[$bindIndex] = $value; + } + ++$bindIndex; + } + } else { + // Named parameters + foreach ($params as $name => $value) { + if (isset($types[$name])) { + $type = $types[$name]; + list($value,) = $this->getBindingInfo($value, $type); + $resolvedParams[$name] = $value; + } else { + $resolvedParams[$name] = $value; + } + } + } + + return $resolvedParams; + } + + /** + * Create a new instance of a SQL query builder. + * + * @return \Doctrine\DBAL\Query\QueryBuilder + */ + public function createQueryBuilder() + { + return new Query\QueryBuilder($this); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php new file mode 100644 index 0000000..4b41ef2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/ConnectionException.php @@ -0,0 +1,54 @@ +. + */ + +namespace Doctrine\DBAL; + +/** + * Doctrine\DBAL\ConnectionException + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision: 4628 $ + * @author Jonathan H. Wage . + */ + +namespace Doctrine\DBAL\Connections; + + +use Doctrine\DBAL\Connection, + Doctrine\DBAL\Driver, + Doctrine\DBAL\Configuration, + Doctrine\Common\EventManager, + Doctrine\DBAL\Event\ConnectionEventArgs, + Doctrine\DBAL\Events; + +/** + * Master-Slave Connection + * + * Connection can be used with master-slave setups. + * + * Important for the understanding of this connection should be how and when + * it picks the slave or master. + * + * 1. Slave if master was never picked before and ONLY if 'getWrappedConnection' + * or 'executeQuery' is used. + * 2. Master picked when 'exec', 'executeUpdate', 'insert', 'delete', 'update', 'createSavepoint', + * 'releaseSavepoint', 'beginTransaction', 'rollback', 'commit', 'query' or + * 'prepare' is called. + * 3. If master was picked once during the lifetime of the connection it will always get picked afterwards. + * 4. One slave connection is randomly picked ONCE during a request. + * + * ATTENTION: You can write to the slave with this connection if you execute a write query without + * opening up a transaction. For example: + * + * $conn = DriverManager::getConnection(...); + * $conn->executeQuery("DELETE FROM table"); + * + * Be aware that Connection#executeQuery is a method specifically for READ + * operations only. + * + * This connection is limited to slave operations using the + * Connection#executeQuery operation only, because it wouldn't be compatible + * with the ORM or SchemaManager code otherwise. Both use all the other + * operations in a context where writes could happen to a slave, which makes + * this restricted approach necessary. + * + * You can manually connect to the master at any time by calling: + * + * $conn->connect('master'); + * + * Instantiation through the DriverManager looks like: + * + * @example + * + * $conn = DriverManager::getConnection(array( + * 'wrapperClass' => 'Doctrine\DBAL\Connections\MasterSlaveConnection', + * 'driver' => 'pdo_mysql', + * 'master' => array('user' => '', 'password' => '', 'host' => '', 'dbname' => ''), + * 'slaves' => array( + * array('user' => 'slave1', 'password', 'host' => '', 'dbname' => ''), + * array('user' => 'slave2', 'password', 'host' => '', 'dbname' => ''), + * ) + * )); + * + * You can also pass 'driverOptions' and any other documented option to each of this drivers to pass additional information. + * + * @author Lars Strojny + * @author Benjamin Eberlei + */ +class MasterSlaveConnection extends Connection +{ + /** + * Master and slave connection (one of the randomly picked slaves) + * + * @var Doctrine\DBAL\Driver\Connection[] + */ + protected $connections = array('master' => null, 'slave' => null); + + /** + * You can keep the slave connection and then switch back to it + * during the request if you know what you are doing. + * + * @var bool + */ + protected $keepSlave = false; + + /** + * Create Master Slave Connection + * + * @param array $params + * @param Driver $driver + * @param Configuration $config + * @param EventManager $eventManager + */ + public function __construct(array $params, Driver $driver, Configuration $config = null, EventManager $eventManager = null) + { + if ( !isset($params['slaves']) || !isset($params['master']) ) { + throw new \InvalidArgumentException('master or slaves configuration missing'); + } + if ( count($params['slaves']) == 0 ) { + throw new \InvalidArgumentException('You have to configure at least one slaves.'); + } + + $params['master']['driver'] = $params['driver']; + foreach ($params['slaves'] as $slaveKey => $slave) { + $params['slaves'][$slaveKey]['driver'] = $params['driver']; + } + + $this->keepSlave = isset($params['keepSlave']) ? (bool)$params['keepSlave'] : false; + + parent::__construct($params, $driver, $config, $eventManager); + } + + /** + * Check if the connection is currently towards the master or not. + * + * @return bool + */ + public function isConnectedToMaster() + { + return $this->_conn !== null && $this->_conn === $this->connections['master']; + } + + /** + * {@inheritDoc} + */ + public function connect($connectionName = null) + { + $requestedConnectionChange = ($connectionName !== null); + $connectionName = $connectionName ?: 'slave'; + + if ( $connectionName !== 'slave' && $connectionName !== 'master' ) { + throw new \InvalidArgumentException("Invalid option to connect(), only master or slave allowed."); + } + + // If we have a connection open, and this is not an explicit connection + // change request, then abort right here, because we are already done. + // This prevents writes to the slave in case of "keepSlave" option enabled. + if ($this->_conn && !$requestedConnectionChange) { + return false; + } + + $forceMasterAsSlave = false; + + if ($this->getTransactionNestingLevel() > 0) { + $connectionName = 'master'; + $forceMasterAsSlave = true; + } + + if ($this->connections[$connectionName]) { + if ($forceMasterAsSlave) { + $this->connections['slave'] = $this->_conn = $this->connections['master']; + } else { + $this->_conn = $this->connections[$connectionName]; + } + return false; + } + + if ($connectionName === 'master') { + // Set slave connection to master to avoid invalid reads + if ($this->connections['slave'] && ! $this->keepSlave) { + unset($this->connections['slave']); + } + + $this->connections['master'] = $this->_conn = $this->connectTo($connectionName); + + if ( ! $this->keepSlave) { + $this->connections['slave'] = $this->connections['master']; + } + } else { + $this->connections['slave'] = $this->_conn = $this->connectTo($connectionName); + } + + if ($this->_eventManager->hasListeners(Events::postConnect)) { + $eventArgs = new ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + } + + return true; + } + + /** + * Connect to a specific connection + * + * @param string $connectionName + * @return Driver + */ + protected function connectTo($connectionName) + { + $params = $this->getParams(); + + $driverOptions = isset($params['driverOptions']) ? $params['driverOptions'] : array(); + + $connectionParams = $this->chooseConnectionConfiguration($connectionName, $params); + + $user = isset($connectionParams['user']) ? $connectionParams['user'] : null; + $password = isset($connectionParams['password']) ? $connectionParams['password'] : null; + + return $this->_driver->connect($connectionParams, $user, $password, $driverOptions); + } + + protected function chooseConnectionConfiguration($connectionName, $params) + { + if ($connectionName === 'master') { + return $params['master']; + } + + return $params['slaves'][array_rand($params['slaves'])]; + } + + /** + * {@inheritDoc} + */ + public function executeUpdate($query, array $params = array(), array $types = array()) + { + $this->connect('master'); + return parent::executeUpdate($query, $params, $types); + } + + /** + * {@inheritDoc} + */ + public function beginTransaction() + { + $this->connect('master'); + return parent::beginTransaction(); + } + + /** + * {@inheritDoc} + */ + public function commit() + { + $this->connect('master'); + return parent::commit(); + } + + /** + * {@inheritDoc} + */ + public function rollBack() + { + $this->connect('master'); + return parent::rollBack(); + } + + /** + * {@inheritDoc} + */ + public function delete($tableName, array $identifier) + { + $this->connect('master'); + return parent::delete($tableName, $identifier); + } + + /** + * {@inheritDoc} + */ + public function update($tableName, array $data, array $identifier, array $types = array()) + { + $this->connect('master'); + return parent::update($tableName, $data, $identifier, $types); + } + + /** + * {@inheritDoc} + */ + public function insert($tableName, array $data, array $types = array()) + { + $this->connect('master'); + return parent::insert($tableName, $data, $types); + } + + /** + * {@inheritDoc} + */ + public function exec($statement) + { + $this->connect('master'); + return parent::exec($statement); + } + + /** + * {@inheritDoc} + */ + public function createSavepoint($savepoint) + { + $this->connect('master'); + + return parent::createSavepoint($savepoint); + } + + /** + * {@inheritDoc} + */ + public function releaseSavepoint($savepoint) + { + $this->connect('master'); + + return parent::releaseSavepoint($savepoint); + } + + /** + * {@inheritDoc} + */ + public function rollbackSavepoint($savepoint) + { + $this->connect('master'); + + return parent::rollbackSavepoint($savepoint); + } + + public function query() + { + $this->connect('master'); + + $args = func_get_args(); + + $logger = $this->getConfiguration()->getSQLLogger(); + if ($logger) { + $logger->startQuery($args[0]); + } + + $statement = call_user_func_array(array($this->_conn, 'query'), $args); + + if ($logger) { + $logger->stopQuery(); + } + + return $statement; + } + + public function prepare($statement) + { + $this->connect('master'); + + return parent::prepare($statement); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php new file mode 100644 index 0000000..c8e430b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php @@ -0,0 +1,106 @@ +getMessage(); + + return new self($msg, 0, $driverEx); + } + + public static function invalidWrapperClass($wrapperClass) + { + return new self("The given 'wrapperClass' ".$wrapperClass." has to be a ". + "subtype of \Doctrine\DBAL\Connection."); + } + + public static function invalidDriverClass($driverClass) + { + return new self("The given 'driverClass' ".$driverClass." has to implement the ". + "\Doctrine\DBAL\Driver interface."); + } + + /** + * @param string $tableName + * @return DBALException + */ + public static function invalidTableName($tableName) + { + return new self("Invalid table name specified: ".$tableName); + } + + /** + * @param string $tableName + * @return DBALException + */ + public static function noColumnsSpecifiedForTable($tableName) + { + return new self("No columns specified for table ".$tableName); + } + + public static function limitOffsetInvalid() + { + return new self("Invalid Offset in Limit Query, it has to be larger or equal to 0."); + } + + public static function typeExists($name) + { + return new self('Type '.$name.' already exists.'); + } + + public static function unknownColumnType($name) + { + return new self('Unknown column type "'.$name.'" requested. Any Doctrine type that you use has ' . + 'to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a list of all the ' . + 'known types with \Doctrine\DBAL\Types\Type::getTypeMap(). If this error occurs during database ' . + 'introspection then you might have forgot to register all database types for a Doctrine Type. Use ' . + 'AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement ' . + 'Type#getMappedDatabaseTypes(). If the type name is empty you might ' . + 'have a problem with the cache or forgot some mapping information.' + ); + } + + public static function typeNotFound($name) + { + return new self('Type to be overwritten '.$name.' does not exist.'); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver.php new file mode 100644 index 0000000..8364990 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver.php @@ -0,0 +1,72 @@ +. + */ + +namespace Doctrine\DBAL; + +/** + * Driver interface. + * Interface that all DBAL drivers must implement. + * + * @since 2.0 + */ +interface Driver +{ + /** + * Attempts to create a connection with the database. + * + * @param array $params All connection parameters passed by the user. + * @param string $username The username to use when connecting. + * @param string $password The password to use when connecting. + * @param array $driverOptions The driver options to use when connecting. + * @return \Doctrine\DBAL\Driver\Connection The database connection. + */ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()); + + /** + * Gets the DatabasePlatform instance that provides all the metadata about + * the platform this driver connects to. + * + * @return \Doctrine\DBAL\Platforms\AbstractPlatform The database platform. + */ + public function getDatabasePlatform(); + + /** + * Gets the SchemaManager that can be used to inspect and change the underlying + * database schema of the platform this driver connects to. + * + * @param \Doctrine\DBAL\Connection $conn + * @return \Doctrine\DBAL\Schema\AbstractSchemaManager + */ + public function getSchemaManager(Connection $conn); + + /** + * Gets the name of the driver. + * + * @return string The name of the driver. + */ + public function getName(); + + /** + * Get the name of the database connected to for this driver. + * + * @param \Doctrine\DBAL\Connection $conn + * @return string $database + */ + public function getDatabase(Connection $conn); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Connection.php new file mode 100644 index 0000000..a618487 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Connection.php @@ -0,0 +1,42 @@ +. + */ + +namespace Doctrine\DBAL\Driver; + +/** + * Connection interface. + * Driver connections must implement this interface. + * + * This resembles (a subset of) the PDO interface. + * + * @since 2.0 + */ +interface Connection +{ + function prepare($prepareString); + function query(); + function quote($input, $type=\PDO::PARAM_STR); + function exec($statement); + function lastInsertId($name = null); + function beginTransaction(); + function commit(); + function rollBack(); + function errorCode(); + function errorInfo(); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Connection.php new file mode 100644 index 0000000..2b46c99 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Connection.php @@ -0,0 +1,41 @@ +. + */ + +namespace Doctrine\DBAL\Driver\DrizzlePDOMySql; + +/** + * @author Kim Hemsø Rasmussen + */ +class Connection extends \Doctrine\DBAL\Driver\PDOConnection +{ + /** + * {@inheritdoc} + */ + public function quote($value, $type=\PDO::PARAM_STR) + { + if (\PDO::PARAM_BOOL === $type) { + if ($value) { + return 'true'; + } else { + return 'false'; + } + } + return parent::quote($value, $type); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Driver.php new file mode 100644 index 0000000..8030bbc --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/DrizzlePDOMySql/Driver.php @@ -0,0 +1,99 @@ +. + */ + +namespace Doctrine\DBAL\Driver\DrizzlePDOMySql; + +/** + * Drizzle driver using PDO MySql. + * + * @author Kim Hemsø Rasmussen + */ +class Driver implements \Doctrine\DBAL\Driver +{ + /** + * {@inheritdoc} + */ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + $conn = new Connection( + $this->_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + return $conn; + } + + /** + * Constructs the Drizzle MySql PDO DSN. + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params) + { + $dsn = 'mysql:'; + if (isset($params['host']) && $params['host'] != '') { + $dsn .= 'host=' . $params['host'] . ';'; + } + if (isset($params['port'])) { + $dsn .= 'port=' . $params['port'] . ';'; + } + if (isset($params['dbname'])) { + $dsn .= 'dbname=' . $params['dbname'] . ';'; + } + if (isset($params['unix_socket'])) { + $dsn .= 'unix_socket=' . $params['unix_socket'] . ';'; + } + + return $dsn; + } + + /** + * {@inheritdoc} + */ + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\DrizzlePlatform(); + } + + /** + * {@inheritdoc} + */ + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\DrizzleSchemaManager($conn); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'drizzle_pdo_mysql'; + } + + /** + * {@inheritdoc} + */ + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['dbname']; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php new file mode 100644 index 0000000..c1c2212 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Connection.php @@ -0,0 +1,115 @@ +. +*/ + +namespace Doctrine\DBAL\Driver\IBMDB2; + +class DB2Connection implements \Doctrine\DBAL\Driver\Connection +{ + private $_conn = null; + + public function __construct(array $params, $username, $password, $driverOptions = array()) + { + $isPersistant = (isset($params['persistent']) && $params['persistent'] == true); + + if ($isPersistant) { + $this->_conn = db2_pconnect($params['dbname'], $username, $password, $driverOptions); + } else { + $this->_conn = db2_connect($params['dbname'], $username, $password, $driverOptions); + } + if ( ! $this->_conn) { + throw new DB2Exception(db2_conn_errormsg()); + } + } + + public function prepare($sql) + { + $stmt = @db2_prepare($this->_conn, $sql); + if ( ! $stmt) { + throw new DB2Exception(db2_stmt_errormsg()); + } + return new DB2Statement($stmt); + } + + public function query() + { + $args = func_get_args(); + $sql = $args[0]; + $stmt = $this->prepare($sql); + $stmt->execute(); + return $stmt; + } + + public function quote($input, $type=\PDO::PARAM_STR) + { + $input = db2_escape_string($input); + if ($type == \PDO::PARAM_INT ) { + return $input; + } else { + return "'".$input."'"; + } + } + + public function exec($statement) + { + $stmt = $this->prepare($statement); + $stmt->execute(); + return $stmt->rowCount(); + } + + public function lastInsertId($name = null) + { + return db2_last_insert_id($this->_conn); + } + + public function beginTransaction() + { + db2_autocommit($this->_conn, DB2_AUTOCOMMIT_OFF); + } + + public function commit() + { + if (!db2_commit($this->_conn)) { + throw new DB2Exception(db2_conn_errormsg($this->_conn)); + } + db2_autocommit($this->_conn, DB2_AUTOCOMMIT_ON); + } + + public function rollBack() + { + if (!db2_rollback($this->_conn)) { + throw new DB2Exception(db2_conn_errormsg($this->_conn)); + } + db2_autocommit($this->_conn, DB2_AUTOCOMMIT_ON); + } + + public function errorCode() + { + return db2_conn_error($this->_conn); + } + + public function errorInfo() + { + return array( + 0 => db2_conn_errormsg($this->_conn), + 1 => $this->errorCode(), + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php new file mode 100644 index 0000000..82c71e5 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php @@ -0,0 +1,111 @@ +. +*/ + +namespace Doctrine\DBAL\Driver\IBMDB2; + +use Doctrine\DBAL\Driver, + Doctrine\DBAL\Connection; + +/** + * IBM DB2 Driver + * + * @since 2.0 + * @author Benjamin Eberlei + */ +class DB2Driver implements Driver +{ + /** + * Attempts to create a connection with the database. + * + * @param array $params All connection parameters passed by the user. + * @param string $username The username to use when connecting. + * @param string $password The password to use when connecting. + * @param array $driverOptions The driver options to use when connecting. + * @return \Doctrine\DBAL\Driver\Connection The database connection. + */ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + if ( ! isset($params['protocol'])) { + $params['protocol'] = 'TCPIP'; + } + + if ($params['host'] !== 'localhost' && $params['host'] != '127.0.0.1') { + // if the host isn't localhost, use extended connection params + $params['dbname'] = 'DRIVER={IBM DB2 ODBC DRIVER}' . + ';DATABASE=' . $params['dbname'] . + ';HOSTNAME=' . $params['host'] . + ';PROTOCOL=' . $params['protocol'] . + ';UID=' . $username . + ';PWD=' . $password .';'; + if (isset($params['port'])) { + $params['dbname'] .= 'PORT=' . $params['port']; + } + + $username = null; + $password = null; + } + + return new DB2Connection($params, $username, $password, $driverOptions); + } + + /** + * Gets the DatabasePlatform instance that provides all the metadata about + * the platform this driver connects to. + * + * @return \Doctrine\DBAL\Platforms\AbstractPlatform The database platform. + */ + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\DB2Platform; + } + + /** + * Gets the SchemaManager that can be used to inspect and change the underlying + * database schema of the platform this driver connects to. + * + * @param \Doctrine\DBAL\Connection $conn + * @return \Doctrine\DBAL\Schema\DB2SchemaManager + */ + public function getSchemaManager(Connection $conn) + { + return new \Doctrine\DBAL\Schema\DB2SchemaManager($conn); + } + + /** + * Gets the name of the driver. + * + * @return string The name of the driver. + */ + public function getName() + { + return 'ibm_db2'; + } + + /** + * Get the name of the database connected to for this driver. + * + * @param \Doctrine\DBAL\Connection $conn + * @return string $database + */ + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['dbname']; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php new file mode 100644 index 0000000..3d07658 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Exception.php @@ -0,0 +1,27 @@ +. +*/ + +namespace Doctrine\DBAL\Driver\IBMDB2; + +class DB2Exception extends \Exception +{ + +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php new file mode 100644 index 0000000..9a43f9f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php @@ -0,0 +1,214 @@ +. +*/ + +namespace Doctrine\DBAL\Driver\IBMDB2; + +use \Doctrine\DBAL\Driver\Statement; + +class DB2Statement implements \IteratorAggregate, Statement +{ + private $_stmt = null; + + private $_bindParam = array(); + + private $_defaultFetchMode = \PDO::FETCH_BOTH; + + /** + * DB2_BINARY, DB2_CHAR, DB2_DOUBLE, or DB2_LONG + * @var array + */ + static private $_typeMap = array( + \PDO::PARAM_INT => DB2_LONG, + \PDO::PARAM_STR => DB2_CHAR, + ); + + public function __construct($stmt) + { + $this->_stmt = $stmt; + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = null) + { + return $this->bindParam($param, $value, $type); + } + + /** + * {@inheritdoc} + */ + public function bindParam($column, &$variable, $type = null, $length = null) + { + $this->_bindParam[$column] =& $variable; + + if ($type && isset(self::$_typeMap[$type])) { + $type = self::$_typeMap[$type]; + } else { + $type = DB2_CHAR; + } + + if (!db2_bind_param($this->_stmt, $column, "variable", DB2_PARAM_IN, $type)) { + throw new DB2Exception(db2_stmt_errormsg()); + } + return true; + } + + /** + * {@inheritdoc} + */ + public function closeCursor() + { + if ( ! $this->_stmt) { + return false; + } + + $this->_bindParam = array(); + db2_free_result($this->_stmt); + $ret = db2_free_stmt($this->_stmt); + $this->_stmt = false; + return $ret; + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + if ( ! $this->_stmt) { + return false; + } + return db2_num_fields($this->_stmt); + } + + /** + * {@inheritdoc} + */ + public function errorCode() + { + return db2_stmt_error(); + } + + /** + * {@inheritdoc} + */ + public function errorInfo() + { + return array( + 0 => db2_stmt_errormsg(), + 1 => db2_stmt_error(), + ); + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + if ( ! $this->_stmt) { + return false; + } + + /*$retval = true; + if ($params !== null) { + $retval = @db2_execute($this->_stmt, $params); + } else { + $retval = @db2_execute($this->_stmt); + }*/ + if ($params === null) { + ksort($this->_bindParam); + $params = array_values($this->_bindParam); + } + $retval = @db2_execute($this->_stmt, $params); + + if ($retval === false) { + throw new DB2Exception(db2_stmt_errormsg()); + } + return $retval; + } + + /** + * {@inheritdoc} + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->_defaultFetchMode = $fetchMode; + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + $data = $this->fetchAll(); + return new \ArrayIterator($data); + } + + /** + * {@inheritdoc} + */ + public function fetch($fetchMode = null) + { + $fetchMode = $fetchMode ?: $this->_defaultFetchMode; + switch ($fetchMode) { + case \PDO::FETCH_BOTH: + return db2_fetch_both($this->_stmt); + case \PDO::FETCH_ASSOC: + return db2_fetch_assoc($this->_stmt); + case \PDO::FETCH_NUM: + return db2_fetch_array($this->_stmt); + default: + throw new DB2Exception("Given Fetch-Style " . $fetchMode . " is not supported."); + } + } + + /** + * {@inheritdoc} + */ + public function fetchAll($fetchMode = null) + { + $rows = array(); + while ($row = $this->fetch($fetchMode)) { + $rows[] = $row; + } + return $rows; + } + + /** + * {@inheritdoc} + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(\PDO::FETCH_NUM); + if ($row && isset($row[$columnIndex])) { + return $row[$columnIndex]; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + return (@db2_num_rows($this->_stmt))?:0; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Driver.php new file mode 100644 index 0000000..60defba --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/Driver.php @@ -0,0 +1,69 @@ +. + */ + +namespace Doctrine\DBAL\Driver\Mysqli; + +use Doctrine\DBAL\Driver as DriverInterface; + +/** + * @author Kim Hemsø Rasmussen + */ +class Driver implements DriverInterface +{ + /** + * {@inheritdoc} + */ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + return new MysqliConnection($params, $username, $password, $driverOptions); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'mysqli'; + } + + /** + * {@inheritdoc} + */ + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\MySqlSchemaManager($conn); + } + + /** + * {@inheritdoc} + */ + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\MySqlPlatform(); + } + + /** + * {@inheritdoc} + */ + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['dbname']; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php new file mode 100644 index 0000000..7ffa2ca --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliConnection.php @@ -0,0 +1,146 @@ +. + */ + +namespace Doctrine\DBAL\Driver\Mysqli; + +use Doctrine\DBAL\Driver\Connection as Connection; + +/** + * @author Kim Hemsø Rasmussen + */ +class MysqliConnection implements Connection +{ + /** + * @var \mysqli + */ + private $_conn; + + public function __construct(array $params, $username, $password, array $driverOptions = array()) + { + $port = isset($params['port']) ? $params['port'] : ini_get('mysqli.default_port'); + $socket = isset($params['unix_socket']) ? $params['unix_socket'] : ini_get('mysqli.default_socket'); + + $this->_conn = mysqli_init(); + if ( ! $this->_conn->real_connect($params['host'], $username, $password, $params['dbname'], $port, $socket)) { + throw new MysqliException($this->_conn->connect_error, $this->_conn->connect_errno); + } + + if (isset($params['charset'])) { + $this->_conn->set_charset($params['charset']); + } + } + + /** + * Retrieve mysqli native resource handle. + * + * Could be used if part of your application is not using DBAL + * + * @return \mysqli + */ + public function getWrappedResourceHandle() + { + return $this->_conn; + } + + /** + * {@inheritdoc} + */ + public function prepare($prepareString) + { + return new MysqliStatement($this->_conn, $prepareString); + } + + /** + * {@inheritdoc} + */ + public function query() + { + $args = func_get_args(); + $sql = $args[0]; + $stmt = $this->prepare($sql); + $stmt->execute(); + return $stmt; + } + + /** + * {@inheritdoc} + */ + public function quote($input, $type=\PDO::PARAM_STR) + { + return "'". $this->_conn->escape_string($input) ."'"; + } + + /** + * {@inheritdoc} + */ + public function exec($statement) + { + $this->_conn->query($statement); + return $this->_conn->affected_rows; + } + + /** + * {@inheritdoc} + */ + public function lastInsertId($name = null) + { + return $this->_conn->insert_id; + } + + /** + * {@inheritdoc} + */ + public function beginTransaction() + { + $this->_conn->query('START TRANSACTION'); + return true; + } + + /** + * {@inheritdoc} + */ + public function commit() + { + return $this->_conn->commit(); + } + + /** + * {@inheritdoc}non-PHPdoc) + */ + public function rollBack() + { + return $this->_conn->rollback(); + } + + /** + * {@inheritdoc} + */ + public function errorCode() + { + return $this->_conn->errno; + } + + /** + * {@inheritdoc} + */ + public function errorInfo() + { + return $this->_conn->error; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php new file mode 100644 index 0000000..139ce8f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php @@ -0,0 +1,26 @@ +. +*/ + +namespace Doctrine\DBAL\Driver\Mysqli; + +/** + * @author Kim Hemsø Rasmussen + */ +class MysqliException extends \Exception +{} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php new file mode 100644 index 0000000..2eaa8fd --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php @@ -0,0 +1,342 @@ +. + */ + +namespace Doctrine\DBAL\Driver\Mysqli; + +use Doctrine\DBAL\Driver\Statement; +use PDO; + +/** + * @author Kim Hemsø Rasmussen + */ +class MysqliStatement implements \IteratorAggregate, Statement +{ + protected static $_paramTypeMap = array( + PDO::PARAM_STR => 's', + PDO::PARAM_BOOL => 'i', + PDO::PARAM_NULL => 's', + PDO::PARAM_INT => 'i', + PDO::PARAM_LOB => 's' // TODO Support LOB bigger then max package size. + ); + + protected $_conn; + protected $_stmt; + + /** + * @var null|false|array + */ + protected $_columnNames; + + /** + * @var null|array + */ + protected $_rowBindedValues; + + /** + * @var array + */ + protected $_bindedValues; + + /** + * Contains ref values for bindValue() + * + * @var array + */ + protected $_values = array(); + + protected $_defaultFetchMode = PDO::FETCH_BOTH; + + public function __construct(\mysqli $conn, $prepareString) + { + $this->_conn = $conn; + $this->_stmt = $conn->prepare($prepareString); + if (false === $this->_stmt) { + throw new MysqliException($this->_conn->error, $this->_conn->errno); + } + + $paramCount = $this->_stmt->param_count; + if (0 < $paramCount) { + // Index 0 is types + // Need to init the string else php think we are trying to access it as a array. + $bindedValues = array(0 => str_repeat('s', $paramCount)); + $null = null; + for ($i = 1; $i < $paramCount; $i++) { + $bindedValues[] =& $null; + } + $this->_bindedValues = $bindedValues; + } + } + + /** + * {@inheritdoc} + */ + public function bindParam($column, &$variable, $type = null, $length = null) + { + if (null === $type) { + $type = 's'; + } else { + if (isset(self::$_paramTypeMap[$type])) { + $type = self::$_paramTypeMap[$type]; + } else { + throw new MysqliException("Unkown type: '{$type}'"); + } + } + + $this->_bindedValues[$column] =& $variable; + $this->_bindedValues[0][$column - 1] = $type; + return true; + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = null) + { + if (null === $type) { + $type = 's'; + } else { + if (isset(self::$_paramTypeMap[$type])) { + $type = self::$_paramTypeMap[$type]; + } else { + throw new MysqliException("Unknown type: '{$type}'"); + } + } + + $this->_values[$param] = $value; + $this->_bindedValues[$param] =& $this->_values[$param]; + $this->_bindedValues[0][$param - 1] = $type; + return true; + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + if (null !== $this->_bindedValues) { + if (null !== $params) { + if ( ! $this->_bindValues($params)) { + throw new MysqliException($this->_stmt->error, $this->_stmt->errno); + } + } else { + if (!call_user_func_array(array($this->_stmt, 'bind_param'), $this->_bindedValues)) { + throw new MysqliException($this->_stmt->error, $this->_stmt->errno); + } + } + } + + if ( ! $this->_stmt->execute()) { + throw new MysqliException($this->_stmt->error, $this->_stmt->errno); + } + + if (null === $this->_columnNames) { + $meta = $this->_stmt->result_metadata(); + if (false !== $meta) { + $columnNames = array(); + foreach ($meta->fetch_fields() as $col) { + $columnNames[] = $col->name; + } + $meta->free(); + + $this->_columnNames = $columnNames; + $this->_rowBindedValues = array_fill(0, count($columnNames), NULL); + + $refs = array(); + foreach ($this->_rowBindedValues as $key => &$value) { + $refs[$key] =& $value; + } + + if (!call_user_func_array(array($this->_stmt, 'bind_result'), $refs)) { + throw new MysqliException($this->_stmt->error, $this->_stmt->errno); + } + } else { + $this->_columnNames = false; + } + } + + // We have a result. + if (false !== $this->_columnNames) { + $this->_stmt->store_result(); + } + return true; + } + + /** + * Bind a array of values to bound parameters + * + * @param array $values + * @return boolean + */ + private function _bindValues($values) + { + $params = array(); + $types = str_repeat('s', count($values)); + $params[0] = $types; + + foreach ($values as &$v) { + $params[] =& $v; + } + return call_user_func_array(array($this->_stmt, 'bind_param'), $params); + } + + /** + * @return boolean|array + */ + private function _fetch() + { + $ret = $this->_stmt->fetch(); + + if (true === $ret) { + $values = array(); + foreach ($this->_rowBindedValues as $v) { + // Mysqli converts them to a scalar type it can fit in. + $values[] = null === $v ? null : (string)$v; + } + return $values; + } + return $ret; + } + + /** + * {@inheritdoc} + */ + public function fetch($fetchMode = null) + { + $values = $this->_fetch(); + if (null === $values) { + return null; + } + + if (false === $values) { + throw new MysqliException($this->_stmt->error, $this->_stmt->errno); + } + + $fetchMode = $fetchMode ?: $this->_defaultFetchMode; + + switch ($fetchMode) { + case PDO::FETCH_NUM: + return $values; + + case PDO::FETCH_ASSOC: + return array_combine($this->_columnNames, $values); + + case PDO::FETCH_BOTH: + $ret = array_combine($this->_columnNames, $values); + $ret += $values; + return $ret; + + default: + throw new MysqliException("Unknown fetch type '{$fetchMode}'"); + } + } + + /** + * {@inheritdoc} + */ + public function fetchAll($fetchMode = null) + { + $fetchMode = $fetchMode ?: $this->_defaultFetchMode; + + $rows = array(); + if (PDO::FETCH_COLUMN == $fetchMode) { + while (($row = $this->fetchColumn()) !== false) { + $rows[] = $row; + } + } else { + while (($row = $this->fetch($fetchMode)) !== null) { + $rows[] = $row; + } + } + + return $rows; + } + + /** + * {@inheritdoc} + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(PDO::FETCH_NUM); + if (null === $row) { + return false; + } + return $row[$columnIndex]; + } + + /** + * {@inheritdoc} + */ + public function errorCode() + { + return $this->_stmt->errno; + } + + /** + * {@inheritdoc} + */ + public function errorInfo() + { + return $this->_stmt->error; + } + + /** + * {@inheritdoc} + */ + public function closeCursor() + { + $this->_stmt->free_result(); + return true; + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + if (false === $this->_columnNames) { + return $this->_stmt->affected_rows; + } + return $this->_stmt->num_rows; + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return $this->_stmt->field_count; + } + + /** + * {@inheritdoc} + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->_defaultFetchMode = $fetchMode; + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + $data = $this->fetchAll(); + return new \ArrayIterator($data); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Driver.php new file mode 100644 index 0000000..d512610 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/Driver.php @@ -0,0 +1,99 @@ +. + */ + +namespace Doctrine\DBAL\Driver\OCI8; + +use Doctrine\DBAL\Platforms; + +/** + * A Doctrine DBAL driver for the Oracle OCI8 PHP extensions. + * + * @author Roman Borschel + * @since 2.0 + */ +class Driver implements \Doctrine\DBAL\Driver +{ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + return new OCI8Connection( + $username, + $password, + $this->_constructDsn($params), + isset($params['charset']) ? $params['charset'] : null, + isset($params['sessionMode']) ? $params['sessionMode'] : OCI_DEFAULT, + isset($params['persistent']) ? $params['persistent'] : false + ); + } + + /** + * Constructs the Oracle DSN. + * + * @return string The DSN. + */ + protected function _constructDsn(array $params) + { + $dsn = ''; + if (isset($params['host']) && $params['host'] != '') { + $dsn .= '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)' . + '(HOST=' . $params['host'] . ')'; + + if (isset($params['port'])) { + $dsn .= '(PORT=' . $params['port'] . ')'; + } else { + $dsn .= '(PORT=1521)'; + } + + if (isset($params['service']) && $params['service'] == true) { + $dsn .= '))(CONNECT_DATA=(SERVICE_NAME=' . $params['dbname'] . '))'; + } else { + $dsn .= '))(CONNECT_DATA=(SID=' . $params['dbname'] . '))'; + } + if (isset($params['pooled']) && $params['pooled'] == true) { + $dsn .= '(SERVER=POOLED)'; + } + $dsn .= ')'; + } else { + $dsn .= $params['dbname']; + } + return $dsn; + } + + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\OraclePlatform(); + } + + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\OracleSchemaManager($conn); + } + + public function getName() + { + return 'oci8'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['user']; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php new file mode 100644 index 0000000..bc74787 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php @@ -0,0 +1,200 @@ +. + */ + +namespace Doctrine\DBAL\Driver\OCI8; + +use Doctrine\DBAL\Platforms\OraclePlatform; + +/** + * OCI8 implementation of the Connection interface. + * + * @since 2.0 + */ +class OCI8Connection implements \Doctrine\DBAL\Driver\Connection +{ + /** + * @var resource + */ + protected $dbh; + + /** + * @var int + */ + protected $executeMode = OCI_COMMIT_ON_SUCCESS; + + /** + * Create a Connection to an Oracle Database using oci8 extension. + * + * @param string $username + * @param string $password + * @param string $db + */ + public function __construct($username, $password, $db, $charset = null, $sessionMode = OCI_DEFAULT, $persistent = false) + { + if (!defined('OCI_NO_AUTO_COMMIT')) { + define('OCI_NO_AUTO_COMMIT', 0); + } + + $this->dbh = $persistent + ? @oci_pconnect($username, $password, $db, $charset, $sessionMode) + : @oci_connect($username, $password, $db, $charset, $sessionMode); + + if ( ! $this->dbh) { + throw OCI8Exception::fromErrorInfo(oci_error()); + } + } + + /** + * Create a non-executed prepared statement. + * + * @param string $prepareString + * @return OCI8Statement + */ + public function prepare($prepareString) + { + return new OCI8Statement($this->dbh, $prepareString, $this); + } + + /** + * @param string $sql + * @return OCI8Statement + */ + public function query() + { + $args = func_get_args(); + $sql = $args[0]; + //$fetchMode = $args[1]; + $stmt = $this->prepare($sql); + $stmt->execute(); + return $stmt; + } + + /** + * Quote input value. + * + * @param mixed $input + * @param int $type PDO::PARAM* + * @return mixed + */ + public function quote($value, $type=\PDO::PARAM_STR) + { + if (is_int($value) || is_float($value)) { + return $value; + } + $value = str_replace("'", "''", $value); + return "'" . addcslashes($value, "\000\n\r\\\032") . "'"; + } + + /** + * + * @param string $statement + * @return int + */ + public function exec($statement) + { + $stmt = $this->prepare($statement); + $stmt->execute(); + return $stmt->rowCount(); + } + + /** + * {@inheritDoc} + */ + public function lastInsertId($name = null) + { + if ($name === null) { + return false; + } + + OraclePlatform::assertValidIdentifier($name); + + $sql = 'SELECT ' . $name . '.CURRVAL FROM DUAL'; + $stmt = $this->query($sql); + $result = $stmt->fetch(\PDO::FETCH_ASSOC); + + if ($result === false || !isset($result['CURRVAL'])) { + throw new OCI8Exception("lastInsertId failed: Query was executed but no result was returned."); + } + + return (int) $result['CURRVAL']; + } + + /** + * Return the current execution mode. + */ + public function getExecuteMode() + { + return $this->executeMode; + } + + /** + * Start a transactiom + * + * Oracle has to explicitly set the autocommit mode off. That means + * after connection, a commit or rollback there is always automatically + * opened a new transaction. + * + * @return bool + */ + public function beginTransaction() + { + $this->executeMode = OCI_NO_AUTO_COMMIT; + return true; + } + + /** + * @throws OCI8Exception + * @return bool + */ + public function commit() + { + if (!oci_commit($this->dbh)) { + throw OCI8Exception::fromErrorInfo($this->errorInfo()); + } + $this->executeMode = OCI_COMMIT_ON_SUCCESS; + return true; + } + + /** + * @throws OCI8Exception + * @return bool + */ + public function rollBack() + { + if (!oci_rollback($this->dbh)) { + throw OCI8Exception::fromErrorInfo($this->errorInfo()); + } + $this->executeMode = OCI_COMMIT_ON_SUCCESS; + return true; + } + + public function errorCode() + { + $error = oci_error($this->dbh); + if ($error !== false) { + $error = $error['code']; + } + return $error; + } + + public function errorInfo() + { + return oci_error($this->dbh); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php new file mode 100644 index 0000000..adeb13f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php @@ -0,0 +1,30 @@ +. +*/ + +namespace Doctrine\DBAL\Driver\OCI8; + +class OCI8Exception extends \Exception +{ + static public function fromErrorInfo($error) + { + return new self($error['message'], $error['code']); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php new file mode 100644 index 0000000..8bf3121 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @@ -0,0 +1,268 @@ +. + */ + +namespace Doctrine\DBAL\Driver\OCI8; + +use PDO; +use IteratorAggregate; +use Doctrine\DBAL\Driver\Statement; + +/** + * The OCI8 implementation of the Statement interface. + * + * @since 2.0 + * @author Roman Borschel + */ +class OCI8Statement implements \IteratorAggregate, Statement +{ + /** Statement handle. */ + protected $_dbh; + protected $_sth; + protected $_conn; + protected static $_PARAM = ':param'; + protected static $fetchModeMap = array( + PDO::FETCH_BOTH => OCI_BOTH, + PDO::FETCH_ASSOC => OCI_ASSOC, + PDO::FETCH_NUM => OCI_NUM, + PDO::PARAM_LOB => OCI_B_BLOB, + PDO::FETCH_COLUMN => OCI_NUM, + ); + protected $_defaultFetchMode = PDO::FETCH_BOTH; + protected $_paramMap = array(); + + /** + * Creates a new OCI8Statement that uses the given connection handle and SQL statement. + * + * @param resource $dbh The connection handle. + * @param string $statement The SQL statement. + */ + public function __construct($dbh, $statement, OCI8Connection $conn) + { + list($statement, $paramMap) = self::convertPositionalToNamedPlaceholders($statement); + $this->_sth = oci_parse($dbh, $statement); + $this->_dbh = $dbh; + $this->_paramMap = $paramMap; + $this->_conn = $conn; + } + + /** + * Convert positional (?) into named placeholders (:param) + * + * Oracle does not support positional parameters, hence this method converts all + * positional parameters into artificially named parameters. Note that this conversion + * is not perfect. All question marks (?) in the original statement are treated as + * placeholders and converted to a named parameter. + * + * The algorithm uses a state machine with two possible states: InLiteral and NotInLiteral. + * Question marks inside literal strings are therefore handled correctly by this method. + * This comes at a cost, the whole sql statement has to be looped over. + * + * @todo extract into utility class in Doctrine\DBAL\Util namespace + * @todo review and test for lost spaces. we experienced missing spaces with oci8 in some sql statements. + * @param string $statement The SQL statement to convert. + * @return string + */ + static public function convertPositionalToNamedPlaceholders($statement) + { + $count = 1; + $inLiteral = false; // a valid query never starts with quotes + $stmtLen = strlen($statement); + $paramMap = array(); + for ($i = 0; $i < $stmtLen; $i++) { + if ($statement[$i] == '?' && !$inLiteral) { + // real positional parameter detected + $paramMap[$count] = ":param$count"; + $len = strlen($paramMap[$count]); + $statement = substr_replace($statement, ":param$count", $i, 1); + $i += $len-1; // jump ahead + $stmtLen = strlen($statement); // adjust statement length + ++$count; + } else if ($statement[$i] == "'" || $statement[$i] == '"') { + $inLiteral = ! $inLiteral; // switch state! + } + } + + return array($statement, $paramMap); + } + + /** + * {@inheritdoc} + */ + public function bindValue($param, $value, $type = null) + { + return $this->bindParam($param, $value, $type, null); + } + + /** + * {@inheritdoc} + */ + public function bindParam($column, &$variable, $type = null,$length = null) + { + $column = isset($this->_paramMap[$column]) ? $this->_paramMap[$column] : $column; + + if ($type == \PDO::PARAM_LOB) { + $lob = oci_new_descriptor($this->_dbh, OCI_D_LOB); + $lob->writeTemporary($variable, OCI_TEMP_BLOB); + + return oci_bind_by_name($this->_sth, $column, $lob, -1, OCI_B_BLOB); + } else { + return oci_bind_by_name($this->_sth, $column, $variable); + } + } + + /** + * Closes the cursor, enabling the statement to be executed again. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function closeCursor() + { + return oci_free_statement($this->_sth); + } + + /** + * {@inheritdoc} + */ + public function columnCount() + { + return oci_num_fields($this->_sth); + } + + /** + * {@inheritdoc} + */ + public function errorCode() + { + $error = oci_error($this->_sth); + if ($error !== false) { + $error = $error['code']; + } + return $error; + } + + /** + * {@inheritdoc} + */ + public function errorInfo() + { + return oci_error($this->_sth); + } + + /** + * {@inheritdoc} + */ + public function execute($params = null) + { + if ($params) { + $hasZeroIndex = array_key_exists(0, $params); + foreach ($params as $key => $val) { + if ($hasZeroIndex && is_numeric($key)) { + $this->bindValue($key + 1, $val); + } else { + $this->bindValue($key, $val); + } + } + } + + $ret = @oci_execute($this->_sth, $this->_conn->getExecuteMode()); + if ( ! $ret) { + throw OCI8Exception::fromErrorInfo($this->errorInfo()); + } + return $ret; + } + + /** + * {@inheritdoc} + */ + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->_defaultFetchMode = $fetchMode; + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + $data = $this->fetchAll(); + return new \ArrayIterator($data); + } + + /** + * {@inheritdoc} + */ + public function fetch($fetchMode = null) + { + $fetchMode = $fetchMode ?: $this->_defaultFetchMode; + if ( ! isset(self::$fetchModeMap[$fetchMode])) { + throw new \InvalidArgumentException("Invalid fetch style: " . $fetchMode); + } + + return oci_fetch_array($this->_sth, self::$fetchModeMap[$fetchMode] | OCI_RETURN_NULLS | OCI_RETURN_LOBS); + } + + /** + * {@inheritdoc} + */ + public function fetchAll($fetchMode = null) + { + $fetchMode = $fetchMode ?: $this->_defaultFetchMode; + if ( ! isset(self::$fetchModeMap[$fetchMode])) { + throw new \InvalidArgumentException("Invalid fetch style: " . $fetchMode); + } + + $result = array(); + if (self::$fetchModeMap[$fetchMode] === OCI_BOTH) { + while ($row = $this->fetch($fetchMode)) { + $result[] = $row; + } + } else { + $fetchStructure = OCI_FETCHSTATEMENT_BY_ROW; + if ($fetchMode == PDO::FETCH_COLUMN) { + $fetchStructure = OCI_FETCHSTATEMENT_BY_COLUMN; + } + + oci_fetch_all($this->_sth, $result, 0, -1, + self::$fetchModeMap[$fetchMode] | OCI_RETURN_NULLS | $fetchStructure | OCI_RETURN_LOBS); + + if ($fetchMode == PDO::FETCH_COLUMN) { + $result = $result[0]; + } + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function fetchColumn($columnIndex = 0) + { + $row = oci_fetch_array($this->_sth, OCI_NUM | OCI_RETURN_NULLS | OCI_RETURN_LOBS); + return isset($row[$columnIndex]) ? $row[$columnIndex] : false; + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + return oci_num_rows($this->_sth); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php new file mode 100644 index 0000000..4595e5a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\DBAL\Driver; + +use \PDO; + +/** + * PDO implementation of the Connection interface. + * Used by all PDO-based drivers. + * + * @since 2.0 + */ +class PDOConnection extends PDO implements Connection +{ + public function __construct($dsn, $user = null, $password = null, array $options = null) + { + parent::__construct($dsn, $user, $password, $options); + $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Doctrine\DBAL\Driver\PDOStatement', array())); + $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php new file mode 100644 index 0000000..de30757 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php @@ -0,0 +1,126 @@ +. +*/ + +namespace Doctrine\DBAL\Driver\PDOIbm; + +use Doctrine\DBAL\Connection; + +/** + * Driver for the PDO IBM extension + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Driver implements \Doctrine\DBAL\Driver +{ + /** + * Attempts to establish a connection with the underlying driver. + * + * @param array $params + * @param string $username + * @param string $password + * @param array $driverOptions + * @return \Doctrine\DBAL\Driver\Connection + */ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + $conn = new \Doctrine\DBAL\Driver\PDOConnection( + $this->_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + return $conn; + } + + /** + * Constructs the MySql PDO DSN. + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params) + { + $dsn = 'ibm:'; + if (isset($params['host'])) { + $dsn .= 'HOSTNAME=' . $params['host'] . ';'; + } + if (isset($params['port'])) { + $dsn .= 'PORT=' . $params['port'] . ';'; + } + $dsn .= 'PROTOCOL=TCPIP;'; + if (isset($params['dbname'])) { + $dsn .= 'DATABASE=' . $params['dbname'] . ';'; + } + + return $dsn; + } + + /** + * Gets the DatabasePlatform instance that provides all the metadata about + * the platform this driver connects to. + * + * @return \Doctrine\DBAL\Platforms\AbstractPlatform The database platform. + */ + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\DB2Platform; + } + + /** + * Gets the SchemaManager that can be used to inspect and change the underlying + * database schema of the platform this driver connects to. + * + * @param \Doctrine\DBAL\Connection $conn + * @return \Doctrine\DBAL\Schema\DB2SchemaManager + */ + public function getSchemaManager(Connection $conn) + { + return new \Doctrine\DBAL\Schema\DB2SchemaManager($conn); + } + + /** + * Gets the name of the driver. + * + * @return string The name of the driver. + */ + public function getName() + { + return 'pdo_ibm'; + } + + /** + * Get the name of the database connected to for this driver. + * + * @param \Doctrine\DBAL\Connection $conn + * @return string $database + */ + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['dbname']; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php new file mode 100644 index 0000000..eeb6727 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php @@ -0,0 +1,102 @@ +. + */ + +namespace Doctrine\DBAL\Driver\PDOMySql; + +use Doctrine\DBAL\Connection; + +/** + * PDO MySql driver. + * + * @since 2.0 + */ +class Driver implements \Doctrine\DBAL\Driver +{ + /** + * Attempts to establish a connection with the underlying driver. + * + * @param array $params + * @param string $username + * @param string $password + * @param array $driverOptions + * @return \Doctrine\DBAL\Driver\Connection + */ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + $conn = new \Doctrine\DBAL\Driver\PDOConnection( + $this->_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + return $conn; + } + + /** + * Constructs the MySql PDO DSN. + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params) + { + $dsn = 'mysql:'; + if (isset($params['host']) && $params['host'] != '') { + $dsn .= 'host=' . $params['host'] . ';'; + } + if (isset($params['port'])) { + $dsn .= 'port=' . $params['port'] . ';'; + } + if (isset($params['dbname'])) { + $dsn .= 'dbname=' . $params['dbname'] . ';'; + } + if (isset($params['unix_socket'])) { + $dsn .= 'unix_socket=' . $params['unix_socket'] . ';'; + } + if (isset($params['charset'])) { + $dsn .= 'charset=' . $params['charset'] . ';'; + } + + return $dsn; + } + + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\MySqlPlatform(); + } + + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\MySqlSchemaManager($conn); + } + + public function getName() + { + return 'pdo_mysql'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + + if (isset($params['dbname'])) { + return $params['dbname']; + } + return $conn->query('SELECT DATABASE()')->fetchColumn(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php new file mode 100644 index 0000000..cb2e6b0 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php @@ -0,0 +1,98 @@ +. + */ + +namespace Doctrine\DBAL\Driver\PDOOracle; + +use Doctrine\DBAL\Platforms; + +/** + * PDO Oracle driver + * + * WARNING: This driver gives us segfauls in our testsuites on CLOB and other + * stuff. PDO Oracle is not maintained by Oracle or anyone in the PHP community, + * which leads us to the recommendation to use the "oci8" driver to connect + * to Oracle instead. + */ +class Driver implements \Doctrine\DBAL\Driver +{ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + return new \Doctrine\DBAL\Driver\PDOConnection( + $this->_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + } + + /** + * Constructs the Oracle PDO DSN. + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params) + { + $dsn = 'oci:'; + if (isset($params['host']) && $params['host'] != '') { + $dsn .= 'dbname=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)' . + '(HOST=' . $params['host'] . ')'; + + if (isset($params['port'])) { + $dsn .= '(PORT=' . $params['port'] . ')'; + } else { + $dsn .= '(PORT=1521)'; + } + + if (isset($params['service']) && $params['service'] == true) { + $dsn .= '))(CONNECT_DATA=(SERVICE_NAME=' . $params['dbname'] . ')))'; + } else { + $dsn .= '))(CONNECT_DATA=(SID=' . $params['dbname'] . ')))'; + } + } else { + $dsn .= 'dbname=' . $params['dbname']; + } + + if (isset($params['charset'])) { + $dsn .= ';charset=' . $params['charset']; + } + + return $dsn; + } + + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\OraclePlatform(); + } + + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\OracleSchemaManager($conn); + } + + public function getName() + { + return 'pdo_oracle'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['user']; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php new file mode 100644 index 0000000..951406d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php @@ -0,0 +1,70 @@ +_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + } + + /** + * Constructs the Postgres PDO DSN. + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params) + { + $dsn = 'pgsql:'; + if (isset($params['host']) && $params['host'] != '') { + $dsn .= 'host=' . $params['host'] . ' '; + } + if (isset($params['port']) && $params['port'] != '') { + $dsn .= 'port=' . $params['port'] . ' '; + } + if (isset($params['dbname'])) { + $dsn .= 'dbname=' . $params['dbname'] . ' '; + } + + return $dsn; + } + + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\PostgreSqlPlatform(); + } + + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\PostgreSqlSchemaManager($conn); + } + + public function getName() + { + return 'pdo_pgsql'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['dbname']; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php new file mode 100644 index 0000000..903d999 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php @@ -0,0 +1,116 @@ +. + */ + +namespace Doctrine\DBAL\Driver\PDOSqlite; + +/** + * The PDO Sqlite driver. + * + * @since 2.0 + */ +class Driver implements \Doctrine\DBAL\Driver +{ + /** + * @var array + */ + protected $_userDefinedFunctions = array( + 'sqrt' => array('callback' => array('Doctrine\DBAL\Platforms\SqlitePlatform', 'udfSqrt'), 'numArgs' => 1), + 'mod' => array('callback' => array('Doctrine\DBAL\Platforms\SqlitePlatform', 'udfMod'), 'numArgs' => 2), + 'locate' => array('callback' => array('Doctrine\DBAL\Platforms\SqlitePlatform', 'udfLocate'), 'numArgs' => -1), + ); + + /** + * Tries to establish a database connection to SQLite. + * + * @param array $params + * @param string $username + * @param string $password + * @param array $driverOptions + * @return \Doctrine\DBAL\Driver\PDOConnection + */ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + if (isset($driverOptions['userDefinedFunctions'])) { + $this->_userDefinedFunctions = array_merge( + $this->_userDefinedFunctions, $driverOptions['userDefinedFunctions']); + unset($driverOptions['userDefinedFunctions']); + } + + $pdo = new \Doctrine\DBAL\Driver\PDOConnection( + $this->_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + + foreach ($this->_userDefinedFunctions as $fn => $data) { + $pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']); + } + + return $pdo; + } + + /** + * Constructs the Sqlite PDO DSN. + * + * @return string The DSN. + * @override + */ + protected function _constructPdoDsn(array $params) + { + $dsn = 'sqlite:'; + if (isset($params['path'])) { + $dsn .= $params['path']; + } else if (isset($params['memory'])) { + $dsn .= ':memory:'; + } + + return $dsn; + } + + /** + * Gets the database platform that is relevant for this driver. + */ + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\SqlitePlatform(); + } + + /** + * Gets the schema manager that is relevant for this driver. + * + * @param \Doctrine\DBAL\Connection $conn + * @return \Doctrine\DBAL\Schema\SqliteSchemaManager + */ + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\SqliteSchemaManager($conn); + } + + public function getName() + { + return 'pdo_sqlite'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return isset($params['path']) ? $params['path'] : null; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php new file mode 100644 index 0000000..01a5769 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\DBAL\Driver\PDOSqlsrv; + +/** + * Sqlsrv Connection implementation. + * + * @since 2.0 + */ +class Connection extends \Doctrine\DBAL\Driver\PDOConnection implements \Doctrine\DBAL\Driver\Connection +{ + /** + * @override + */ + public function quote($value, $type=\PDO::PARAM_STR) + { + $val = parent::quote($value, $type); + + // Fix for a driver version terminating all values with null byte + if (strpos($val, "\0") !== false) { + $val = substr($val, 0, -1); + } + + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php new file mode 100644 index 0000000..7072b5f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php @@ -0,0 +1,87 @@ +. + */ + +namespace Doctrine\DBAL\Driver\PDOSqlsrv; + +/** + * The PDO-based Sqlsrv driver. + * + * @since 2.0 + */ +class Driver implements \Doctrine\DBAL\Driver +{ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + return new Connection( + $this->_constructPdoDsn($params), + $username, + $password, + $driverOptions + ); + } + + /** + * Constructs the Sqlsrv PDO DSN. + * + * @return string The DSN. + */ + private function _constructPdoDsn(array $params) + { + $dsn = 'sqlsrv:server='; + + if (isset($params['host'])) { + $dsn .= $params['host']; + } + + if (isset($params['port']) && !empty($params['port'])) { + $dsn .= ',' . $params['port']; + } + + if (isset($params['dbname'])) {; + $dsn .= ';Database=' . $params['dbname']; + } + + if (isset($params['MultipleActiveResultSets'])) { + $dsn .= '; MultipleActiveResultSets=' . ($params['MultipleActiveResultSets'] ? 'true' : 'false'); + } + + return $dsn; + } + + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\SQLServer2008Platform(); + } + + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\SQLServerSchemaManager($conn); + } + + public function getName() + { + return 'pdo_sqlsrv'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['dbname']; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php new file mode 100644 index 0000000..2673ae9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php @@ -0,0 +1,50 @@ +. + */ + +namespace Doctrine\DBAL\Driver; + +/** + * The PDO implementation of the Statement interface. + * Used by all PDO-based drivers. + * + * @since 2.0 + */ +class PDOStatement extends \PDOStatement implements Statement +{ + private function __construct() {} + + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + // This thin wrapper is necessary to shield against the weird signature + // of PDOStatement::setFetchMode(): even if the second and third + // parameters are optional, PHP will not let us remove it from this + // declaration. + if ($arg2 === null && $arg3 === null) { + return parent::setFetchMode($fetchMode); + } + + if ($arg3 === null) { + return parent::setFetchMode($fetchMode, $arg2); + } + + return parent::setFetchMode($fetchMode, $arg2, $arg3); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ResultStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ResultStatement.php new file mode 100644 index 0000000..561dc35 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/ResultStatement.php @@ -0,0 +1,93 @@ +. + */ + +namespace Doctrine\DBAL\Driver; + +use PDO; + +/** + * Interface for the reading part of a prepare statement only. + * + * @author Benjamin Eberlei + */ +interface ResultStatement extends \Traversable +{ + /** + * Closes the cursor, enabling the statement to be executed again. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + function closeCursor(); + + + /** + * columnCount + * Returns the number of columns in the result set + * + * @return integer Returns the number of columns in the result set represented + * by the PDOStatement object. If there is no result set, + * this method should return 0. + */ + function columnCount(); + + /** + * setFetchMode + * Set the fetch mode to use while iterating this statement. + * + * @param integer $fetchMode + */ + function setFetchMode($fetchMode, $arg2 = null, $arg3 = null); + + /** + * fetch + * + * @see Query::HYDRATE_* constants + * @param integer $fetchMode Controls how the next row will be returned to the caller. + * This value must be one of the Query::HYDRATE_* constants, + * defaulting to Query::HYDRATE_BOTH + * + * @return mixed + */ + function fetch($fetchMode = null); + + /** + * Returns an array containing all of the result set rows + * + * @param integer $fetchMode Controls how the next row will be returned to the caller. + * This value must be one of the Query::HYDRATE_* constants, + * defaulting to Query::HYDRATE_BOTH + * + * @return array + */ + function fetchAll($fetchMode = null); + + /** + * fetchColumn + * Returns a single column from the next row of a + * result set or FALSE if there are no more rows. + * + * @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. If no + * value is supplied, PDOStatement->fetchColumn() + * fetches the first column. + * + * @return string returns a single column in the next row of a result set. + */ + function fetchColumn($columnIndex = 0); +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php new file mode 100644 index 0000000..c7043cc --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php @@ -0,0 +1,72 @@ +. + */ + +namespace Doctrine\DBAL\Driver\SQLSrv; + +/** + * Driver for ext/sqlsrv + */ +class Driver implements \Doctrine\DBAL\Driver +{ + public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) + { + if (!isset($params['host'])) { + throw new SQLSrvException("Missing 'host' in configuration for sqlsrv driver."); + } + if (!isset($params['dbname'])) { + throw new SQLSrvException("Missing 'dbname' in configuration for sqlsrv driver."); + } + + $serverName = $params['host']; + if (isset($params['port'])) { + $serverName .= ', ' . $params['port']; + } + $driverOptions['Database'] = $params['dbname']; + $driverOptions['UID'] = $username; + $driverOptions['PWD'] = $password; + + if (!isset($driverOptions['ReturnDatesAsStrings'])) { + $driverOptions['ReturnDatesAsStrings'] = 1; + } + + return new SQLSrvConnection($serverName, $driverOptions); + } + + public function getDatabasePlatform() + { + return new \Doctrine\DBAL\Platforms\SQLServer2008Platform(); + } + + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + return new \Doctrine\DBAL\Schema\SQLServerSchemaManager($conn); + } + + public function getName() + { + return 'sqlsrv'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + $params = $conn->getParams(); + return $params['dbname']; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/LastInsertId.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/LastInsertId.php new file mode 100644 index 0000000..421d071 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/LastInsertId.php @@ -0,0 +1,42 @@ +. + */ + +namespace Doctrine\DBAL\Driver\SQLSrv; + +/** + * Last Id Data Container + * + * @since 2.3 + * @author Benjamin Eberlei + */ +class LastInsertId +{ + private $id; + + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php new file mode 100644 index 0000000..82544ca --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php @@ -0,0 +1,161 @@ +. + */ + +namespace Doctrine\DBAL\Driver\SQLSrv; + +/** + * SQL Server implementation for the Connection interface. + * + * @since 2.3 + * @author Benjamin Eberlei + */ +class SQLSrvConnection implements \Doctrine\DBAL\Driver\Connection +{ + /** + * @var resource + */ + protected $conn; + + /** + * @var LastInsertId + */ + protected $lastInsertId; + + + public function __construct($serverName, $connectionOptions) + { + $this->conn = sqlsrv_connect($serverName, $connectionOptions); + if ( ! $this->conn) { + throw SQLSrvException::fromSqlSrvErrors(); + } + $this->lastInsertId = new LastInsertId(); + } + + /** + * {@inheritDoc} + */ + public function prepare($sql) + { + return new SQLSrvStatement($this->conn, $sql, $this->lastInsertId); + } + + /** + * {@inheritDoc} + */ + public function query() + { + $args = func_get_args(); + $sql = $args[0]; + $stmt = $this->prepare($sql); + $stmt->execute(); + return $stmt; + } + + /** + * {@inheritDoc} + * @license New BSD, code from Zend Framework + */ + public function quote($value, $type=\PDO::PARAM_STR) + { + if (is_int($value)) { + return $value; + } else if (is_float($value)) { + return sprintf('%F', $value); + } + + return "'" . str_replace("'", "''", $value) . "'"; + } + + /** + * {@inheritDoc} + */ + public function exec($statement) + { + $stmt = $this->prepare($statement); + $stmt->execute(); + return $stmt->rowCount(); + } + + /** + * {@inheritDoc} + */ + public function lastInsertId($name = null) + { + if ($name !== null) { + $sql = "SELECT IDENT_CURRENT(".$this->quote($name).") AS LastInsertId"; + $stmt = $this->prepare($sql); + $stmt->execute(); + + return $stmt->fetchColumn(); + } + + return $this->lastInsertId->getId(); + } + + /** + * {@inheritDoc} + */ + public function beginTransaction() + { + if ( ! sqlsrv_begin_transaction($this->conn)) { + throw SQLSrvException::fromSqlSrvErrors(); + } + } + + /** + * {@inheritDoc} + */ + public function commit() + { + if ( ! sqlsrv_commit($this->conn)) { + throw SQLSrvException::fromSqlSrvErrors(); + } + } + + /** + * {@inheritDoc} + */ + public function rollBack() + { + if ( ! sqlsrv_rollback($this->conn)) { + throw SQLSrvException::fromSqlSrvErrors(); + } + } + + /** + * {@inheritDoc} + */ + public function errorCode() + { + $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); + if ($errors) { + return $errors[0]['code']; + } + return false; + } + + /** + * {@inheritDoc} + */ + public function errorInfo() + { + return sqlsrv_errors(SQLSRV_ERR_ERRORS); + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php new file mode 100644 index 0000000..6777877 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php @@ -0,0 +1,43 @@ +. + */ + +namespace Doctrine\DBAL\Driver\SQLSrv; + +class SQLSrvException extends \Doctrine\DBAL\DBALException +{ + /** + * Helper method to turn sql server errors into exception. + * + * @return SQLSrvException + */ + static public function fromSqlSrvErrors() + { + $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); + $message = ""; + foreach ($errors as $error) { + $message .= "SQLSTATE [".$error['SQLSTATE'].", ".$error['code']."]: ". $error['message']."\n"; + } + if ( ! $message) { + $message = "SQL Server error occured but no error message was retrieved from driver."; + } + + return new self(rtrim($message)); + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php new file mode 100644 index 0000000..76a156b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php @@ -0,0 +1,251 @@ +. + */ + +namespace Doctrine\DBAL\Driver\SQLSrv; + +use PDO; +use IteratorAggregate; +use Doctrine\DBAL\Driver\Statement; + +/** + * SQL Server Statement + * + * @since 2.3 + * @author Benjamin Eberlei + */ +class SQLSrvStatement implements IteratorAggregate, Statement +{ + /** + * SQLSRV Resource + * + * @var resource + */ + private $conn; + + /** + * SQL Statement to execute + * + * @var string + */ + private $sql; + + /** + * SQLSRV Statement Resource + * + * @var resource + */ + private $stmt; + + /** + * Parameters to bind + * + * @var array + */ + private $params = array(); + + /** + * Translations + * + * @var array + */ + private static $fetchMap = array( + PDO::FETCH_BOTH => SQLSRV_FETCH_BOTH, + PDO::FETCH_ASSOC => SQLSRV_FETCH_ASSOC, + PDO::FETCH_NUM => SQLSRV_FETCH_NUMERIC, + ); + + /** + * Fetch Style + * + * @param int + */ + private $defaultFetchMode = PDO::FETCH_BOTH; + + /** + * @var int|null + */ + private $lastInsertId; + + /** + * Append to any INSERT query to retrieve the last insert id. + * + * @var string + */ + const LAST_INSERT_ID_SQL = ';SELECT SCOPE_IDENTITY() AS LastInsertId;'; + + public function __construct($conn, $sql, $lastInsertId = null) + { + $this->conn = $conn; + $this->sql = $sql; + + if (stripos($sql, 'INSERT INTO ') === 0) { + $this->sql .= self::LAST_INSERT_ID_SQL; + $this->lastInsertId = $lastInsertId; + } + } + + public function bindValue($param, $value, $type = null) + { + return $this->bindParam($param, $value, $type,null); + } + + /** + * {@inheritdoc} + */ + public function bindParam($column, &$variable, $type = null, $length = null) + { + if (!is_numeric($column)) { + throw new SQLSrvException("sqlsrv does not support named parameters to queries, use question mark (?) placeholders instead."); + } + + if ($type === \PDO::PARAM_LOB) { + $this->params[$column-1] = array($variable, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_VARBINARY('max')); + } else { + $this->params[$column-1] = $variable; + } + } + + public function closeCursor() + { + if ($this->stmt) { + sqlsrv_free_stmt($this->stmt); + } + } + + public function columnCount() + { + return sqlsrv_num_fields($this->stmt); + } + + /** + * {@inheritDoc} + */ + public function errorCode() + { + $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); + if ($errors) { + return $errors[0]['code']; + } + return false; + } + + /** + * {@inheritDoc} + */ + public function errorInfo() + { + return sqlsrv_errors(SQLSRV_ERR_ERRORS); + } + + public function execute($params = null) + { + if ($params) { + $hasZeroIndex = array_key_exists(0, $params); + foreach ($params as $key => $val) { + $key = ($hasZeroIndex && is_numeric($key)) ? $key + 1 : $key; + $this->bindValue($key, $val); + } + } + + $this->stmt = sqlsrv_query($this->conn, $this->sql, $this->params); + if ( ! $this->stmt) { + throw SQLSrvException::fromSqlSrvErrors(); + } + + if ($this->lastInsertId) { + sqlsrv_next_result($this->stmt); + sqlsrv_fetch($this->stmt); + $this->lastInsertId->setId( sqlsrv_get_field($this->stmt, 0) ); + } + } + + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + $this->defaultFetchMode = $fetchMode; + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + $data = $this->fetchAll(); + return new \ArrayIterator($data); + } + + /** + * {@inheritdoc} + */ + public function fetch($fetchMode = null) + { + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + if (isset(self::$fetchMap[$fetchMode])) { + return sqlsrv_fetch_array($this->stmt, self::$fetchMap[$fetchMode]); + } else if ($fetchMode == PDO::FETCH_OBJ || $fetchMode == PDO::FETCH_CLASS) { + $className = null; + $ctorArgs = null; + if (func_num_args() >= 2) { + $args = func_get_args(); + $className = $args[1]; + $ctorArgs = (isset($args[2])) ? $args[2] : array(); + } + return sqlsrv_fetch_object($this->stmt, $className, $ctorArgs); + } + + throw new SQLSrvException("Fetch mode is not supported!"); + } + + /** + * {@inheritdoc} + */ + public function fetchAll($fetchMode = null) + { + $className = null; + $ctorArgs = null; + if (func_num_args() >= 2) { + $args = func_get_args(); + $className = $args[1]; + $ctorArgs = (isset($args[2])) ? $args[2] : array(); + } + + $rows = array(); + while ($row = $this->fetch($fetchMode, $className, $ctorArgs)) { + $rows[] = $row; + } + return $rows; + } + + /** + * {@inheritdoc} + */ + public function fetchColumn($columnIndex = 0) + { + $row = $this->fetch(PDO::FETCH_NUM); + return $row[$columnIndex]; + } + + /** + * {@inheritdoc} + */ + public function rowCount() + { + return sqlsrv_rows_affected($this->stmt); + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Statement.php new file mode 100644 index 0000000..718614d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/Statement.php @@ -0,0 +1,125 @@ +. + */ + +namespace Doctrine\DBAL\Driver; + +use \PDO; + +/** + * Statement interface. + * Drivers must implement this interface. + * + * This resembles (a subset of) the PDOStatement interface. + * + * @author Konsta Vesterinen + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + */ +interface Statement extends ResultStatement +{ + /** + * Binds a value to a corresponding named or positional + * placeholder in the SQL statement that was used to prepare the statement. + * + * @param mixed $param Parameter identifier. For a prepared statement using named placeholders, + * this will be a parameter name of the form :name. For a prepared statement + * using question mark placeholders, this will be the 1-indexed position of the parameter + * + * @param mixed $value The value to bind to the parameter. + * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + function bindValue($param, $value, $type = null); + + /** + * Binds a PHP variable to a corresponding named or question mark placeholder in the + * SQL statement that was use to prepare the statement. Unlike PDOStatement->bindValue(), + * the variable is bound as a reference and will only be evaluated at the time + * that PDOStatement->execute() is called. + * + * Most parameters are input parameters, that is, parameters that are + * used in a read-only fashion to build up the query. Some drivers support the invocation + * of stored procedures that return data as output parameters, and some also as input/output + * parameters that both send in data and are updated to receive it. + * + * @param mixed $column Parameter identifier. For a prepared statement using named placeholders, + * this will be a parameter name of the form :name. For a prepared statement + * using question mark placeholders, this will be the 1-indexed position of the parameter + * + * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. + * + * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. To return + * an INOUT parameter from a stored procedure, use the bitwise OR operator to set the + * PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter. + * @param integer $length You must specify maxlength when using an OUT bind so that PHP allocates enough memory to hold the returned value. + * @return boolean Returns TRUE on success or FALSE on failure. + */ + function bindParam($column, &$variable, $type = null, $length = null); + + /** + * errorCode + * Fetch the SQLSTATE associated with the last operation on the statement handle + * + * @see Doctrine_Adapter_Interface::errorCode() + * @return string error code string + */ + function errorCode(); + + /** + * errorInfo + * Fetch extended error information associated with the last operation on the statement handle + * + * @see Doctrine_Adapter_Interface::errorInfo() + * @return array error info array + */ + function errorInfo(); + + /** + * Executes a prepared statement + * + * If the prepared statement included parameter markers, you must either: + * call PDOStatement->bindParam() to bind PHP variables to the parameter markers: + * bound variables pass their value as input and receive the output value, + * if any, of their associated parameter markers or pass an array of input-only + * parameter values + * + * + * @param array $params An array of values with as many elements as there are + * bound parameters in the SQL statement being executed. + * @return boolean Returns TRUE on success or FALSE on failure. + */ + function execute($params = null); + + /** + * rowCount + * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement + * executed by the corresponding object. + * + * If the last SQL statement executed by the associated Statement object was a SELECT statement, + * some databases may return the number of rows returned by that statement. However, + * this behaviour is not guaranteed for all databases and should not be + * relied on for portable applications. + * + * @return integer Returns the number of rows. + */ + function rowCount(); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/DriverManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/DriverManager.php new file mode 100644 index 0000000..7cdde95 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/DriverManager.php @@ -0,0 +1,176 @@ +. + */ + +namespace Doctrine\DBAL; + +use Doctrine\Common\EventManager; + +/** + * Factory for creating Doctrine\DBAL\Connection instances. + * + * @author Roman Borschel + * @since 2.0 + */ +final class DriverManager +{ + /** + * List of supported drivers and their mappings to the driver classes. + * + * To add your own driver use the 'driverClass' parameter to + * {@link DriverManager::getConnection()}. + * + * @var array + */ + private static $_driverMap = array( + 'pdo_mysql' => 'Doctrine\DBAL\Driver\PDOMySql\Driver', + 'pdo_sqlite' => 'Doctrine\DBAL\Driver\PDOSqlite\Driver', + 'pdo_pgsql' => 'Doctrine\DBAL\Driver\PDOPgSql\Driver', + 'pdo_oci' => 'Doctrine\DBAL\Driver\PDOOracle\Driver', + 'oci8' => 'Doctrine\DBAL\Driver\OCI8\Driver', + 'ibm_db2' => 'Doctrine\DBAL\Driver\IBMDB2\DB2Driver', + 'pdo_ibm' => 'Doctrine\DBAL\Driver\PDOIbm\Driver', + 'pdo_sqlsrv' => 'Doctrine\DBAL\Driver\PDOSqlsrv\Driver', + 'mysqli' => 'Doctrine\DBAL\Driver\Mysqli\Driver', + 'drizzle_pdo_mysql' => 'Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver', + 'sqlsrv' => 'Doctrine\DBAL\Driver\SQLSrv\Driver', + ); + + /** Private constructor. This class cannot be instantiated. */ + private function __construct() { } + + /** + * Creates a connection object based on the specified parameters. + * This method returns a Doctrine\DBAL\Connection which wraps the underlying + * driver connection. + * + * $params must contain at least one of the following. + * + * Either 'driver' with one of the following values: + * + * pdo_mysql + * pdo_sqlite + * pdo_pgsql + * pdo_oci (unstable) + * pdo_sqlsrv + * pdo_ibm (unstable) + * pdo_sqlsrv + * mysqli + * sqlsrv + * ibm_db2 (unstable) + * drizzle_pdo_mysql + * + * OR 'driverClass' that contains the full class name (with namespace) of the + * driver class to instantiate. + * + * Other (optional) parameters: + * + * user (string): + * The username to use when connecting. + * + * password (string): + * The password to use when connecting. + * + * driverOptions (array): + * Any additional driver-specific options for the driver. These are just passed + * through to the driver. + * + * pdo: + * You can pass an existing PDO instance through this parameter. The PDO + * instance will be wrapped in a Doctrine\DBAL\Connection. + * + * wrapperClass: + * You may specify a custom wrapper class through the 'wrapperClass' + * parameter but this class MUST inherit from Doctrine\DBAL\Connection. + * + * driverClass: + * The driver class to use. + * + * @param array $params The parameters. + * @param \Doctrine\DBAL\Configuration The configuration to use. + * @param \Doctrine\Common\EventManager The event manager to use. + * @return \Doctrine\DBAL\Connection + */ + public static function getConnection( + array $params, + Configuration $config = null, + EventManager $eventManager = null) + { + // create default config and event manager, if not set + if ( ! $config) { + $config = new Configuration(); + } + if ( ! $eventManager) { + $eventManager = new EventManager(); + } + + // check for existing pdo object + if (isset($params['pdo']) && ! $params['pdo'] instanceof \PDO) { + throw DBALException::invalidPdoInstance(); + } else if (isset($params['pdo'])) { + $params['pdo']->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + $params['driver'] = 'pdo_' . $params['pdo']->getAttribute(\PDO::ATTR_DRIVER_NAME); + } else { + self::_checkParams($params); + } + if (isset($params['driverClass'])) { + $className = $params['driverClass']; + } else { + $className = self::$_driverMap[$params['driver']]; + } + + $driver = new $className(); + + $wrapperClass = 'Doctrine\DBAL\Connection'; + if (isset($params['wrapperClass'])) { + if (is_subclass_of($params['wrapperClass'], $wrapperClass)) { + $wrapperClass = $params['wrapperClass']; + } else { + throw DBALException::invalidWrapperClass($params['wrapperClass']); + } + } + + return new $wrapperClass($params, $driver, $config, $eventManager); + } + + /** + * Checks the list of parameters. + * + * @param array $params + */ + private static function _checkParams(array $params) + { + // check existance of mandatory parameters + + // driver + if ( ! isset($params['driver']) && ! isset($params['driverClass'])) { + throw DBALException::driverRequired(); + } + + // check validity of parameters + + // driver + if ( isset($params['driver']) && ! isset(self::$_driverMap[$params['driver']])) { + throw DBALException::unknownDriver($params['driver'], array_keys(self::$_driverMap)); + } + + if (isset($params['driverClass']) && ! in_array('Doctrine\DBAL\Driver', class_implements($params['driverClass'], true))) { + throw DBALException::invalidDriverClass($params['driverClass']); + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php new file mode 100644 index 0000000..f4cb1cd --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php @@ -0,0 +1,79 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\Common\EventArgs, + Doctrine\DBAL\Connection; + +/** + * Event Arguments used when a Driver connection is established inside Doctrine\DBAL\Connection. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class ConnectionEventArgs extends EventArgs +{ + /** + * @var Connection + */ + private $_connection = null; + + public function __construct(Connection $connection) + { + $this->_connection = $connection; + } + + /** + * @return \Doctrine\DBAL\Connection + */ + public function getConnection() + { + return $this->_connection; + } + + /** + * @return \Doctrine\DBAL\Driver + */ + public function getDriver() + { + return $this->_connection->getDriver(); + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getDatabasePlatform() + { + return $this->_connection->getDatabasePlatform(); + } + + /** + * @return \Doctrine\DBAL\Schema\AbstractSchemaManager + */ + public function getSchemaManager() + { + return $this->_connection->getSchemaManager(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php new file mode 100644 index 0000000..fc22744 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php @@ -0,0 +1,74 @@ +. +*/ + +namespace Doctrine\DBAL\Event\Listeners; + +use Doctrine\DBAL\Event\ConnectionEventArgs; +use Doctrine\DBAL\Events; +use Doctrine\Common\EventSubscriber; + +/** + * MySQL Session Init Event Subscriber which allows to set the Client Encoding of the Connection + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @deprecated Use "charset" option to PDO MySQL Connection instead. + */ +class MysqlSessionInit implements EventSubscriber +{ + /** + * @var string + */ + private $_charset; + + /** + * @var string + */ + private $_collation; + + /** + * Configure Charset and Collation options of MySQL Client for each Connection + * + * @param string $charset + * @param string $collation + */ + public function __construct($charset = 'utf8', $collation = false) + { + $this->_charset = $charset; + $this->_collation = $collation; + } + + /** + * @param ConnectionEventArgs $args + * @return void + */ + public function postConnect(ConnectionEventArgs $args) + { + $collation = ($this->_collation) ? " COLLATE ".$this->_collation : ""; + $args->getConnection()->executeUpdate("SET NAMES ".$this->_charset . $collation); + } + + public function getSubscribedEvents() + { + return array(Events::postConnect); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php new file mode 100644 index 0000000..8355403 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php @@ -0,0 +1,80 @@ +. +*/ + +namespace Doctrine\DBAL\Event\Listeners; + +use Doctrine\DBAL\Event\ConnectionEventArgs; +use Doctrine\DBAL\Events; +use Doctrine\Common\EventSubscriber; + +/** + * Should be used when Oracle Server default enviroment does not match the Doctrine requirements. + * + * The following enviroment variables are required for the Doctrine default date format: + * + * NLS_TIME_FORMAT="HH24:MI:SS" + * NLS_DATE_FORMAT="YYYY-MM-DD HH24:MI:SS" + * NLS_TIMESTAMP_FORMAT="YYYY-MM-DD HH24:MI:SS" + * NLS_TIMESTAMP_TZ_FORMAT="YYYY-MM-DD HH24:MI:SS TZH:TZM" + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + */ +class OracleSessionInit implements EventSubscriber +{ + protected $_defaultSessionVars = array( + 'NLS_TIME_FORMAT' => "HH24:MI:SS", + 'NLS_DATE_FORMAT' => "YYYY-MM-DD HH24:MI:SS", + 'NLS_TIMESTAMP_FORMAT' => "YYYY-MM-DD HH24:MI:SS", + 'NLS_TIMESTAMP_TZ_FORMAT' => "YYYY-MM-DD HH24:MI:SS TZH:TZM", + 'NLS_NUMERIC_CHARACTERS' => ".,", + ); + + /** + * @param array $oracleSessionVars + */ + public function __construct(array $oracleSessionVars = array()) + { + $this->_defaultSessionVars = array_merge($this->_defaultSessionVars, $oracleSessionVars); + } + + /** + * @param ConnectionEventArgs $args + * @return void + */ + public function postConnect(ConnectionEventArgs $args) + { + if (count($this->_defaultSessionVars)) { + array_change_key_case($this->_defaultSessionVars, \CASE_UPPER); + $vars = array(); + foreach ($this->_defaultSessionVars as $option => $value) { + $vars[] = $option." = '".$value."'"; + } + $sql = "ALTER SESSION SET ".implode(" ", $vars); + $args->getConnection()->executeUpdate($sql); + } + } + + public function getSubscribedEvents() + { + return array(Events::postConnect); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php new file mode 100644 index 0000000..8dfde62 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php @@ -0,0 +1,63 @@ +. +*/ + +namespace Doctrine\DBAL\Event\Listeners; + +use Doctrine\DBAL\Event\ConnectionEventArgs; +use Doctrine\DBAL\Events; +use Doctrine\Common\EventSubscriber; + +/** + * Session init listener for executing a single SQL statement right after a connection is opened. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Benjamin Eberlei + */ +class SQLSessionInit implements EventSubscriber +{ + /** + * @var string + */ + protected $sql; + + /** + * @param string $sql + */ + public function __construct($sql) + { + $this->sql = $sql; + } + + /** + * @param ConnectionEventArgs $args + * @return void + */ + public function postConnect(ConnectionEventArgs $args) + { + $conn = $args->getConnection(); + $conn->exec($this->sql); + } + + public function getSubscribedEvents() + { + return array(Events::postConnect); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php new file mode 100644 index 0000000..0200ce7 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php @@ -0,0 +1,114 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\TableDiff; + +/** + * Event Arguments used when SQL queries for adding table columns are generated inside Doctrine\DBAL\Platform\*Platform. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaAlterTableAddColumnEventArgs extends SchemaEventArgs +{ + /** + * @var \Doctrine\DBAL\Schema\Column + */ + private $_column = null; + + /** + * @var \Doctrine\DBAL\Schema\TableDiff + */ + private $_tableDiff = null; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $_platform = null; + + /** + * @var array + */ + private $_sql = array(); + + /** + * @param \Doctrine\DBAL\Schema\Column $column + * @param \Doctrine\DBAL\Schema\TableDiff $tableDiff + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function __construct(Column $column, TableDiff $tableDiff, AbstractPlatform $platform) + { + $this->_column = $column; + $this->_tableDiff = $tableDiff; + $this->_platform = $platform; + } + + /** + * @return \Doctrine\DBAL\Schema\Column + */ + public function getColumn() + { + return $this->_column; + } + + /** + * @return \Doctrine\DBAL\Schema\TableDiff + */ + public function getTableDiff() + { + return $this->_tableDiff; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getPlatform() + { + return $this->_platform; + } + + /** + * @param string|array $sql + * @return \Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs + */ + public function addSql($sql) + { + if (is_array($sql)) { + $this->_sql = array_merge($this->_sql, $sql); + } else { + $this->_sql[] = $sql; + } + + return $this; + } + + /** + * @return array + */ + public function getSql() + { + return $this->_sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php new file mode 100644 index 0000000..bd59d7d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php @@ -0,0 +1,114 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\ColumnDiff, + Doctrine\DBAL\Schema\TableDiff; + +/** + * Event Arguments used when SQL queries for changing table columns are generated inside Doctrine\DBAL\Platform\*Platform. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaAlterTableChangeColumnEventArgs extends SchemaEventArgs +{ + /** + * @var \Doctrine\DBAL\Schema\ColumnDiff + */ + private $_columnDiff = null; + + /** + * @var \Doctrine\DBAL\Schema\TableDiff + */ + private $_tableDiff = null; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $_platform = null; + + /** + * @var array + */ + private $_sql = array(); + + /** + * @param \Doctrine\DBAL\Schema\ColumnDiff $columnDiff + * @param \Doctrine\DBAL\Schema\TableDiff $tableDiff + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function __construct(ColumnDiff $columnDiff, TableDiff $tableDiff, AbstractPlatform $platform) + { + $this->_columnDiff = $columnDiff; + $this->_tableDiff = $tableDiff; + $this->_platform = $platform; + } + + /** + * @return \Doctrine\DBAL\Schema\ColumnDiff + */ + public function getColumnDiff() + { + return $this->_columnDiff; + } + + /** + * @return \Doctrine\DBAL\Schema\TableDiff + */ + public function getTableDiff() + { + return $this->_tableDiff; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getPlatform() + { + return $this->_platform; + } + + /** + * @param string|array $sql + * @return \Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs + */ + public function addSql($sql) + { + if (is_array($sql)) { + $this->_sql = array_merge($this->_sql, $sql); + } else { + $this->_sql[] = $sql; + } + + return $this; + } + + /** + * @return array + */ + public function getSql() + { + return $this->_sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php new file mode 100644 index 0000000..9f85338 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php @@ -0,0 +1,99 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\TableDiff; + +/** + * Event Arguments used when SQL queries for creating tables are generated inside Doctrine\DBAL\Platform\*Platform. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaAlterTableEventArgs extends SchemaEventArgs +{ + /** + * @var \Doctrine\DBAL\Schema\TableDiff + */ + private $_tableDiff = null; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $_platform = null; + + /** + * @var array + */ + private $_sql = array(); + + /** + * @param \Doctrine\DBAL\Schema\TableDiff $tableDiff + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function __construct(TableDiff $tableDiff, AbstractPlatform $platform) + { + $this->_tableDiff = $tableDiff; + $this->_platform = $platform; + } + + /** + * @return \Doctrine\DBAL\Schema\TableDiff + */ + public function getTableDiff() + { + return $this->_tableDiff; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getPlatform() + { + return $this->_platform; + } + + /** + * @param string|array $sql + * @return \Doctrine\DBAL\Event\SchemaAlterTableEventArgs + */ + public function addSql($sql) + { + if (is_array($sql)) { + $this->_sql = array_merge($this->_sql, $sql); + } else { + $this->_sql[] = $sql; + } + + return $this; + } + + /** + * @return array + */ + public function getSql() + { + return $this->_sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php new file mode 100644 index 0000000..4b981f8 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php @@ -0,0 +1,114 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\TableDiff; + +/** + * Event Arguments used when SQL queries for removing table columns are generated inside Doctrine\DBAL\Platform\*Platform. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaAlterTableRemoveColumnEventArgs extends SchemaEventArgs +{ + /** + * @var \Doctrine\DBAL\Schema\Column + */ + private $_column = null; + + /** + * @var \Doctrine\DBAL\Schema\TableDiff + */ + private $_tableDiff = null; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $_platform = null; + + /** + * @var array + */ + private $_sql = array(); + + /** + * @param \Doctrine\DBAL\Schema\Column $column + * @param \Doctrine\DBAL\Schema\TableDiff $tableDiff + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function __construct(Column $column, TableDiff $tableDiff, AbstractPlatform $platform) + { + $this->_column = $column; + $this->_tableDiff = $tableDiff; + $this->_platform = $platform; + } + + /** + * @return \Doctrine\DBAL\Schema\Column + */ + public function getColumn() + { + return $this->_column; + } + + /** + * @return \Doctrine\DBAL\Schema\TableDiff + */ + public function getTableDiff() + { + return $this->_tableDiff; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getPlatform() + { + return $this->_platform; + } + + /** + * @param string|array $sql + * @return \Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs + */ + public function addSql($sql) + { + if (is_array($sql)) { + $this->_sql = array_merge($this->_sql, $sql); + } else { + $this->_sql[] = $sql; + } + + return $this; + } + + /** + * @return array + */ + public function getSql() + { + return $this->_sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php new file mode 100644 index 0000000..90e6a38 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php @@ -0,0 +1,129 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\TableDiff; + +/** + * Event Arguments used when SQL queries for renaming table columns are generated inside Doctrine\DBAL\Platform\*Platform. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaAlterTableRenameColumnEventArgs extends SchemaEventArgs +{ + /** + * @var string + */ + private $_oldColumnName = null; + + /** + * @var \Doctrine\DBAL\Schema\Column + */ + private $_column = null; + + /** + * @var \Doctrine\DBAL\Schema\TableDiff + */ + private $_tableDiff = null; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $_platform = null; + + /** + * @var array + */ + private $_sql = array(); + + /** + * @param string $oldColumnName + * @param \Doctrine\DBAL\Schema\Column $column + * @param \Doctrine\DBAL\Schema\TableDiff $tableDiff + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function __construct($oldColumnName, Column $column, TableDiff $tableDiff, AbstractPlatform $platform) + { + $this->_oldColumnName = $oldColumnName; + $this->_column = $column; + $this->_tableDiff = $tableDiff; + $this->_platform = $platform; + } + + /** + * @return string + */ + public function getOldColumnName() + { + return $this->_oldColumnName; + } + + /** + * @return \Doctrine\DBAL\Schema\Column + */ + public function getColumn() + { + return $this->_column; + } + + /** + * @return \Doctrine\DBAL\Schema\TableDiff + */ + public function getTableDiff() + { + return $this->_tableDiff; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getPlatform() + { + return $this->_platform; + } + + /** + * @param string|array $sql + * @return \Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs + */ + public function addSql($sql) + { + if (is_array($sql)) { + $this->_sql = array_merge($this->_sql, $sql); + } else { + $this->_sql[] = $sql; + } + + return $this; + } + + /** + * @return array + */ + public function getSql() + { + return $this->_sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php new file mode 100644 index 0000000..fecb015 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php @@ -0,0 +1,137 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Connection, + Doctrine\DBAL\Schema\Column; + +/** + * Event Arguments used when the portable column definition is generated inside Doctrine\DBAL\Schema\AbstractSchemaManager. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaColumnDefinitionEventArgs extends SchemaEventArgs +{ + /** + * @var \Doctrine\DBAL\Schema\Column + */ + private $_column = null; + + /** + * Raw column data as fetched from the database + * + * @var array + */ + private $_tableColumn = null; + + /** + * @var string + */ + private $_table = null; + + /** + * @var string + */ + private $_database = null; + + /** + * @var \Doctrine\DBAL\Connection + */ + private $_connection = null; + + /** + * @param array $tableColumn + * @param string $table + * @param string $database + * @param \Doctrine\DBAL\Connection $conn + */ + public function __construct(array $tableColumn, $table, $database, Connection $connection) + { + $this->_tableColumn = $tableColumn; + $this->_table = $table; + $this->_database = $database; + $this->_connection = $connection; + } + + /** + * Allows to clear the column which means the column will be excluded from + * tables column list. + * + * @param null|\Doctrine\DBAL\Schema\Column $column + * @return SchemaColumnDefinitionEventArgs + */ + public function setColumn(Column $column = null) + { + $this->_column = $column; + + return $this; + } + + /** + * @return \Doctrine\DBAL\Schema\Column + */ + public function getColumn() + { + return $this->_column; + } + + /** + * @return array + */ + public function getTableColumn() + { + return $this->_tableColumn; + } + + /** + * @return string + */ + public function getTable() + { + return $this->_table; + } + + /** + * @return string + */ + public function getDatabase() + { + return $this->_database; + } + + /** + * @return \Doctrine\DBAL\Connection + */ + public function getConnection() + { + return $this->_connection; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getDatabasePlatform() + { + return $this->_connection->getDatabasePlatform(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php new file mode 100644 index 0000000..5e7383c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php @@ -0,0 +1,114 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\Table; + +/** + * Event Arguments used when SQL queries for creating table columns are generated inside Doctrine\DBAL\Platform\AbstractPlatform. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaCreateTableColumnEventArgs extends SchemaEventArgs +{ + /** + * @var \Doctrine\DBAL\Schema\Column + */ + private $_column = null; + + /** + * @var \Doctrine\DBAL\Schema\Table + */ + private $_table = null; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $_platform = null; + + /** + * @var array + */ + private $_sql = array(); + + /** + * @param \Doctrine\DBAL\Schema\Column $column + * @param \Doctrine\DBAL\Schema\Table $table + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function __construct(Column $column, Table $table, AbstractPlatform $platform) + { + $this->_column = $column; + $this->_table = $table; + $this->_platform = $platform; + } + + /** + * @return \Doctrine\DBAL\Schema\Column + */ + public function getColumn() + { + return $this->_column; + } + + /** + * @return \Doctrine\DBAL\Schema\Table + */ + public function getTable() + { + return $this->_table; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getPlatform() + { + return $this->_platform; + } + + /** + * @param string|array $sql + * @return \Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs + */ + public function addSql($sql) + { + if (is_array($sql)) { + $this->_sql = array_merge($this->_sql, $sql); + } else { + $this->_sql[] = $sql; + } + + return $this; + } + + /** + * @return array + */ + public function getSql() + { + return $this->_sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php new file mode 100644 index 0000000..3149faa --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php @@ -0,0 +1,128 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Table; + +/** + * Event Arguments used when SQL queries for creating tables are generated inside Doctrine\DBAL\Platform\AbstractPlatform. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaCreateTableEventArgs extends SchemaEventArgs +{ + /** + * @var \Doctrine\DBAL\Schema\Table + */ + private $_table = null; + + /** + * @var array + */ + private $_columns = null; + + /** + * @var array + */ + private $_options = null; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $_platform = null; + + /** + * @var array + */ + private $_sql = array(); + + /** + * @param \Doctrine\DBAL\Schema\Table $table + * @param array $columns + * @param array $options + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function __construct(Table $table, array $columns, array $options, AbstractPlatform $platform) + { + $this->_table = $table; + $this->_columns = $columns; + $this->_options = $options; + $this->_platform = $platform; + } + + /** + * @return \Doctrine\DBAL\Schema\Table + */ + public function getTable() + { + return $this->_table; + } + + /** + * @return array + */ + public function getColumns() + { + return $this->_columns; + } + + /** + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getPlatform() + { + return $this->_platform; + } + + /** + * @param string|array $sql + * @return \Doctrine\DBAL\Event\SchemaCreateTableEventArgs + */ + public function addSql($sql) + { + if (is_array($sql)) { + $this->_sql = array_merge($this->_sql, $sql); + } else { + $this->_sql[] = $sql; + } + + return $this; + } + + /** + * @return array + */ + public function getSql() + { + return $this->_sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php new file mode 100644 index 0000000..55133be --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php @@ -0,0 +1,98 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Table; + +/** + * Event Arguments used when the SQL query for dropping tables are generated inside Doctrine\DBAL\Platform\AbstractPlatform. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaDropTableEventArgs extends SchemaEventArgs +{ + /** + * @var string|\Doctrine\DBAL\Schema\Table + */ + private $_table = null; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $_platform = null; + + /** + * @var string + */ + private $_sql = null; + + /** + * @param string|\Doctrine\DBAL\Schema\Table $table + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function __construct($table, AbstractPlatform $platform) + { + if ( ! $table instanceof Table && !is_string($table)) { + throw new \InvalidArgumentException('SchemaCreateTableEventArgs expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); + } + + $this->_table = $table; + $this->_platform = $platform; + } + + /** + * @return string|\Doctrine\DBAL\Schema\Table + */ + public function getTable() + { + return $this->_table; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getPlatform() + { + return $this->_platform; + } + + /** + * @param string $sql + * @return \Doctrine\DBAL\Event\SchemaDropTableEventArgs + */ + public function setSql($sql) + { + $this->_sql = $sql; + + return $this; + } + + /** + * @return string + */ + public function getSql() + { + return $this->_sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaEventArgs.php new file mode 100644 index 0000000..a3509fb --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaEventArgs.php @@ -0,0 +1,56 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\Common\EventArgs; + +/** + * Base class for schema related events. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaEventArgs extends EventArgs +{ + /** + * @var boolean + */ + private $_preventDefault = false; + + /** + * @return \Doctrine\DBAL\Event\SchemaEventArgs + */ + public function preventDefault() + { + $this->_preventDefault = true; + + return $this; + } + + /** + * @return boolean + */ + public function isDefaultPrevented() + { + return $this->_preventDefault; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php new file mode 100644 index 0000000..248d43e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php @@ -0,0 +1,122 @@ +. +*/ + +namespace Doctrine\DBAL\Event; + +use Doctrine\DBAL\Connection, + Doctrine\DBAL\Schema\Index; + +/** + * Event Arguments used when the portable index definition is generated inside Doctrine\DBAL\Schema\AbstractSchemaManager. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Jan Sorgalla + */ +class SchemaIndexDefinitionEventArgs extends SchemaEventArgs +{ + /** + * @var \Doctrine\DBAL\Schema\Index + */ + private $_index = null; + + /** + * Raw index data as fetched from the database + * + * @var array + */ + private $_tableIndex = null; + + /** + * @var string + */ + private $_table = null; + + /** + * @var \Doctrine\DBAL\Connection + */ + private $_connection = null; + + /** + * @param array $tableIndex + * @param string $table + * @param \Doctrine\DBAL\Connection $conn + */ + public function __construct(array $tableIndex, $table, Connection $connection) + { + $this->_tableIndex = $tableIndex; + $this->_table = $table; + $this->_connection = $connection; + } + + /** + * Allows to clear the index which means the index will be excluded from + * tables index list. + * + * @param null|\Doctrine\DBAL\Schema\Index $index + * @return SchemaIndexDefinitionEventArgs + */ + public function setIndex(Index $index = null) + { + $this->_index = $index; + + return $this; + } + + /** + * @return \Doctrine\DBAL\Schema\Index + */ + public function getIndex() + { + return $this->_index; + } + + /** + * @return array + */ + public function getTableIndex() + { + return $this->_tableIndex; + } + + /** + * @return string + */ + public function getTable() + { + return $this->_table; + } + + /** + * @return \Doctrine\DBAL\Connection + */ + public function getConnection() + { + return $this->_connection; + } + + /** + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getDatabasePlatform() + { + return $this->_connection->getDatabasePlatform(); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Events.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Events.php new file mode 100644 index 0000000..0869dd9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Events.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\DBAL; + +/** + * Container for all DBAL events. + * + * This class cannot be instantiated. + * + * @author Roman Borschel + * @since 2.0 + */ +final class Events +{ + private function __construct() {} + + const postConnect = 'postConnect'; + + const onSchemaCreateTable = 'onSchemaCreateTable'; + const onSchemaCreateTableColumn = 'onSchemaCreateTableColumn'; + const onSchemaDropTable = 'onSchemaDropTable'; + const onSchemaAlterTable = 'onSchemaAlterTable'; + const onSchemaAlterTableAddColumn = 'onSchemaAlterTableAddColumn'; + const onSchemaAlterTableRemoveColumn = 'onSchemaAlterTableRemoveColumn'; + const onSchemaAlterTableChangeColumn = 'onSchemaAlterTableChangeColumn'; + const onSchemaAlterTableRenameColumn = 'onSchemaAlterTableRenameColumn'; + const onSchemaColumnDefinition = 'onSchemaColumnDefinition'; + const onSchemaIndexDefinition = 'onSchemaIndexDefinition'; +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGenerator.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGenerator.php new file mode 100644 index 0000000..c52a40b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGenerator.php @@ -0,0 +1,160 @@ +. + */ + +namespace Doctrine\DBAL\Id; + +use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Connection; + +/** + * Table ID Generator for those poor languages that are missing sequences. + * + * WARNING: The Table Id Generator clones a second independent database + * connection to work correctly. This means using the generator requests that + * generate IDs will have two open database connections. This is necessary to + * be safe from transaction failures in the main connection. Make sure to only + * ever use one TableGenerator otherwise you end up with many connections. + * + * TableID Generator does not work with SQLite. + * + * The TableGenerator does not take care of creating the SQL Table itself. You + * should look at the `TableGeneratorSchemaVisitor` to do this for you. + * Otherwise the schema for a table looks like: + * + * CREATE sequences ( + * sequence_name VARCHAR(255) NOT NULL, + * sequence_value INT NOT NULL DEFAULT '1', + * sequence_increment_by INT NOT NULL DEFAULT '1', + * PRIMARY KEY (table_name) + * ); + * + * Technically this generator works as follows: + * + * 1. Use a robust transaction serialization level. + * 2. Open transaction + * 3. Acquire a read lock on the table row (SELECT .. FOR UPDATE) + * 4. Increment current value by one and write back to database + * 5. Commit transaction + * + * If you are using a sequence_increment_by value that is larger than one the + * ID Generator will keep incrementing values until it hits the incrementation + * gap before issuing another query. + * + * If no row is present for a given sequence a new one will be created with the + * default values 'value' = 1 and 'increment_by' = 1 + * + * @author Benjamin Eberlei + */ +class TableGenerator +{ + /** + * @var \Doctrine\DBAL\Connection + */ + private $conn; + + /** + * @var string + */ + private $generatorTableName; + + /** + * @var array + */ + private $sequences = array(); + + /** + * @param Connection $conn + * @param string $generatorTableName + */ + public function __construct(Connection $conn, $generatorTableName = 'sequences') + { + $params = $conn->getParams(); + if ($params['driver'] == 'pdo_sqlite') { + throw new \Doctrine\DBAL\DBALException("Cannot use TableGenerator with SQLite."); + } + $this->conn = DriverManager::getConnection($params, $conn->getConfiguration(), $conn->getEventManager()); + $this->generatorTableName = $generatorTableName; + } + + /** + * Generate the next unused value for the given sequence name + * + * @param string + * @return int + */ + public function nextValue($sequenceName) + { + if (isset($this->sequences[$sequenceName])) { + $value = $this->sequences[$sequenceName]['value']; + $this->sequences[$sequenceName]['value']++; + if ($this->sequences[$sequenceName]['value'] >= $this->sequences[$sequenceName]['max']) { + unset ($this->sequences[$sequenceName]); + } + return $value; + } + + $this->conn->beginTransaction(); + + try { + $platform = $this->conn->getDatabasePlatform(); + $sql = "SELECT sequence_value, sequence_increment_by " . + "FROM " . $platform->appendLockHint($this->generatorTableName, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) . " " . + "WHERE sequence_name = ? " . $platform->getWriteLockSQL(); + $stmt = $this->conn->executeQuery($sql, array($sequenceName)); + + if ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + $row = array_change_key_case($row, CASE_LOWER); + + $value = $row['sequence_value']; + $value++; + + if ($row['sequence_increment_by'] > 1) { + $this->sequences[$sequenceName] = array( + 'value' => $value, + 'max' => $row['sequence_value'] + $row['sequence_increment_by'] + ); + } + + $sql = "UPDATE " . $this->generatorTableName . " ". + "SET sequence_value = sequence_value + sequence_increment_by " . + "WHERE sequence_name = ? AND sequence_value = ?"; + $rows = $this->conn->executeUpdate($sql, array($sequenceName, $row['sequence_value'])); + + if ($rows != 1) { + throw new \Doctrine\DBAL\DBALException("Race-condition detected while updating sequence. Aborting generation"); + } + } else { + $this->conn->insert( + $this->generatorTableName, + array('sequence_name' => $sequenceName, 'sequence_value' => 1, 'sequence_increment_by' => 1) + ); + $value = 1; + } + + $this->conn->commit(); + + } catch(\Exception $e) { + $this->conn->rollback(); + throw new \Doctrine\DBAL\DBALException("Error occured while generating ID with TableGenerator, aborted generation: " . $e->getMessage(), 0, $e); + } + + return $value; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php new file mode 100644 index 0000000..e340397 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php @@ -0,0 +1,90 @@ +. + */ + +namespace Doctrine\DBAL\Id; + +use Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Schema, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\ForeignKeyConstraint, + Doctrine\DBAL\Schema\Constraint, + Doctrine\DBAL\Schema\Sequence, + Doctrine\DBAL\Schema\Index; + +class TableGeneratorSchemaVisitor implements \Doctrine\DBAL\Schema\Visitor\Visitor +{ + /** + * @var string + */ + private $generatorTableName; + + public function __construct($generatorTableName = 'sequences') + { + $this->generatorTableName = $generatorTableName; + } + + /** + * @param Schema $schema + */ + public function acceptSchema(Schema $schema) + { + $table = $schema->createTable($this->generatorTableName); + $table->addColumn('sequence_name', 'string'); + $table->addColumn('sequence_value', 'integer', array('default' => 1)); + $table->addColumn('sequence_increment_by', 'integer', array('default' => 1)); + } + + /** + * @param Table $table + */ + public function acceptTable(Table $table) + { + } + + /** + * @param Column $column + */ + public function acceptColumn(Table $table, Column $column) + { + } + + /** + * @param Table $localTable + * @param ForeignKeyConstraint $fkConstraint + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + } + + /** + * @param Table $table + * @param Index $index + */ + public function acceptIndex(Table $table, Index $index) + { + } + + /** + * @param Sequence $sequence + */ + public function acceptSequence(Sequence $sequence) + { + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/LockMode.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/LockMode.php new file mode 100644 index 0000000..52d87d2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/LockMode.php @@ -0,0 +1,42 @@ +. +*/ + +namespace Doctrine\DBAL; + +/** + * Contains all DBAL LockModes + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Roman Borschel + */ +class LockMode +{ + const NONE = 0; + const OPTIMISTIC = 1; + const PESSIMISTIC_READ = 2; + const PESSIMISTIC_WRITE = 4; + + final private function __construct() { } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php new file mode 100644 index 0000000..7d70b90 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/DebugStack.php @@ -0,0 +1,69 @@ +. + */ + +namespace Doctrine\DBAL\Logging; + +/** + * Includes executed SQLs in a Debug Stack + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class DebugStack implements SQLLogger +{ + /** @var array $queries Executed SQL queries. */ + public $queries = array(); + + /** @var boolean $enabled If Debug Stack is enabled (log queries) or not. */ + public $enabled = true; + + public $start = null; + + public $currentQuery = 0; + + /** + * {@inheritdoc} + */ + public function startQuery($sql, array $params = null, array $types = null) + { + if ($this->enabled) { + $this->start = microtime(true); + $this->queries[++$this->currentQuery] = array('sql' => $sql, 'params' => $params, 'types' => $types, 'executionMS' => 0); + } + } + + /** + * {@inheritdoc} + */ + public function stopQuery() + { + if ($this->enabled) { + $this->queries[$this->currentQuery]['executionMS'] = microtime(true) - $this->start; + } + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php new file mode 100644 index 0000000..a332258 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php @@ -0,0 +1,61 @@ +. + */ + +namespace Doctrine\DBAL\Logging; + +/** + * A SQL logger that logs to the standard output using echo/var_dump. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EchoSQLLogger implements SQLLogger +{ + /** + * {@inheritdoc} + */ + public function startQuery($sql, array $params = null, array $types = null) + { + echo $sql . PHP_EOL; + + if ($params) { + var_dump($params); + } + + if ($types) { + var_dump($types); + } + } + + /** + * {@inheritdoc} + */ + public function stopQuery() + { + + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/LoggerChain.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/LoggerChain.php new file mode 100644 index 0000000..6725cc5 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/LoggerChain.php @@ -0,0 +1,64 @@ +. + */ + +namespace Doctrine\DBAL\Logging; + +/** + * Chains multiple SQLLogger + * + * + * @link www.doctrine-project.org + * @since 2.2 + * @author Christophe Coevoet + */ +class LoggerChain implements SQLLogger +{ + private $loggers = array(); + + /** + * Adds a logger in the chain + * + * @param SQLLogger $logger + */ + public function addLogger(SQLLogger $logger) + { + $this->loggers[] = $logger; + } + + /** + * {@inheritdoc} + */ + public function startQuery($sql, array $params = null, array $types = null) + { + foreach ($this->loggers as $logger) { + $logger->startQuery($sql, $params, $types); + } + } + + /** + * {@inheritdoc} + */ + public function stopQuery() + { + foreach ($this->loggers as $logger) { + $logger->stopQuery(); + } + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/SQLLogger.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/SQLLogger.php new file mode 100644 index 0000000..9564f4c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Logging/SQLLogger.php @@ -0,0 +1,54 @@ +. + */ + +namespace Doctrine\DBAL\Logging; + +/** + * Interface for SQL loggers. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +interface SQLLogger +{ + /** + * Logs a SQL statement somewhere. + * + * @param string $sql The SQL to be executed. + * @param array $params The SQL parameters. + * @param array $types The SQL parameter types. + * @return void + */ + public function startQuery($sql, array $params = null, array $types = null); + + /** + * Mark the last started query as stopped. This can be used for timing of queries. + * + * @return void + */ + public function stopQuery(); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php new file mode 100644 index 0000000..b983c4a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -0,0 +1,2854 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\DBALException, + Doctrine\DBAL\Connection, + Doctrine\DBAL\Types, + Doctrine\DBAL\Schema\Constraint, + Doctrine\DBAL\Schema\Sequence, + Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Index, + Doctrine\DBAL\Schema\ForeignKeyConstraint, + Doctrine\DBAL\Schema\TableDiff, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\ColumnDiff, + Doctrine\DBAL\Types\Type, + Doctrine\DBAL\Events, + Doctrine\Common\EventManager, + Doctrine\DBAL\Event\SchemaCreateTableEventArgs, + Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs, + Doctrine\DBAL\Event\SchemaDropTableEventArgs, + Doctrine\DBAL\Event\SchemaAlterTableEventArgs, + Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs, + Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs, + Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs, + Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs; + +/** + * Base class for all DatabasePlatforms. The DatabasePlatforms are the central + * point of abstraction of platform-specific behaviors, features and SQL dialects. + * They are a passive source of information. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Lukas Smith (PEAR MDB2 library) + * @author Benjamin Eberlei + * @todo Remove any unnecessary methods. + */ +abstract class AbstractPlatform +{ + /** + * @var integer + */ + const CREATE_INDEXES = 1; + + /** + * @var integer + */ + const CREATE_FOREIGNKEYS = 2; + + /** + * @var integer + */ + const TRIM_UNSPECIFIED = 0; + + /** + * @var integer + */ + const TRIM_LEADING = 1; + + /** + * @var integer + */ + const TRIM_TRAILING = 2; + + /** + * @var integer + */ + const TRIM_BOTH = 3; + + /** + * @var array + */ + protected $doctrineTypeMapping = null; + + /** + * Contains a list of all columns that should generate parseable column comments for type-detection + * in reverse engineering scenarios. + * + * @var array + */ + protected $doctrineTypeComments = null; + + /** + * @var Doctrine\Common\EventManager + */ + protected $_eventManager; + + /** + * Holds the KeywordList instance for the current platform. + * + * @var \Doctrine\DBAL\Platforms\Keywords\KeywordList + */ + protected $_keywords; + + /** + * Constructor. + */ + public function __construct() {} + + /** + * Sets the EventManager used by the Platform. + * + * @param \Doctrine\Common\EventManager + */ + public function setEventManager(EventManager $eventManager) + { + $this->_eventManager = $eventManager; + } + + /** + * Gets the EventManager used by the Platform. + * + * @return \Doctrine\Common\EventManager + */ + public function getEventManager() + { + return $this->_eventManager; + } + + /** + * Gets the SQL snippet that declares a boolean column. + * + * @param array $columnDef + * + * @return string + */ + abstract public function getBooleanTypeDeclarationSQL(array $columnDef); + + /** + * Gets the SQL snippet that declares a 4 byte integer column. + * + * @param array $columnDef + * + * @return string + */ + abstract public function getIntegerTypeDeclarationSQL(array $columnDef); + + /** + * Gets the SQL snippet that declares an 8 byte integer column. + * + * @param array $columnDef + * + * @return string + */ + abstract public function getBigIntTypeDeclarationSQL(array $columnDef); + + /** + * Gets the SQL snippet that declares a 2 byte integer column. + * + * @param array $columnDef + * + * @return string + */ + abstract public function getSmallIntTypeDeclarationSQL(array $columnDef); + + /** + * Gets the SQL snippet that declares common properties of an integer column. + * + * @param array $columnDef + * @return string + */ + abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef); + + /** + * Lazy load Doctrine Type Mappings + * + * @return void + */ + abstract protected function initializeDoctrineTypeMappings(); + + /** + * Initialize Doctrine Type Mappings with the platform defaults + * and with all additional type mappings. + */ + private function initializeAllDoctrineTypeMappings() + { + $this->initializeDoctrineTypeMappings(); + + foreach (Type::getTypesMap() as $typeName => $className) { + foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) { + $this->doctrineTypeMapping[$dbType] = $typeName; + } + } + } + + /** + * Gets the SQL snippet used to declare a VARCHAR column type. + * + * @param array $field + * + * @return string + */ + public function getVarcharTypeDeclarationSQL(array $field) + { + if ( !isset($field['length'])) { + $field['length'] = $this->getVarcharDefaultLength(); + } + + $fixed = (isset($field['fixed'])) ? $field['fixed'] : false; + + if ($field['length'] > $this->getVarcharMaxLength()) { + return $this->getClobTypeDeclarationSQL($field); + } + + return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed); + } + + /** + * Get the SQL Snippet to create a GUID/UUID field. + * + * By default this maps directly to a VARCHAR and only maps to more + * special datatypes when the underlying databases support this datatype. + * + * @param array $field + * + * @return string + */ + public function getGuidTypeDeclarationSQL(array $field) + { + return $this->getVarcharTypeDeclarationSQL($field); + } + + /** + * @param integer $length + * @param boolean $fixed + * + * @return string + * + * @throws \Doctrine\DBAL\DBALException + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + throw DBALException::notSupported('VARCHARs not supported by Platform.'); + } + + /** + * Gets the SQL snippet used to declare a CLOB column type. + * + * @param array $field + * + * @return string + */ + abstract public function getClobTypeDeclarationSQL(array $field); + + /** + * Gets the SQL Snippet used to declare a BLOB column type. + * + * @param array $field + * + * @return string + */ + abstract public function getBlobTypeDeclarationSQL(array $field); + + /** + * Gets the name of the platform. + * + * @return string + */ + abstract public function getName(); + + /** + * Register a doctrine type to be used in conjunction with a column type of this platform. + * + * @param string $dbType + * @param string $doctrineType + * + * @throws \Doctrine\DBAL\DBALException if the type is not found + */ + public function registerDoctrineTypeMapping($dbType, $doctrineType) + { + if ($this->doctrineTypeMapping === null) { + $this->initializeAllDoctrineTypeMappings(); + } + + if (!Types\Type::hasType($doctrineType)) { + throw DBALException::typeNotFound($doctrineType); + } + + $dbType = strtolower($dbType); + $this->doctrineTypeMapping[$dbType] = $doctrineType; + } + + /** + * Get the Doctrine type that is mapped for the given database column type. + * + * @param string $dbType + * + * @return string + */ + public function getDoctrineTypeMapping($dbType) + { + if ($this->doctrineTypeMapping === null) { + $this->initializeAllDoctrineTypeMappings(); + } + + $dbType = strtolower($dbType); + + if (!isset($this->doctrineTypeMapping[$dbType])) { + throw new \Doctrine\DBAL\DBALException("Unknown database type ".$dbType." requested, " . get_class($this) . " may not support it."); + } + + return $this->doctrineTypeMapping[$dbType]; + } + + /** + * Check if a database type is currently supported by this platform. + * + * @param string $dbType + * + * @return boolean + */ + public function hasDoctrineTypeMappingFor($dbType) + { + if ($this->doctrineTypeMapping === null) { + $this->initializeAllDoctrineTypeMappings(); + } + + $dbType = strtolower($dbType); + return isset($this->doctrineTypeMapping[$dbType]); + } + + /** + * Initialize the Doctrine Type comments instance variable for in_array() checks. + * + * @return void + */ + protected function initializeCommentedDoctrineTypes() + { + $this->doctrineTypeComments = array(); + + foreach (Type::getTypesMap() as $typeName => $className) { + $type = Type::getType($typeName); + + if ($type->requiresSQLCommentHint($this)) { + $this->doctrineTypeComments[] = $typeName; + } + } + } + + /** + * Is it necessary for the platform to add a parsable type comment to allow reverse engineering the given type? + * + * @param Type $doctrineType + * + * @return boolean + */ + public function isCommentedDoctrineType(Type $doctrineType) + { + if ($this->doctrineTypeComments === null) { + $this->initializeCommentedDoctrineTypes(); + } + + return in_array($doctrineType->getName(), $this->doctrineTypeComments); + } + + /** + * Mark this type as to be commented in ALTER TABLE and CREATE TABLE statements. + * + * @param string|Type $doctrineType + * + * @return void + */ + public function markDoctrineTypeCommented($doctrineType) + { + if ($this->doctrineTypeComments === null) { + $this->initializeCommentedDoctrineTypes(); + } + + $this->doctrineTypeComments[] = $doctrineType instanceof Type ? $doctrineType->getName() : $doctrineType; + } + + /** + * Get the comment to append to a column comment that helps parsing this type in reverse engineering. + * + * @param Type $doctrineType + * @return string + */ + public function getDoctrineTypeComment(Type $doctrineType) + { + return '(DC2Type:' . $doctrineType->getName() . ')'; + } + + /** + * Return the comment of a passed column modified by potential doctrine type comment hints. + * + * @param Column $column + * @return string + */ + protected function getColumnComment(Column $column) + { + $comment = $column->getComment(); + + if ($this->isCommentedDoctrineType($column->getType())) { + $comment .= $this->getDoctrineTypeComment($column->getType()); + } + + return $comment; + } + + /** + * Gets the character used for identifier quoting. + * + * @return string + */ + public function getIdentifierQuoteCharacter() + { + return '"'; + } + + /** + * Gets the string portion that starts an SQL comment. + * + * @return string + */ + public function getSqlCommentStartString() + { + return "--"; + } + + /** + * Gets the string portion that ends an SQL comment. + * + * @return string + */ + public function getSqlCommentEndString() + { + return "\n"; + } + + /** + * Gets the maximum length of a varchar field. + * + * @return integer + */ + public function getVarcharMaxLength() + { + return 4000; + } + + /** + * Gets the default length of a varchar field. + * + * @return integer + */ + public function getVarcharDefaultLength() + { + return 255; + } + + /** + * Gets all SQL wildcard characters of the platform. + * + * @return array + */ + public function getWildcards() + { + return array('%', '_'); + } + + /** + * Returns the regular expression operator. + * + * @return string + */ + public function getRegexpExpression() + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Returns global unique identifier + * + * @return string to get global unique identifier + */ + public function getGuidExpression() + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Returns the average value of a column + * + * @param string $column the column to use + * + * @return string generated sql including an AVG aggregate function + */ + public function getAvgExpression($column) + { + return 'AVG(' . $column . ')'; + } + + /** + * Returns the number of rows (without a NULL value) of a column + * + * If a '*' is used instead of a column the number of selected rows + * is returned. + * + * @param string|integer $column the column to use + * + * @return string generated sql including a COUNT aggregate function + */ + public function getCountExpression($column) + { + return 'COUNT(' . $column . ')'; + } + + /** + * Returns the highest value of a column + * + * @param string $column the column to use + * @return string generated sql including a MAX aggregate function + */ + public function getMaxExpression($column) + { + return 'MAX(' . $column . ')'; + } + + /** + * Returns the lowest value of a column + * + * @param string $column the column to use + * @return string + */ + public function getMinExpression($column) + { + return 'MIN(' . $column . ')'; + } + + /** + * Returns the total sum of a column + * + * @param string $column the column to use + * @return string + */ + public function getSumExpression($column) + { + return 'SUM(' . $column . ')'; + } + + // scalar functions + + /** + * Returns the md5 sum of a field. + * + * Note: Not SQL92, but common functionality + * + * @param string $column + * @return string + */ + public function getMd5Expression($column) + { + return 'MD5(' . $column . ')'; + } + + /** + * Returns the length of a text field. + * + * @param string $column + * + * @return string + */ + public function getLengthExpression($column) + { + return 'LENGTH(' . $column . ')'; + } + + /** + * Returns the squared value of a column + * + * @param string $column the column to use + * + * @return string generated sql including an SQRT aggregate function + */ + public function getSqrtExpression($column) + { + return 'SQRT(' . $column . ')'; + } + + /** + * Rounds a numeric field to the number of decimals specified. + * + * @param string $column + * @param integer $decimals + * + * @return string + */ + public function getRoundExpression($column, $decimals = 0) + { + return 'ROUND(' . $column . ', ' . $decimals . ')'; + } + + /** + * Returns the remainder of the division operation + * $expression1 / $expression2. + * + * @param string $expression1 + * @param string $expression2 + * + * @return string + */ + public function getModExpression($expression1, $expression2) + { + return 'MOD(' . $expression1 . ', ' . $expression2 . ')'; + } + + /** + * Trim a string, leading/trailing/both and with a given char which defaults to space. + * + * @param string $str + * @param integer $pos + * @param string $char has to be quoted already + * + * @return string + */ + public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false) + { + $posStr = ''; + $trimChar = ($char != false) ? $char . ' FROM ' : ''; + + switch ($pos) { + case self::TRIM_LEADING: + $posStr = 'LEADING '.$trimChar; + break; + + case self::TRIM_TRAILING: + $posStr = 'TRAILING '.$trimChar; + break; + + case self::TRIM_BOTH: + $posStr = 'BOTH '.$trimChar; + break; + } + + return 'TRIM(' . $posStr . $str . ')'; + } + + /** + * rtrim + * returns the string $str with proceeding space characters removed + * + * @param string $str literal string or column name + * + * @return string + */ + public function getRtrimExpression($str) + { + return 'RTRIM(' . $str . ')'; + } + + /** + * ltrim + * returns the string $str with leading space characters removed + * + * @param string $str literal string or column name + * + * @return string + */ + public function getLtrimExpression($str) + { + return 'LTRIM(' . $str . ')'; + } + + /** + * upper + * Returns the string $str with all characters changed to + * uppercase according to the current character set mapping. + * + * @param string $str literal string or column name + * + * @return string + */ + public function getUpperExpression($str) + { + return 'UPPER(' . $str . ')'; + } + + /** + * lower + * Returns the string $str with all characters changed to + * lowercase according to the current character set mapping. + * + * @param string $str literal string or column name + * + * @return string + */ + public function getLowerExpression($str) + { + return 'LOWER(' . $str . ')'; + } + + /** + * returns the position of the first occurrence of substring $substr in string $str + * + * @param string $str literal string + * @param string $substr literal string to find + * @param integer $startPos position to start at, beginning of string by default + * + * @return string + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Returns the current system date. + * + * @return string + */ + public function getNowExpression() + { + return 'NOW()'; + } + + /** + * return string to call a function to get a substring inside an SQL statement + * + * Note: Not SQL92, but common functionality. + * + * SQLite only supports the 2 parameter variant of this function + * + * @param string $value an sql string literal or column name/alias + * @param integer $from where to start the substring portion + * @param integer $length the substring portion length + * + * @return string + */ + public function getSubstringExpression($value, $from, $length = null) + { + if ($length === null) { + return 'SUBSTRING(' . $value . ' FROM ' . $from . ')'; + } + + return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')'; + } + + /** + * Returns a series of strings concatinated + * + * concat() accepts an arbitrary number of parameters. Each parameter + * must contain an expression + * + * @param string $arg1, $arg2 ... $argN strings that will be concatenated. + * + * @return string + */ + public function getConcatExpression() + { + return join(' || ' , func_get_args()); + } + + /** + * Returns the SQL for a logical not. + * + * Example: + * + * $q = new Doctrine_Query(); + * $e = $q->expr; + * $q->select('*')->from('table') + * ->where($e->eq('id', $e->not('null')); + * + * + * @param string $expression + * + * @return string a logical expression + */ + public function getNotExpression($expression) + { + return 'NOT(' . $expression . ')'; + } + + /** + * Returns the SQL to check if a value is one in a set of + * given values. + * + * in() accepts an arbitrary number of parameters. The first parameter + * must always specify the value that should be matched against. Successive + * must contain a logical expression or an array with logical expressions. + * These expressions will be matched against the first parameter. + * + * @param string $column the value that should be matched against + * @param string|array $values values that will be matched against $column + * + * @return string logical expression + */ + public function getInExpression($column, $values) + { + if ( ! is_array($values)) { + $values = array($values); + } + + // TODO: fix this code: the method does not exist + $values = $this->getIdentifiers($values); + + if (count($values) == 0) { + throw new \InvalidArgumentException('Values must not be empty.'); + } + + return $column . ' IN (' . implode(', ', $values) . ')'; + } + + /** + * Returns SQL that checks if a expression is null. + * + * @param string $expression the expression that should be compared to null + * + * @return string logical expression + */ + public function getIsNullExpression($expression) + { + return $expression . ' IS NULL'; + } + + /** + * Returns SQL that checks if a expression is not null. + * + * @param string $expression the expression that should be compared to null + * + * @return string logical expression + */ + public function getIsNotNullExpression($expression) + { + return $expression . ' IS NOT NULL'; + } + + /** + * Returns SQL that checks if an expression evaluates to a value between + * two values. + * + * The parameter $expression is checked if it is between $value1 and $value2. + * + * Note: There is a slight difference in the way BETWEEN works on some databases. + * http://www.w3schools.com/sql/sql_between.asp. If you want complete database + * independence you should avoid using between(). + * + * @param string $expression the value to compare to + * @param string $value1 the lower value to compare with + * @param string $value2 the higher value to compare with + * + * @return string logical expression + */ + public function getBetweenExpression($expression, $value1, $value2) + { + return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2; + } + + public function getAcosExpression($value) + { + return 'ACOS(' . $value . ')'; + } + + public function getSinExpression($value) + { + return 'SIN(' . $value . ')'; + } + + public function getPiExpression() + { + return 'PI()'; + } + + public function getCosExpression($value) + { + return 'COS(' . $value . ')'; + } + + /** + * Calculate the difference in days between the two passed dates. + * + * Computes diff = date1 - date2 + * + * @param string $date1 + * @param string $date2 + * + * @return string + */ + public function getDateDiffExpression($date1, $date2) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Add the number of given days to a date. + * + * @param string $date + * @param integer $days + * + * @return string + */ + public function getDateAddDaysExpression($date, $days) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Substract the number of given days to a date. + * + * @param string $date + * @param integer $days + * + * @return string + */ + public function getDateSubDaysExpression($date, $days) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Add the number of given months to a date. + * + * @param string $date + * @param integer $months + * + * @return string + */ + public function getDateAddMonthExpression($date, $months) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Substract the number of given months to a date. + * + * @param string $date + * @param integer $months + * + * @return string + */ + public function getDateSubMonthExpression($date, $months) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Gets SQL bit AND comparison expression + * + * @param string $value1 + * @param string $value2 + * + * @return string + */ + public function getBitAndComparisonExpression($value1, $value2) + { + return '(' . $value1 . ' & ' . $value2 . ')'; + } + + /** + * Gets SQL bit OR comparison expression + * + * @param string $value1 + * @param string $value2 + * + * @return string + */ + public function getBitOrComparisonExpression($value1, $value2) + { + return '(' . $value1 . ' | ' . $value2 . ')'; + } + + public function getForUpdateSQL() + { + return 'FOR UPDATE'; + } + + /** + * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification. + * + * @param string $fromClause + * @param integer $lockMode + * + * @return string + */ + public function appendLockHint($fromClause, $lockMode) + { + return $fromClause; + } + + /** + * Get the sql snippet to append to any SELECT statement which locks rows in shared read lock. + * + * This defaults to the ASNI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database + * vendors allow to lighten this constraint up to be a real read lock. + * + * @return string + */ + public function getReadLockSQL() + { + return $this->getForUpdateSQL(); + } + + /** + * Get the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows. + * + * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ASNI SQL standard. + * + * @return string + */ + public function getWriteLockSQL() + { + return $this->getForUpdateSQL(); + } + + /** + * Get the SQL snippet to drop an existing database + * + * @param string $database name of the database that should be dropped + * + * @return string + */ + public function getDropDatabaseSQL($database) + { + return 'DROP DATABASE ' . $database; + } + + /** + * Drop a Table + * + * @throws \InvalidArgumentException + * + * @param Table|string $table + * + * @return string + */ + public function getDropTableSQL($table) + { + $tableArg = $table; + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } else if(!is_string($table)) { + throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); + } + + if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) { + $eventArgs = new SchemaDropTableEventArgs($tableArg, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs); + + if ($eventArgs->isDefaultPrevented()) { + return $eventArgs->getSql(); + } + } + + return 'DROP TABLE ' . $table; + } + + /** + * Get SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction. + * + * @param Table|string $table + * + * @return string + */ + public function getDropTemporaryTableSQL($table) + { + return $this->getDropTableSQL($table); + } + + /** + * Drop index from a table + * + * @param Index|string $name + * @param string|Table $table + * + * @return string + */ + public function getDropIndexSQL($index, $table = null) + { + if ($index instanceof Index) { + $index = $index->getQuotedName($this); + } else if(!is_string($index)) { + throw new \InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); + } + + return 'DROP INDEX ' . $index; + } + + /** + * Get drop constraint sql + * + * @param \Doctrine\DBAL\Schema\Constraint $constraint + * @param string|Table $table + * + * @return string + */ + public function getDropConstraintSQL($constraint, $table) + { + if ($constraint instanceof Constraint) { + $constraint = $constraint->getQuotedName($this); + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint; + } + + /** + * @param ForeignKeyConstraint|string $foreignKey + * @param Table|string $table + * + * @return string + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + if ($foreignKey instanceof ForeignKeyConstraint) { + $foreignKey = $foreignKey->getQuotedName($this); + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey; + } + + /** + * Gets the SQL statement(s) to create a table with the specified name, columns and constraints + * on this platform. + * + * @param string $table The name of the table. + * @param integer $createFlags + * + * @return array The sequence of SQL statements. + */ + public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES) + { + if ( ! is_int($createFlags)) { + throw new \InvalidArgumentException("Second argument of AbstractPlatform::getCreateTableSQL() has to be integer."); + } + + if (count($table->getColumns()) === 0) { + throw DBALException::noColumnsSpecifiedForTable($table->getName()); + } + + $tableName = $table->getQuotedName($this); + $options = $table->getOptions(); + $options['uniqueConstraints'] = array(); + $options['indexes'] = array(); + $options['primary'] = array(); + + if (($createFlags&self::CREATE_INDEXES) > 0) { + foreach ($table->getIndexes() as $index) { + /* @var $index Index */ + if ($index->isPrimary()) { + $options['primary'] = $index->getColumns(); + $options['primary_index'] = $index; + } else { + $options['indexes'][$index->getName()] = $index; + } + } + } + + $columnSql = array(); + $columns = array(); + + foreach ($table->getColumns() as $column) { + /* @var \Doctrine\DBAL\Schema\Column $column */ + + if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaCreateTableColumn)) { + $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + if ($eventArgs->isDefaultPrevented()) { + continue; + } + } + + $columnData = array(); + $columnData['name'] = $column->getQuotedName($this); + $columnData['type'] = $column->getType(); + $columnData['length'] = $column->getLength(); + $columnData['notnull'] = $column->getNotNull(); + $columnData['fixed'] = $column->getFixed(); + $columnData['unique'] = false; // TODO: what do we do about this? + $columnData['version'] = $column->hasPlatformOption("version") ? $column->getPlatformOption('version') : false; + + if (strtolower($columnData['type']) == "string" && $columnData['length'] === null) { + $columnData['length'] = 255; + } + + $columnData['unsigned'] = $column->getUnsigned(); + $columnData['precision'] = $column->getPrecision(); + $columnData['scale'] = $column->getScale(); + $columnData['default'] = $column->getDefault(); + $columnData['columnDefinition'] = $column->getColumnDefinition(); + $columnData['autoincrement'] = $column->getAutoincrement(); + $columnData['comment'] = $this->getColumnComment($column); + + if (in_array($column->getName(), $options['primary'])) { + $columnData['primary'] = true; + } + + $columns[$columnData['name']] = $columnData; + } + + if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) { + $options['foreignKeys'] = array(); + foreach ($table->getForeignKeys() as $fkConstraint) { + $options['foreignKeys'][] = $fkConstraint; + } + } + + if (null !== $this->_eventManager && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) { + $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs); + + if ($eventArgs->isDefaultPrevented()) { + return array_merge($eventArgs->getSql(), $columnSql); + } + } + + $sql = $this->_getCreateTableSQL($tableName, $columns, $options); + if ($this->supportsCommentOnStatement()) { + foreach ($table->getColumns() as $column) { + if ($this->getColumnComment($column)) { + $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getName(), $this->getColumnComment($column)); + } + } + } + + return array_merge($sql, $columnSql); + } + + public function getCommentOnColumnSQL($tableName, $columnName, $comment) + { + return "COMMENT ON COLUMN " . $tableName . "." . $columnName . " IS '" . $comment . "'"; + } + + /** + * Gets the SQL used to create a table. + * + * @param string $tableName + * @param array $columns + * @param array $options + * + * @return array + */ + protected function _getCreateTableSQL($tableName, array $columns, array $options = array()) + { + $columnListSql = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { + foreach ($options['uniqueConstraints'] as $name => $definition) { + $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); + } + } + + if (isset($options['primary']) && ! empty($options['primary'])) { + $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')'; + } + + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach($options['indexes'] as $index => $definition) { + $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition); + } + } + + $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql; + + $check = $this->getCheckDeclarationSQL($columns); + if ( ! empty($check)) { + $query .= ', ' . $check; + } + $query .= ')'; + + $sql[] = $query; + + if (isset($options['foreignKeys'])) { + foreach ((array) $options['foreignKeys'] as $definition) { + $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); + } + } + + return $sql; + } + + public function getCreateTemporaryTableSnippetSQL() + { + return "CREATE TEMPORARY TABLE"; + } + + /** + * Gets the SQL to create a sequence on this platform. + * + * @param \Doctrine\DBAL\Schema\Sequence $sequence + * + * @return string + * + * @throws DBALException + */ + public function getCreateSequenceSQL(Sequence $sequence) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Gets the SQL statement to change a sequence on this platform. + * + * @param \Doctrine\DBAL\Schema\Sequence $sequence + * + * @return string + */ + public function getAlterSequenceSQL(Sequence $sequence) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Gets the SQL to create a constraint on a table on this platform. + * + * @param \Doctrine\DBAL\Schema\Constraint $constraint + * @param string|Table $table + * + * @return string + */ + public function getCreateConstraintSQL(Constraint $constraint, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this); + + $columns = array(); + foreach ($constraint->getColumns() as $column) { + $columns[] = $column; + } + $columnList = '('. implode(', ', $columns) . ')'; + + $referencesClause = ''; + if ($constraint instanceof Index) { + if($constraint->isPrimary()) { + $query .= ' PRIMARY KEY'; + } elseif ($constraint->isUnique()) { + $query .= ' UNIQUE'; + } else { + throw new \InvalidArgumentException( + 'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().' + ); + } + } else if ($constraint instanceof ForeignKeyConstraint) { + $query .= ' FOREIGN KEY'; + + $foreignColumns = array(); + foreach ($constraint->getForeignColumns() as $column) { + $foreignColumns[] = $column; + } + + $referencesClause = ' REFERENCES '.$constraint->getForeignTableName(). ' ('.implode(', ', $foreignColumns).')'; + } + $query .= ' '.$columnList.$referencesClause; + + return $query; + } + + /** + * Gets the SQL to create an index on a table on this platform. + * + * @param Index $index + * @param string|Table $table name of the table on which the index is to be created + * + * @return string + */ + public function getCreateIndexSQL(Index $index, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + $name = $index->getQuotedName($this); + $columns = $index->getColumns(); + + if (count($columns) == 0) { + throw new \InvalidArgumentException("Incomplete definition. 'columns' required."); + } + + if ($index->isPrimary()) { + return $this->getCreatePrimaryKeySQL($index, $table); + } + + $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table; + $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')'; + + return $query; + } + + /** + * Adds additional flags for index generation + * + * @param Index $index + * + * @return string + */ + protected function getCreateIndexSQLFlags(Index $index) + { + return $index->isUnique() ? 'UNIQUE ' : ''; + } + + /** + * Get SQL to create an unnamed primary key constraint. + * + * @param Index $index + * @param string|Table $table + * + * @return string + */ + public function getCreatePrimaryKeySQL(Index $index, $table) + { + return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index->getColumns()) . ')'; + } + + /** + * Quotes a string so that it can be safely used as a table or column name, + * even if it is a reserved word of the platform. This also detects identifier + * chains separated by dot and quotes them independently. + * + * NOTE: Just because you CAN use quoted identifiers doesn't mean + * you SHOULD use them. In general, they end up causing way more + * problems than they solve. + * + * @param string $str identifier name to be quoted + * + * @return string quoted identifier string + */ + public function quoteIdentifier($str) + { + if (strpos($str, ".") !== false) { + $parts = array_map(array($this, "quoteIdentifier"), explode(".", $str)); + + return implode(".", $parts); + } + + return $this->quoteSingleIdentifier($str); + } + + /** + * Quote a single identifier (no dot chain separation) + * + * @param string $str + * + * @return string + */ + public function quoteSingleIdentifier($str) + { + $c = $this->getIdentifierQuoteCharacter(); + + return $c . str_replace($c, $c.$c, $str) . $c; + } + + /** + * Create a new foreign key + * + * @param ForeignKeyConstraint $foreignKey ForeignKey instance + * @param string|Table $table name of the table on which the foreign key is to be created + * + * @return string + */ + public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey); + + return $query; + } + + /** + * Gets the sql statements for altering an existing table. + * + * The method returns an array of sql statements, since some platforms need several statements. + * + * @param TableDiff $diff + * + * @return array + */ + public function getAlterTableSQL(TableDiff $diff) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * @param Column $column + * @param TableDiff $diff + * @param array $columnSql + * + * @return boolean + */ + protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql) + { + if (null === $this->_eventManager) { + return false; + } + + if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) { + return false; + } + + $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + /** + * @param Column $column + * @param TableDiff $diff + * @param array $columnSql + * + * @return boolean + */ + protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql) + { + if (null === $this->_eventManager) { + return false; + } + + if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) { + return false; + } + + $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + /** + * @param ColumnDiff $columnDiff + * @param TableDiff $diff + * @param array $columnSql + * + * @return boolean + */ + protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql) + { + if (null === $this->_eventManager) { + return false; + } + + if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) { + return false; + } + + $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + /** + * @param string $oldColumnName + * @param Column $column + * @param TableDiff $diff + * @param array $columnSql + * + * @return boolean + */ + protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql) + { + if (null === $this->_eventManager) { + return false; + } + + if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) { + return false; + } + + $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs); + + $columnSql = array_merge($columnSql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + /** + * @param TableDiff $diff + * @param array $sql + * + * @return boolean + */ + protected function onSchemaAlterTable(TableDiff $diff, &$sql) + { + if (null === $this->_eventManager) { + return false; + } + + if ( ! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) { + return false; + } + + $eventArgs = new SchemaAlterTableEventArgs($diff, $this); + $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs); + + $sql = array_merge($sql, $eventArgs->getSql()); + + return $eventArgs->isDefaultPrevented(); + } + + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $tableName = $diff->name; + + $sql = array(); + if ($this->supportsForeignKeyConstraints()) { + foreach ($diff->removedForeignKeys as $foreignKey) { + $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); + } + foreach ($diff->changedForeignKeys as $foreignKey) { + $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); + } + } + + foreach ($diff->removedIndexes as $index) { + $sql[] = $this->getDropIndexSQL($index, $tableName); + } + foreach ($diff->changedIndexes as $index) { + $sql[] = $this->getDropIndexSQL($index, $tableName); + } + + return $sql; + } + + protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $tableName = false !== $diff->newName ? $diff->newName : $diff->name; + + $sql = array(); + if ($this->supportsForeignKeyConstraints()) { + foreach ($diff->addedForeignKeys as $foreignKey) { + $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); + } + foreach ($diff->changedForeignKeys as $foreignKey) { + $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); + } + } + + foreach ($diff->addedIndexes as $index) { + $sql[] = $this->getCreateIndexSQL($index, $tableName); + } + foreach ($diff->changedIndexes as $index) { + $sql[] = $this->getCreateIndexSQL($index, $tableName); + } + + return $sql; + } + + /** + * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions. + * + * @param TableDiff $diff + * + * @return array + */ + protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff) + { + return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff)); + } + + /** + * Get declaration of a number of fields in bulk + * + * @param array $fields a multidimensional associative array. + * The first dimension determines the field name, while the second + * dimension is keyed with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * charset + * Text value with the default CHARACTER SET for this field. + * collation + * Text value with the default COLLATION for this field. + * unique + * unique constraint + * + * @return string + */ + public function getColumnDeclarationListSQL(array $fields) + { + $queryFields = array(); + + foreach ($fields as $fieldName => $field) { + $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field); + } + + return implode(', ', $queryFields); + } + + /** + * Obtain DBMS specific SQL code portion needed to declare a generic type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * charset + * Text value with the default CHARACTER SET for this field. + * collation + * Text value with the default COLLATION for this field. + * unique + * unique constraint + * check + * column check constraint + * columnDefinition + * a string that defines the complete column + * + * @return string DBMS specific SQL code portion that should be used to declare the column. + */ + public function getColumnDeclarationSQL($name, array $field) + { + if (isset($field['columnDefinition'])) { + $columnDef = $this->getCustomTypeDeclarationSQL($field); + } else { + $default = $this->getDefaultValueDeclarationSQL($field); + + $charset = (isset($field['charset']) && $field['charset']) ? + ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : ''; + + $collation = (isset($field['collation']) && $field['collation']) ? + ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : ''; + + $notnull = (isset($field['notnull']) && $field['notnull']) ? ' NOT NULL' : ''; + + $unique = (isset($field['unique']) && $field['unique']) ? + ' ' . $this->getUniqueFieldDeclarationSQL() : ''; + + $check = (isset($field['check']) && $field['check']) ? + ' ' . $field['check'] : ''; + + $typeDecl = $field['type']->getSqlDeclaration($field, $this); + $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation; + } + + if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment']) { + $columnDef .= " COMMENT '" . $field['comment'] . "'"; + } + + return $name . ' ' . $columnDef; + } + + /** + * Gets the SQL snippet that declares a floating point column of arbitrary precision. + * + * @param array $columnDef + * + * @return string + */ + public function getDecimalTypeDeclarationSQL(array $columnDef) + { + $columnDef['precision'] = ( ! isset($columnDef['precision']) || empty($columnDef['precision'])) + ? 10 : $columnDef['precision']; + $columnDef['scale'] = ( ! isset($columnDef['scale']) || empty($columnDef['scale'])) + ? 0 : $columnDef['scale']; + + return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')'; + } + + /** + * Obtain DBMS specific SQL code portion needed to set a default value + * declaration to be used in statements like CREATE TABLE. + * + * @param array $field field definition array + * + * @return string DBMS specific SQL code portion needed to set a default value + */ + public function getDefaultValueDeclarationSQL($field) + { + $default = empty($field['notnull']) ? ' DEFAULT NULL' : ''; + + if (isset($field['default'])) { + $default = " DEFAULT '".$field['default']."'"; + if (isset($field['type'])) { + if (in_array((string)$field['type'], array("Integer", "BigInteger", "SmallInteger"))) { + $default = " DEFAULT ".$field['default']; + } else if ((string)$field['type'] == 'DateTime' && $field['default'] == $this->getCurrentTimestampSQL()) { + $default = " DEFAULT ".$this->getCurrentTimestampSQL(); + } else if ((string) $field['type'] == 'Boolean') { + $default = " DEFAULT '" . $this->convertBooleans($field['default']) . "'"; + } + } + } + return $default; + } + + /** + * Obtain DBMS specific SQL code portion needed to set a CHECK constraint + * declaration to be used in statements like CREATE TABLE. + * + * @param array $definition check definition + * + * @return string DBMS specific SQL code portion needed to set a CHECK constraint + */ + public function getCheckDeclarationSQL(array $definition) + { + $constraints = array(); + foreach ($definition as $field => $def) { + if (is_string($def)) { + $constraints[] = 'CHECK (' . $def . ')'; + } else { + if (isset($def['min'])) { + $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')'; + } + + if (isset($def['max'])) { + $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')'; + } + } + } + + return implode(', ', $constraints); + } + + /** + * Obtain DBMS specific SQL code portion needed to set a unique + * constraint declaration to be used in statements like CREATE TABLE. + * + * @param string $name name of the unique constraint + * @param Index $index index definition + * + * @return string DBMS specific SQL code portion needed + * to set a constraint + */ + public function getUniqueConstraintDeclarationSQL($name, Index $index) + { + if (count($index->getColumns()) === 0) { + throw new \InvalidArgumentException("Incomplete definition. 'columns' required."); + } + + return 'CONSTRAINT ' . $name . ' UNIQUE (' + . $this->getIndexFieldDeclarationListSQL($index->getColumns()) + . ')'; + } + + /** + * Obtain DBMS specific SQL code portion needed to set an index + * declaration to be used in statements like CREATE TABLE. + * + * @param string $name name of the index + * @param Index $index index definition + * + * @return string DBMS specific SQL code portion needed to set an index + */ + public function getIndexDeclarationSQL($name, Index $index) + { + $type = ''; + + if ($index->isUnique()) { + $type = 'UNIQUE '; + } + + if (count($index->getColumns()) === 0) { + throw new \InvalidArgumentException("Incomplete definition. 'columns' required."); + } + + return $type . 'INDEX ' . $name . ' (' + . $this->getIndexFieldDeclarationListSQL($index->getColumns()) + . ')'; + } + + /** + * getCustomTypeDeclarationSql + * Obtail SQL code portion needed to create a custom column, + * e.g. when a field has the "columnDefinition" keyword. + * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate. + * + * @param array $columnDef + * + * @return string + */ + public function getCustomTypeDeclarationSQL(array $columnDef) + { + return $columnDef['columnDefinition']; + } + + /** + * getIndexFieldDeclarationList + * Obtain DBMS specific SQL code portion needed to set an index + * declaration to be used in statements like CREATE TABLE. + * + * @param array $fields + * + * @return string + */ + public function getIndexFieldDeclarationListSQL(array $fields) + { + $ret = array(); + + foreach ($fields as $field => $definition) { + if (is_array($definition)) { + $ret[] = $field; + } else { + $ret[] = $definition; + } + } + + return implode(', ', $ret); + } + + /** + * A method to return the required SQL string that fits between CREATE ... TABLE + * to create the table as a temporary table. + * + * Should be overridden in driver classes to return the correct string for the + * specific database type. + * + * The default is to return the string "TEMPORARY" - this will result in a + * SQL error for any database that does not support temporary tables, or that + * requires a different SQL command from "CREATE TEMPORARY TABLE". + * + * @return string The string required to be placed between "CREATE" and "TABLE" + * to generate a temporary table, if possible. + */ + public function getTemporaryTableSQL() + { + return 'TEMPORARY'; + } + + /** + * Some vendors require temporary table names to be qualified specially. + * + * @param string $tableName + * + * @return string + */ + public function getTemporaryTableName($tableName) + { + return $tableName; + } + + /** + * Get sql query to show a list of database. + * + * @return string + */ + public function getShowDatabasesSQL() + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint + * of a field declaration to be used in statements like CREATE TABLE. + * + * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey + * + * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint + * of a field declaration. + */ + public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) + { + $sql = $this->getForeignKeyBaseDeclarationSQL($foreignKey); + $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey); + + return $sql; + } + + /** + * Return the FOREIGN KEY query section dealing with non-standard options + * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... + * + * @param ForeignKeyConstraint $foreignKey foreign key definition + * + * @return string + */ + public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) + { + $query = ''; + if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) { + $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate')); + } + if ($foreignKey->hasOption('onDelete')) { + $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete')); + } + return $query; + } + + /** + * returns given referential action in uppercase if valid, otherwise throws + * an exception + * + * @throws \InvalidArgumentException if unknown referential action given + * + * @param string $action foreign key referential action + * + * @return string + */ + public function getForeignKeyReferentialActionSQL($action) + { + $upper = strtoupper($action); + switch ($upper) { + case 'CASCADE': + case 'SET NULL': + case 'NO ACTION': + case 'RESTRICT': + case 'SET DEFAULT': + return $upper; + default: + throw new \InvalidArgumentException('Invalid foreign key action: ' . $upper); + } + } + + /** + * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint + * of a field declaration to be used in statements like CREATE TABLE. + * + * @param ForeignKeyConstraint $foreignKey + * + * @return string + */ + public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey) + { + $sql = ''; + if (strlen($foreignKey->getName())) { + $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' '; + } + $sql .= 'FOREIGN KEY ('; + + if (count($foreignKey->getLocalColumns()) === 0) { + throw new \InvalidArgumentException("Incomplete definition. 'local' required."); + } + if (count($foreignKey->getForeignColumns()) === 0) { + throw new \InvalidArgumentException("Incomplete definition. 'foreign' required."); + } + if (strlen($foreignKey->getForeignTableName()) === 0) { + throw new \InvalidArgumentException("Incomplete definition. 'foreignTable' required."); + } + + $sql .= implode(', ', $foreignKey->getLocalColumns()) + . ') REFERENCES ' + . $foreignKey->getQuotedForeignTableName($this) . ' (' + . implode(', ', $foreignKey->getForeignColumns()) . ')'; + + return $sql; + } + + /** + * Obtain DBMS specific SQL code portion needed to set the UNIQUE constraint + * of a field declaration to be used in statements like CREATE TABLE. + * + * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint + * of a field declaration. + */ + public function getUniqueFieldDeclarationSQL() + { + return 'UNIQUE'; + } + + /** + * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET + * of a field declaration to be used in statements like CREATE TABLE. + * + * @param string $charset name of the charset + * + * @return string DBMS specific SQL code portion needed to set the CHARACTER SET + * of a field declaration. + */ + public function getColumnCharsetDeclarationSQL($charset) + { + return ''; + } + + /** + * Obtain DBMS specific SQL code portion needed to set the COLLATION + * of a field declaration to be used in statements like CREATE TABLE. + * + * @param string $collation name of the collation + * + * @return string DBMS specific SQL code portion needed to set the COLLATION + * of a field declaration. + */ + public function getColumnCollationDeclarationSQL($collation) + { + return ''; + } + + /** + * Whether the platform prefers sequences for ID generation. + * Subclasses should override this method to return TRUE if they prefer sequences. + * + * @return boolean + */ + public function prefersSequences() + { + return false; + } + + /** + * Whether the platform prefers identity columns (eg. autoincrement) for ID generation. + * Subclasses should override this method to return TRUE if they prefer identity columns. + * + * @return boolean + */ + public function prefersIdentityColumns() + { + return false; + } + + /** + * Some platforms need the boolean values to be converted. + * + * The default conversion in this implementation converts to integers (false => 0, true => 1). + * + * @param mixed $item + * + * @return mixed + */ + public function convertBooleans($item) + { + if (is_array($item)) { + foreach ($item as $k => $value) { + if (is_bool($value)) { + $item[$k] = (int) $value; + } + } + } else if (is_bool($item)) { + $item = (int) $item; + } + + return $item; + } + + /** + * Gets the SQL specific for the platform to get the current date. + * + * @return string + */ + public function getCurrentDateSQL() + { + return 'CURRENT_DATE'; + } + + /** + * Gets the SQL specific for the platform to get the current time. + * + * @return string + */ + public function getCurrentTimeSQL() + { + return 'CURRENT_TIME'; + } + + /** + * Gets the SQL specific for the platform to get the current timestamp + * + * @return string + */ + public function getCurrentTimestampSQL() + { + return 'CURRENT_TIMESTAMP'; + } + + /** + * Get sql for transaction isolation level Connection constant + * + * @param integer $level + * + * @return string + */ + protected function _getTransactionIsolationLevelSQL($level) + { + switch ($level) { + case Connection::TRANSACTION_READ_UNCOMMITTED: + return 'READ UNCOMMITTED'; + case Connection::TRANSACTION_READ_COMMITTED: + return 'READ COMMITTED'; + case Connection::TRANSACTION_REPEATABLE_READ: + return 'REPEATABLE READ'; + case Connection::TRANSACTION_SERIALIZABLE: + return 'SERIALIZABLE'; + default: + throw new \InvalidArgumentException('Invalid isolation level:' . $level); + } + } + + public function getListDatabasesSQL() + { + throw DBALException::notSupported(__METHOD__); + } + + public function getListSequencesSQL($database) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getListTableConstraintsSQL($table) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getListTableColumnsSQL($table, $database = null) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getListTablesSQL() + { + throw DBALException::notSupported(__METHOD__); + } + + public function getListUsersSQL() + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Get the SQL to list all views of a database or user. + * + * @param string $database + * + * @return string + */ + public function getListViewsSQL($database) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Get the list of indexes for the current database. + * + * The current database parameter is optional but will always be passed + * when using the SchemaManager API and is the database the given table is in. + * + * Attention: Some platforms only support currentDatabase when they + * are connected with that database. Cross-database information schema + * requests may be impossible. + * + * @param string $table + * @param string $currentDatabase + * + * @return string + */ + public function getListTableIndexesSQL($table, $currentDatabase = null) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getListTableForeignKeysSQL($table) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getCreateViewSQL($name, $sql) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getDropViewSQL($name) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Get the SQL snippet to drop an existing sequence + * + * @param \Doctrine\DBAL\Schema\Sequence $sequence + * + * @return string + */ + public function getDropSequenceSQL($sequence) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getSequenceNextValSQL($sequenceName) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * create a new database + * + * @param string $database name of the database that should be created + * + * @return string + */ + public function getCreateDatabaseSQL($database) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Get sql to set the transaction isolation level + * + * @param integer $level + * + * @return string + */ + public function getSetTransactionIsolationSQL($level) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Obtain DBMS specific SQL to be used to create datetime fields in + * statements like CREATE TABLE + * + * @param array $fieldDeclaration + * + * @return string + */ + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Obtain DBMS specific SQL to be used to create datetime with timezone offset fields. + * + * @param array $fieldDeclaration + * + * @return string + */ + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) + { + return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration); + } + + + /** + * Obtain DBMS specific SQL to be used to create date fields in statements + * like CREATE TABLE. + * + * @param array $fieldDeclaration + * + * @return string + */ + public function getDateTypeDeclarationSQL(array $fieldDeclaration) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * Obtain DBMS specific SQL to be used to create time fields in statements + * like CREATE TABLE. + * + * @param array $fieldDeclaration + * + * @return string + */ + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getFloatDeclarationSQL(array $fieldDeclaration) + { + return 'DOUBLE PRECISION'; + } + + /** + * Gets the default transaction isolation level of the platform. + * + * @return integer The default isolation level. + * + * @see Doctrine\DBAL\Connection\TRANSACTION_* constants. + */ + public function getDefaultTransactionIsolationLevel() + { + return Connection::TRANSACTION_READ_COMMITTED; + } + + /* supports*() methods */ + + /** + * Whether the platform supports sequences. + * + * @return boolean + */ + public function supportsSequences() + { + return false; + } + + /** + * Whether the platform supports identity columns. + * Identity columns are columns that recieve an auto-generated value from the + * database on insert of a row. + * + * @return boolean + */ + public function supportsIdentityColumns() + { + return false; + } + + /** + * Whether the platform supports indexes. + * + * @return boolean + */ + public function supportsIndexes() + { + return true; + } + + /** + * Whether the platform supports altering tables. + * + * @return boolean + */ + public function supportsAlterTable() + { + return true; + } + + /** + * Whether the platform supports transactions. + * + * @return boolean + */ + public function supportsTransactions() + { + return true; + } + + /** + * Whether the platform supports savepoints. + * + * @return boolean + */ + public function supportsSavepoints() + { + return true; + } + + /** + * Whether the platform supports releasing savepoints. + * + * @return boolean + */ + public function supportsReleaseSavepoints() + { + return $this->supportsSavepoints(); + } + + /** + * Whether the platform supports primary key constraints. + * + * @return boolean + */ + public function supportsPrimaryConstraints() + { + return true; + } + + /** + * Does the platform supports foreign key constraints? + * + * @return boolean + */ + public function supportsForeignKeyConstraints() + { + return true; + } + + /** + * Does this platform supports onUpdate in foreign key constraints? + * + * @return boolean + */ + public function supportsForeignKeyOnUpdate() + { + return ($this->supportsForeignKeyConstraints() && true); + } + + /** + * Whether the platform supports database schemas. + * + * @return boolean + */ + public function supportsSchemas() + { + return false; + } + + /** + * Can this platform emulate schemas? + * + * Platforms that either support or emulate schemas don't automatically + * filter a schema for the namespaced elements in {@link + * AbstractManager#createSchema}. + * + * @return boolean + */ + public function canEmulateSchemas() + { + return false; + } + + /** + * Some databases don't allow to create and drop databases at all or only with certain tools. + * + * @return boolean + */ + public function supportsCreateDropDatabase() + { + return true; + } + + /** + * Whether the platform supports getting the affected rows of a recent + * update/delete type query. + * + * @return boolean + */ + public function supportsGettingAffectedRows() + { + return true; + } + + /** + * Does this plaform support to add inline column comments as postfix. + * + * @return boolean + */ + public function supportsInlineColumnComments() + { + return false; + } + + /** + * Does this platform support the propriortary synatx "COMMENT ON asset" + * + * @return boolean + */ + public function supportsCommentOnStatement() + { + return false; + } + + public function getIdentityColumnNullInsertSQL() + { + return ""; + } + + /** + * Does this platform views ? + * + * @return boolean + */ + public function supportsViews() + { + return true; + } + + /** + * Gets the format string, as accepted by the date() function, that describes + * the format of a stored datetime value of this platform. + * + * @return string The format string. + */ + public function getDateTimeFormatString() + { + return 'Y-m-d H:i:s'; + } + + /** + * Gets the format string, as accepted by the date() function, that describes + * the format of a stored datetime with timezone value of this platform. + * + * @return string The format string. + */ + public function getDateTimeTzFormatString() + { + return 'Y-m-d H:i:s'; + } + + /** + * Gets the format string, as accepted by the date() function, that describes + * the format of a stored date value of this platform. + * + * @return string The format string. + */ + public function getDateFormatString() + { + return 'Y-m-d'; + } + + /** + * Gets the format string, as accepted by the date() function, that describes + * the format of a stored time value of this platform. + * + * @return string The format string. + */ + public function getTimeFormatString() + { + return 'H:i:s'; + } + + /** + * Modify limit query + * + * @param string $query + * @param integer $limit + * @param integer $offset + * + * @return string + */ + final public function modifyLimitQuery($query, $limit, $offset = null) + { + if ($limit !== null) { + $limit = (int)$limit; + } + + if ($offset !== null) { + $offset = (int)$offset; + + if ($offset < 0) { + throw new DBALException("LIMIT argument offset=$offset is not valid"); + } + if ($offset > 0 && ! $this->supportsLimitOffset()) { + throw new DBALException(sprintf("Platform %s does not support offset values in limit queries.", $this->getName())); + } + } + + return $this->doModifyLimitQuery($query, $limit, $offset); + } + + /** + * Adds an driver-specific LIMIT clause to the query + * + * @param string $query + * @param integer $limit + * @param integer $offset + * + * @return string + */ + protected function doModifyLimitQuery($query, $limit, $offset) + { + if ($limit !== null) { + $query .= ' LIMIT ' . $limit; + } + + if ($offset !== null) { + $query .= ' OFFSET ' . $offset; + } + + return $query; + } + + /** + * Does the database platform support offsets in modify limit clauses? + * + * @return boolean + */ + public function supportsLimitOffset() + { + return true; + } + + /** + * Gets the character casing of a column in an SQL result set of this platform. + * + * @param string $column The column name for which to get the correct character casing. + * + * @return string The column name in the character casing used in SQL result sets. + */ + public function getSQLResultCasing($column) + { + return $column; + } + + /** + * Makes any fixes to a name of a schema element (table, sequence, ...) that are required + * by restrictions of the platform, like a maximum length. + * + * @param string $schemaElementName + * + * @return string + */ + public function fixSchemaElementName($schemaElementName) + { + return $schemaElementName; + } + + /** + * Maximum length of any given databse identifier, like tables or column names. + * + * @return integer + */ + public function getMaxIdentifierLength() + { + return 63; + } + + /** + * Get the insert sql for an empty insert statement + * + * @param string $tableName + * @param string $identifierColumnName + * + * @return string $sql + */ + public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName) + { + return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)'; + } + + /** + * Generate a Truncate Table SQL statement for a given table. + * + * Cascade is not supported on many platforms but would optionally cascade the truncate by + * following the foreign keys. + * + * @param string $tableName + * @param boolean $cascade + * + * @return string + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + return 'TRUNCATE '.$tableName; + } + + /** + * This is for test reasons, many vendors have special requirements for dummy statements. + * + * @return string + */ + public function getDummySelectSQL() + { + return 'SELECT 1'; + } + + /** + * Generate SQL to create a new savepoint + * + * @param string $savepoint + * + * @return string + */ + public function createSavePoint($savepoint) + { + return 'SAVEPOINT ' . $savepoint; + } + + /** + * Generate SQL to release a savepoint + * + * @param string $savepoint + * + * @return string + */ + public function releaseSavePoint($savepoint) + { + return 'RELEASE SAVEPOINT ' . $savepoint; + } + + /** + * Generate SQL to rollback a savepoint + * + * @param string $savepoint + * + * @return string + */ + public function rollbackSavePoint($savepoint) + { + return 'ROLLBACK TO SAVEPOINT ' . $savepoint; + } + + /** + * Return the keyword list instance of this platform. + * + * Throws exception if no keyword list is specified. + * + * @throws DBALException + * + * @return \Doctrine\DBAL\Platforms\Keywords\KeywordList + */ + final public function getReservedKeywordsList() + { + // Check for an existing instantiation of the keywords class. + if ($this->_keywords) { + return $this->_keywords; + } + + $class = $this->getReservedKeywordsClass(); + $keywords = new $class; + if ( ! $keywords instanceof \Doctrine\DBAL\Platforms\Keywords\KeywordList) { + throw DBALException::notSupported(__METHOD__); + } + + // Store the instance so it doesn't need to be generated on every request. + $this->_keywords = $keywords; + + return $keywords; + } + + /** + * The class name of the reserved keywords list. + * + * @return string + */ + protected function getReservedKeywordsClass() + { + throw DBALException::notSupported(__METHOD__); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php new file mode 100644 index 0000000..114cd7d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DB2Platform.php @@ -0,0 +1,545 @@ +. +*/ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\TableDiff; + +class DB2Platform extends AbstractPlatform +{ + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $field) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * {@inheritDoc} + */ + public function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = array( + 'smallint' => 'smallint', + 'bigint' => 'bigint', + 'integer' => 'integer', + 'time' => 'time', + 'date' => 'date', + 'varchar' => 'string', + 'character' => 'string', + 'clob' => 'text', + 'decimal' => 'decimal', + 'double' => 'float', + 'real' => 'float', + 'timestamp' => 'datetime', + ); + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $field) + { + // todo clob(n) with $field['length']; + return 'CLOB(1M)'; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'db2'; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $columnDef) + { + return 'SMALLINT'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $columnDef) + { + return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $columnDef) + { + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $columnDef) + { + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + { + $autoinc = ''; + if ( ! empty($columnDef['autoincrement'])) { + $autoinc = ' GENERATED BY DEFAULT AS IDENTITY'; + } + + return $autoinc; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + { + if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) { + return "TIMESTAMP(0) WITH DEFAULT"; + } + + return 'TIMESTAMP(0)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIME'; + } + + public function getListDatabasesSQL() + { + throw DBALException::notSupported(__METHOD__); + } + + public function getListSequencesSQL($database) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getListTableConstraintsSQL($table) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * This code fragment is originally from the Zend_Db_Adapter_Db2 class. + * + * @license New BSD License + * @param string $table + * @param string $database + * @return string + */ + public function getListTableColumnsSQL($table, $database = null) + { + return "SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno, + c.typename, c.default, c.nulls, c.length, c.scale, + c.identity, tc.type AS tabconsttype, k.colseq + FROM syscat.columns c + LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc + ON (k.tabschema = tc.tabschema + AND k.tabname = tc.tabname + AND tc.type = 'P')) + ON (c.tabschema = k.tabschema + AND c.tabname = k.tabname + AND c.colname = k.colname) + WHERE UPPER(c.tabname) = UPPER('" . $table . "') ORDER BY c.colno"; + } + + public function getListTablesSQL() + { + return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'"; + } + + public function getListUsersSQL() + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return "SELECT NAME, TEXT FROM SYSIBM.SYSVIEWS"; + } + + /** + * {@inheritDoc} + */ + public function getListTableIndexesSQL($table, $currentDatabase = null) + { + return "SELECT NAME, COLNAMES, UNIQUERULE FROM SYSIBM.SYSINDEXES WHERE TBNAME = UPPER('" . $table . "')"; + } + + public function getListTableForeignKeysSQL($table) + { + return "SELECT TBNAME, RELNAME, REFTBNAME, DELETERULE, UPDATERULE, FKCOLNAMES, PKCOLNAMES ". + "FROM SYSIBM.SYSRELS WHERE TBNAME = UPPER('".$table."')"; + } + + public function getCreateViewSQL($name, $sql) + { + return "CREATE VIEW ".$name." AS ".$sql; + } + + public function getDropViewSQL($name) + { + return "DROP VIEW ".$name; + } + + /** + * {@inheritDoc} + */ + public function getDropSequenceSQL($sequence) + { + throw DBALException::notSupported(__METHOD__); + } + + public function getSequenceNextValSQL($sequenceName) + { + throw DBALException::notSupported(__METHOD__); + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($database) + { + return "CREATE DATABASE ".$database; + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($database) + { + return "DROP DATABASE ".$database.";"; + } + + /** + * {@inheritDoc} + */ + public function supportsCreateDropDatabase() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function supportsReleaseSavepoints() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function getCurrentDateSQL() + { + return 'VALUES CURRENT DATE'; + } + + /** + * {@inheritDoc} + */ + public function getCurrentTimeSQL() + { + return 'VALUES CURRENT TIME'; + } + + /** + * {@inheritDoc} + */ + public function getCurrentTimestampSQL() + { + return "VALUES CURRENT TIMESTAMP"; + } + + /** + * {@inheritDoc} + */ + public function getIndexDeclarationSQL($name, Index $index) + { + return $this->getUniqueConstraintDeclarationSQL($name, $index); + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($tableName, array $columns, array $options = array()) + { + $indexes = array(); + if (isset($options['indexes'])) { + $indexes = $options['indexes']; + } + $options['indexes'] = array(); + + $sqls = parent::_getCreateTableSQL($tableName, $columns, $options); + + foreach ($indexes as $definition) { + $sqls[] = $this->getCreateIndexSQL($definition, $tableName); + } + return $sqls; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $sql = array(); + $columnSql = array(); + + $queryParts = array(); + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'ADD COLUMN ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'DROP COLUMN ' . $column->getQuotedName($this); + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + /* @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */ + $column = $columnDiff->column; + $queryParts[] = 'ALTER ' . ($columnDiff->oldColumnName) . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'RENAME ' . $oldColumnName . ' TO ' . $column->getQuotedName($this); + } + + $tableSql = array(); + + if ( ! $this->onSchemaAlterTable($diff, $tableSql)) { + if (count($queryParts) > 0) { + $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(" ", $queryParts); + } + + $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff)); + + if ($diff->newName !== false) { + $sql[] = 'RENAME TABLE TO ' . $diff->newName; + } + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * {@inheritDoc} + */ + public function getDefaultValueDeclarationSQL($field) + { + if (isset($field['notnull']) && $field['notnull'] && !isset($field['default'])) { + if (in_array((string)$field['type'], array("Integer", "BigInteger", "SmallInteger"))) { + $field['default'] = 0; + } else if((string)$field['type'] == "DateTime") { + $field['default'] = "00-00-00 00:00:00"; + } else if ((string)$field['type'] == "Date") { + $field['default'] = "00-00-00"; + } else if((string)$field['type'] == "Time") { + $field['default'] = "00:00:00"; + } else { + $field['default'] = ''; + } + } + + unset($field['default']); // @todo this needs fixing + if (isset($field['version']) && $field['version']) { + if ((string)$field['type'] != "DateTime") { + $field['default'] = "1"; + } + } + + return parent::getDefaultValueDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName) + { + return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (DEFAULT)'; + } + + public function getCreateTemporaryTableSnippetSQL() + { + return "DECLARE GLOBAL TEMPORARY TABLE"; + } + + /** + * {@inheritDoc} + */ + public function getTemporaryTableName($tableName) + { + return "SESSION." . $tableName; + } + + /** + * {@inheritDoc} + */ + protected function doModifyLimitQuery($query, $limit, $offset = null) + { + if ($limit === null && $offset === null) { + return $query; + } + + $limit = (int)$limit; + $offset = (int)(($offset)?:0); + + // Todo OVER() needs ORDER BY data! + $sql = 'SELECT db22.* FROM (SELECT ROW_NUMBER() OVER() AS DC_ROWNUM, db21.* '. + 'FROM (' . $query . ') db21) db22 WHERE db22.DC_ROWNUM BETWEEN ' . ($offset+1) .' AND ' . ($offset+$limit); + + return $sql; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos == false) { + return 'LOCATE(' . $substr . ', ' . $str . ')'; + } + + return 'LOCATE(' . $substr . ', ' . $str . ', '.$startPos.')'; + } + + /** + * {@inheritDoc} + */ + public function getSubstringExpression($value, $from, $length = null) + { + if ($length === null) { + return 'SUBSTR(' . $value . ', ' . $from . ')'; + } + + return 'SUBSTR(' . $value . ', ' . $from . ', ' . $length . ')'; + } + + /** + * {@inheritDoc} + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + * + * DB2 returns all column names in SQL result sets in uppercase. + */ + public function getSQLResultCasing($column) + { + return strtoupper($column); + } + + public function getForUpdateSQL() + { + return ' WITH RR USE AND KEEP UPDATE LOCKS'; + } + + /** + * {@inheritDoc} + */ + public function getDummySelectSQL() + { + return 'SELECT 1 FROM sysibm.sysdummy1'; + } + + /** + * {@inheritDoc} + * + * DB2 supports savepoints, but they work semantically different than on other vendor platforms. + * + * TODO: We have to investigate how to get DB2 up and running with savepoints. + */ + public function supportsSavepoints() + { + return false; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return 'Doctrine\DBAL\Platforms\Keywords\DB2Keywords'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php new file mode 100644 index 0000000..47bb364 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/DrizzlePlatform.php @@ -0,0 +1,495 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\DBALException, + Doctrine\DBAL\Schema\TableDiff, + Doctrine\DBAL\Schema\Index, + Doctrine\DBAL\Schema\Table; + +/** + * Drizzle platform + * + * @author Kim Hemsø Rasmussen + */ +class DrizzlePlatform extends AbstractPlatform +{ + /** + * {@inheritDoc} + */ + public function getName() + { + return 'drizzle'; + } + + /** + * {@inheritDoc} + */ + public function getIdentifierQuoteCharacter() + { + return '`'; + } + + + /** + * {@inheritDoc} + */ public function getConcatExpression() + { + $args = func_get_args(); + + return 'CONCAT(' . join(', ', (array) $args) . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return 'DATEDIFF(' . $date1 . ', ' . $date2 . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateAddDaysExpression($date, $days) + { + return 'DATE_ADD(' . $date . ', INTERVAL ' . $days . ' DAY)'; + } + + /** + * {@inheritDoc} + */ + public function getDateSubDaysExpression($date, $days) + { + return 'DATE_SUB(' . $date . ', INTERVAL ' . $days . ' DAY)'; + } + + /** + * {@inheritDoc} + */ + public function getDateAddMonthExpression($date, $months) + { + return 'DATE_ADD(' . $date . ', INTERVAL ' . $months . ' MONTH)'; + } + + /** + * {@inheritDoc} + */ + public function getDateSubMonthExpression($date, $months) + { + return 'DATE_SUB(' . $date . ', INTERVAL ' . $months . ' MONTH)'; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $field) + { + return 'BOOLEAN'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $field) + { + return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + { + $autoinc = ''; + if ( ! empty($columnDef['autoincrement'])) { + $autoinc = ' AUTO_INCREMENT'; + } + return $autoinc; + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $field) + { + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $field) + { + return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = array( + 'boolean' => 'boolean', + 'varchar' => 'string', + 'integer' => 'integer', + 'blob' => 'text', + 'decimal' => 'decimal', + 'datetime' => 'datetime', + 'date' => 'date', + 'time' => 'time', + 'text' => 'text', + 'timestamp' => 'datetime', + 'double' => 'float', + 'bigint' => 'bigint', + ); + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $field) + { + return 'TEXT'; + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $field) + { + return 'BLOB'; + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($name) + { + return 'DROP DATABASE ' . $name; + } + + public function getListDatabasesSQL() + { + return "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE CATALOG_NAME='LOCAL'"; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return 'Doctrine\DBAL\Platforms\Keywords\DrizzleKeywords'; + } + + public function getListTablesSQL() + { + return "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE' AND TABLE_SCHEMA=DATABASE()"; + } + + public function getListTableColumnsSQL($table, $database = null) + { + if ($database) { + $database = "'" . $database . "'"; + } else { + $database = 'DATABASE()'; + } + + return "SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE, IS_AUTO_INCREMENT, CHARACTER_MAXIMUM_LENGTH, COLUMN_DEFAULT," . + " NUMERIC_PRECISION, NUMERIC_SCALE" . + " FROM DATA_DICTIONARY.COLUMNS" . + " WHERE TABLE_SCHEMA=" . $database . " AND TABLE_NAME = '" . $table . "'"; + } + + public function getListTableForeignKeysSQL($table, $database = null) + { + if ($database) { + $database = "'" . $database . "'"; + } else { + $database = 'DATABASE()'; + } + + return "SELECT CONSTRAINT_NAME, CONSTRAINT_COLUMNS, REFERENCED_TABLE_NAME, REFERENCED_TABLE_COLUMNS, UPDATE_RULE, DELETE_RULE" . + " FROM DATA_DICTIONARY.FOREIGN_KEYS" . + " WHERE CONSTRAINT_SCHEMA=" . $database . " AND CONSTRAINT_TABLE='" . $table . "'"; + } + + /** + * {@inheritDoc} + */ + public function getListTableIndexesSQL($table, $database = null) + { + if ($database) { + $database = "'" . $database . "'"; + } else { + $database = 'DATABASE()'; + } + + return "SELECT INDEX_NAME AS 'key_name', COLUMN_NAME AS 'column_name', IS_USED_IN_PRIMARY AS 'primary', IS_UNIQUE=0 AS 'non_unique'" . + " FROM DATA_DICTIONARY.INDEX_PARTS" . + " WHERE TABLE_SCHEMA=" . $database . " AND TABLE_NAME='" . $table . "'"; + } + + /** + * {@inheritDoc} + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsInlineColumnComments() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsViews() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function getDropIndexSQL($index, $table=null) + { + if ($index instanceof Index) { + $indexName = $index->getQuotedName($this); + } else if (is_string($index)) { + $indexName = $index; + } else { + throw new \InvalidArgumentException('DrizzlePlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } else if(!is_string($table)) { + throw new \InvalidArgumentException('DrizzlePlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); + } + + if ($index instanceof Index && $index->isPrimary()) { + // drizzle primary keys are always named "PRIMARY", + // so we cannot use them in statements because of them being keyword. + return $this->getDropPrimaryKeySQL($table); + } + + return 'DROP INDEX ' . $indexName . ' ON ' . $table; + } + + /** + * @param Index $index + * @param Table $table + * + * @return string + */ + protected function getDropPrimaryKeySQL($table) + { + return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + { + if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) { + return 'TIMESTAMP'; + } + + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIME'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $columnSql = array(); + $queryParts = array(); + + if ($diff->newName !== false) { + $queryParts[] = 'RENAME TO ' . $diff->newName; + } + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'DROP ' . $column->getQuotedName($this); + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + /* @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */ + $column = $columnDiff->column; + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'CHANGE ' . ($columnDiff->oldColumnName) . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'CHANGE ' . $oldColumnName . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + $sql = array(); + $tableSql = array(); + + if ( ! $this->onSchemaAlterTable($diff, $tableSql)) { + if (count($queryParts) > 0) { + $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(", ", $queryParts); + } + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * {@inheritDoc} + */ + public function getDropTemporaryTableSQL($table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } else if(!is_string($table)) { + throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); + } + + return 'DROP TEMPORARY TABLE ' . $table; + } + + /** + * {@inheritDoc} + */ + public function convertBooleans($item) + { + if (is_array($item)) { + foreach ($item as $key => $value) { + if (is_bool($value) || is_numeric($item)) { + $item[$key] = ($value) ? 'true' : 'false'; + } + } + } else if (is_bool($item) || is_numeric($item)) { + $item = ($item) ? 'true' : 'false'; + } + + return $item; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos == false) { + return 'LOCATE(' . $substr . ', ' . $str . ')'; + } + + return 'LOCATE(' . $substr . ', ' . $str . ', '.$startPos.')'; + } + + /** + * {@inheritDoc} + */ + public function getGuidExpression() + { + return 'UUID()'; + } + + /** + * {@inheritDoc} + */ + public function getRegexpExpression() + { + return 'RLIKE'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php new file mode 100644 index 0000000..77c1c67 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php @@ -0,0 +1,438 @@ +. + */ + + +namespace Doctrine\DBAL\Platforms\Keywords; + +/** + * DB2 Keywords + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + */ +class DB2Keywords extends KeywordList +{ + public function getName() + { + return 'DB2'; + } + + protected function getKeywords() + { + return array( + 'ACTIVATE', + 'ADD', + 'AFTER', + 'ALIAS', + 'ALL', + 'ALLOCATE', + 'DOCUMENT', + 'DOUBLE', + 'DROP', + 'DSSIZE', + 'DYNAMIC', + 'EACH', + 'LOCK', + 'LOCKMAX', + 'LOCKSIZE', + 'LONG', + 'LOOP', + 'MAINTAINED', + 'ROUND_CEILING', + 'ROUND_DOWN', + 'ROUND_FLOOR', + 'ROUND_HALF_DOWN', + 'ROUND_HALF_EVEN', + 'ROUND_HALF_UP', + 'ALLOW', + 'ALTER', + 'AND', + 'ANY', + 'AS', + 'ASENSITIVE', + 'ASSOCIATE', + 'ASUTIME', + 'AT', + 'ATTRIBUTES', + 'AUDIT', + 'AUTHORIZATION', + 'AUX', + 'AUXILIARY', + 'BEFORE', + 'BEGIN', + 'BETWEEN', + 'BINARY', + 'BUFFERPOOL', + 'BY', + 'CACHE', + 'CALL', + 'CALLED', + 'CAPTURE', + 'CARDINALITY', + 'CASCADED', + 'CASE', + 'CAST', + 'CCSID', + 'CHAR', + 'CHARACTER', + 'CHECK', + 'CLONE', + 'CLOSE', + 'CLUSTER', + 'COLLECTION', + 'COLLID', + 'COLUMN', + 'COMMENT', + 'COMMIT', + 'CONCAT', + 'CONDITION', + 'CONNECT', + 'CONNECTION', + 'CONSTRAINT', + 'CONTAINS', + 'CONTINUE', + 'COUNT', + 'COUNT_BIG', + 'CREATE', + 'CROSS', + 'CURRENT', + 'CURRENT_DATE', + 'CURRENT_LC_CTYPE', + 'CURRENT_PATH', + 'CURRENT_SCHEMA', + 'CURRENT_SERVER', + 'CURRENT_TIME', + 'CURRENT_TIMESTAMP', + 'CURRENT_TIMEZONE', + 'CURRENT_USER', + 'CURSOR', + 'CYCLE', + 'DATA', + 'DATABASE', + 'DATAPARTITIONNAME', + 'DATAPARTITIONNUM', + 'EDITPROC', + 'ELSE', + 'ELSEIF', + 'ENABLE', + 'ENCODING', + 'ENCRYPTION', + 'END', + 'END-EXEC', + 'ENDING', + 'ERASE', + 'ESCAPE', + 'EVERY', + 'EXCEPT', + 'EXCEPTION', + 'EXCLUDING', + 'EXCLUSIVE', + 'EXECUTE', + 'EXISTS', + 'EXIT', + 'EXPLAIN', + 'EXTERNAL', + 'EXTRACT', + 'FENCED', + 'FETCH', + 'FIELDPROC', + 'FILE', + 'FINAL', + 'FOR', + 'FOREIGN', + 'FREE', + 'FROM', + 'FULL', + 'FUNCTION', + 'GENERAL', + 'GENERATED', + 'GET', + 'GLOBAL', + 'GO', + 'GOTO', + 'GRANT', + 'GRAPHIC', + 'GROUP', + 'HANDLER', + 'HASH', + 'HASHED_VALUE', + 'HAVING', + 'HINT', + 'HOLD', + 'HOUR', + 'HOURS', + 'IDENTITY', + 'IF', + 'IMMEDIATE', + 'IN', + 'INCLUDING', + 'INCLUSIVE', + 'INCREMENT', + 'INDEX', + 'INDICATOR', + 'INF', + 'INFINITY', + 'INHERIT', + 'INNER', + 'INOUT', + 'INSENSITIVE', + 'INSERT', + 'INTEGRITY', + 'MATERIALIZED', + 'MAXVALUE', + 'MICROSECOND', + 'MICROSECONDS', + 'MINUTE', + 'MINUTES', + 'MINVALUE', + 'MODE', + 'MODIFIES', + 'MONTH', + 'MONTHS', + 'NAN', + 'NEW', + 'NEW_TABLE', + 'NEXTVAL', + 'NO', + 'NOCACHE', + 'NOCYCLE', + 'NODENAME', + 'NODENUMBER', + 'NOMAXVALUE', + 'NOMINVALUE', + 'NONE', + 'NOORDER', + 'NORMALIZED', + 'NOT', + 'NULL', + 'NULLS', + 'NUMPARTS', + 'OBID', + 'OF', + 'OLD', + 'OLD_TABLE', + 'ON', + 'OPEN', + 'OPTIMIZATION', + 'OPTIMIZE', + 'OPTION', + 'OR', + 'ORDER', + 'OUT', + 'OUTER', + 'OVER', + 'OVERRIDING', + 'PACKAGE', + 'PADDED', + 'PAGESIZE', + 'PARAMETER', + 'PART', + 'PARTITION', + 'PARTITIONED', + 'PARTITIONING', + 'PARTITIONS', + 'PASSWORD', + 'PATH', + 'PIECESIZE', + 'PLAN', + 'POSITION', + 'PRECISION', + 'PREPARE', + 'PREVVAL', + 'PRIMARY', + 'PRIQTY', + 'PRIVILEGES', + 'PROCEDURE', + 'PROGRAM', + 'PSID', + 'ROUND_UP', + 'ROUTINE', + 'ROW', + 'ROW_NUMBER', + 'ROWNUMBER', + 'ROWS', + 'ROWSET', + 'RRN', + 'RUN', + 'SAVEPOINT', + 'SCHEMA', + 'SCRATCHPAD', + 'SCROLL', + 'SEARCH', + 'SECOND', + 'SECONDS', + 'SECQTY', + 'SECURITY', + 'SELECT', + 'SENSITIVE', + 'SEQUENCE', + 'SESSION', + 'SESSION_USER', + 'SET', + 'SIGNAL', + 'SIMPLE', + 'SNAN', + 'SOME', + 'SOURCE', + 'SPECIFIC', + 'SQL', + 'SQLID', + 'STACKED', + 'STANDARD', + 'START', + 'STARTING', + 'STATEMENT', + 'STATIC', + 'STATMENT', + 'STAY', + 'STOGROUP', + 'STORES', + 'STYLE', + 'SUBSTRING', + 'SUMMARY', + 'SYNONYM', + 'SYSFUN', + 'SYSIBM', + 'SYSPROC', + 'SYSTEM', + 'SYSTEM_USER', + 'TABLE', + 'TABLESPACE', + 'THEN', + 'TIME', + 'TIMESTAMP', + 'TO', + 'TRANSACTION', + 'TRIGGER', + 'TRIM', + 'TRUNCATE', + 'TYPE', + 'UNDO', + 'UNION', + 'UNIQUE', + 'UNTIL', + 'UPDATE', + 'DATE', + 'DAY', + 'DAYS', + 'DB2GENERAL', + 'DB2GENRL', + 'DB2SQL', + 'DBINFO', + 'DBPARTITIONNAME', + 'DBPARTITIONNUM', + 'DEALLOCATE', + 'DECLARE', + 'DEFAULT', + 'DEFAULTS', + 'DEFINITION', + 'DELETE', + 'DENSE_RANK', + 'DENSERANK', + 'DESCRIBE', + 'DESCRIPTOR', + 'DETERMINISTIC', + 'DIAGNOSTICS', + 'DISABLE', + 'DISALLOW', + 'DISCONNECT', + 'DISTINCT', + 'DO', + 'INTERSECT', + 'PUBLIC', + 'USAGE', + 'INTO', + 'QUERY', + 'USER', + 'IS', + 'QUERYNO', + 'USING', + 'ISOBID', + 'RANGE', + 'VALIDPROC', + 'ISOLATION', + 'RANK', + 'VALUE', + 'ITERATE', + 'READ', + 'VALUES', + 'JAR', + 'READS', + 'VARIABLE', + 'JAVA', + 'RECOVERY', + 'VARIANT', + 'JOIN', + 'REFERENCES', + 'VCAT', + 'KEEP', + 'REFERENCING', + 'VERSION', + 'KEY', + 'REFRESH', + 'VIEW', + 'LABEL', + 'RELEASE', + 'VOLATILE', + 'LANGUAGE', + 'RENAME', + 'VOLUMES', + 'LATERAL', + 'REPEAT', + 'WHEN', + 'LC_CTYPE', + 'RESET', + 'WHENEVER', + 'LEAVE', + 'RESIGNAL', + 'WHERE', + 'LEFT', + 'RESTART', + 'WHILE', + 'LIKE', + 'RESTRICT', + 'WITH', + 'LINKTYPE', + 'RESULT', + 'WITHOUT', + 'LOCAL', + 'RESULT_SET_LOCATOR WLM', + 'LOCALDATE', + 'RETURN', + 'WRITE', + 'LOCALE', + 'RETURNS', + 'XMLELEMENT', + 'LOCALTIME', + 'REVOKE', + 'XMLEXISTS', + 'LOCALTIMESTAMP RIGHT', + 'XMLNAMESPACES', + 'LOCATOR', + 'ROLE', + 'YEAR', + 'LOCATORS', + 'ROLLBACK', + 'YEARS', + ); + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DrizzleKeywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DrizzleKeywords.php new file mode 100644 index 0000000..c6d3187 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/DrizzleKeywords.php @@ -0,0 +1,340 @@ +. + */ + + +namespace Doctrine\DBAL\Platforms\Keywords; + +/** + * Drizzle Keywordlist + * + * @author Kim Hemsø Rasmussen + */ +class DrizzleKeywords extends KeywordList +{ + public function getName() + { + return 'drizzle'; + } + + protected function getKeywords() + { + return array( + 'ABS', + 'ALL', + 'ALLOCATE', + 'ALTER', + 'AND', + 'ANY', + 'ARE', + 'ARRAY', + 'AS', + 'ASENSITIVE', + 'ASYMMETRIC', + 'AT', + 'ATOMIC', + 'AUTHORIZATION', + 'AVG', + 'BEGIN', + 'BETWEEN', + 'BIGINT', + 'BINARY', + 'BLOB', + 'BOOLEAN', + 'BOTH', + 'BY', + 'CALL', + 'CALLED', + 'CARDINALITY', + 'CASCADED', + 'CASE', + 'CAST', + 'CEIL', + 'CEILING', + 'CHAR', + 'CHARACTER', + 'CHARACTER_LENGTH', + 'CHAR_LENGTH', + 'CHECK', + 'CLOB', + 'CLOSE', + 'COALESCE', + 'COLLATE', + 'COLLECT', + 'COLUMN', + 'COMMIT', + 'CONDITION', + 'CONNECT', + 'CONSTRAINT', + 'CONVERT', + 'CORR', + 'CORRESPONDING', + 'COUNT', + 'COVAR_POP', + 'COVAR_SAMP', + 'CREATE', + 'CROSS', + 'CUBE', + 'CUME_DIST', + 'CURRENT', + 'CURRENT_DATE', + 'CURRENT_DEFAULT_TRANSFORM_GROUP', + 'CURRENT_PATH', + 'CURRENT_ROLE', + 'CURRENT_TIME', + 'CURRENT_TIMESTAMP', + 'CURRENT_TRANSFORM_GROUP_FOR_TYPE', + 'CURRENT_USER', + 'CURSOR', + 'CYCLE', + 'DATE', + 'DAY', + 'DEALLOCATE', + 'DEC', + 'DECIMAL', + 'DECLARE', + 'DEFAULT', + 'DELETE', + 'DENSE_RANK', + 'DEREF', + 'DESCRIBE', + 'DETERMINISTIC', + 'DISCONNECT', + 'DISTINCT', + 'DOUBLE', + 'DROP', + 'DYNAMIC', + 'EACH', + 'ELEMENT', + 'ELSE', + 'END', + 'ESCAPE', + 'EVERY', + 'EXCEPT', + 'EXEC', + 'EXECUTE', + 'EXISTS', + 'EXP', + 'EXTERNAL', + 'EXTRACT', + 'FALSE', + 'FETCH', + 'FILTER', + 'FLOAT', + 'FLOOR', + 'FOR', + 'FOREIGN', + 'FREE', + 'FROM', + 'FULL', + 'FUNCTION', + 'FUSION', + 'GET', + 'GLOBAL', + 'GRANT', + 'GROUP', + 'GROUPING', + 'HAVING', + 'HOLD', + 'HOUR', + 'IDENTITY', + 'IN', + 'INDICATOR', + 'INNER', + 'INOUT', + 'INSENSITIVE', + 'INSERT', + 'INT', + 'INTEGER', + 'INTERSECT', + 'INTERSECTION', + 'INTERVAL', + 'INTO', + 'IS', + 'JOIN', + 'LANGUAGE', + 'LARGE', + 'LATERAL', + 'LEADING', + 'LEFT', + 'LIKE', + 'LN', + 'LOCAL', + 'LOCALTIME', + 'LOCALTIMESTAMP', + 'LOWER', + 'MATCH', + 'MAX', + 'MEMBER', + 'MERGE', + 'METHOD', + 'MIN', + 'MINUTE', + 'MOD', + 'MODIFIES', + 'MODULE', + 'MONTH', + 'MULTISET', + 'NATIONAL', + 'NATURAL', + 'NCHAR', + 'NCLOB', + 'NEW', + 'NO', + 'NONE', + 'NORMALIZE', + 'NOT', + 'NULL_SYM', + 'NULLIF', + 'NUMERIC', + 'OCTET_LENGTH', + 'OF', + 'OLD', + 'ON', + 'ONLY', + 'OPEN', + 'OR', + 'ORDER', + 'OUT', + 'OUTER', + 'OVER', + 'OVERLAPS', + 'OVERLAY', + 'PARAMETER', + 'PARTITION', + 'PERCENTILE_CONT', + 'PERCENTILE_DISC', + 'PERCENT_RANK', + 'POSITION', + 'POWER', + 'PRECISION', + 'PREPARE', + 'PRIMARY', + 'PROCEDURE', + 'RANGE', + 'RANK', + 'READS', + 'REAL', + 'RECURSIVE', + 'REF', + 'REFERENCES', + 'REFERENCING', + 'REGR_AVGX', + 'REGR_AVGY', + 'REGR_COUNT', + 'REGR_INTERCEPT', + 'REGR_R2', + 'REGR_SLOPE', + 'REGR_SXX', + 'REGR_SXY', + 'REGR_SYY', + 'RELEASE', + 'RESULT', + 'RETURN', + 'RETURNS', + 'REVOKE', + 'RIGHT', + 'ROLLBACK', + 'ROLLUP', + 'ROW', + 'ROWS', + 'ROW_NUMBER', + 'SAVEPOINT', + 'SCOPE', + 'SCROLL', + 'SEARCH', + 'SECOND', + 'SELECT', + 'SENSITIVE', + 'SESSION_USER', + 'SET', + 'SIMILAR', + 'SMALLINT', + 'SOME', + 'SPECIFIC', + 'SPECIFICTYPE', + 'SQL', + 'SQLEXCEPTION', + 'SQLSTATE', + 'SQLWARNING', + 'SQRT', + 'START', + 'STATIC', + 'STDDEV_POP', + 'STDDEV_SAMP', + 'SUBMULTISET', + 'SUBSTRING', + 'SUM', + 'SYMMETRIC', + 'SYSTEM', + 'SYSTEM_USER', + 'TABLE', + 'TABLESAMPLE', + 'THEN', + 'TIME', + 'TIMESTAMP', + 'TIMEZONE_HOUR', + 'TIMEZONE_MINUTE', + 'TO', + 'TRAILING', + 'TRANSLATE', + 'TRANSLATION', + 'TREAT', + 'TRIGGER', + 'TRIM', + 'TRUE', + 'UESCAPE', + 'UNION', + 'UNIQUE', + 'UNKNOWN', + 'UNNEST', + 'UPDATE', + 'UPPER', + 'USER', + 'USING', + 'VALUE', + 'VALUES', + 'VARCHAR', + 'VARYING', + 'VAR_POP', + 'VAR_SAMP', + 'WHEN', + 'WHENEVER', + 'WHERE', + 'WIDTH_BUCKET', + 'WINDOW', + 'WITH', + 'WITHIN', + 'WITHOUT', + 'XML', + 'XMLAGG', + 'XMLATTRIBUTES', + 'XMLBINARY', + 'XMLCOMMENT', + 'XMLCONCAT', + 'XMLELEMENT', + 'XMLFOREST', + 'XMLNAMESPACES', + 'XMLPARSE', + 'XMLPI', + 'XMLROOT', + 'XMLSERIALIZE', + 'YEAR', + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/KeywordList.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/KeywordList.php new file mode 100644 index 0000000..f30bb36 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/KeywordList.php @@ -0,0 +1,63 @@ +. + */ + + +namespace Doctrine\DBAL\Platforms\Keywords; + +/** + * Abstract interface for a SQL reserved keyword dictionary. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + */ +abstract class KeywordList +{ + private $keywords = null; + + /** + * Check if the given word is a keyword of this dialect/vendor platform. + * + * @param string $word + * @return bool + */ + public function isKeyword($word) + { + if ($this->keywords === null) { + $this->initializeKeywords(); + } + + return isset($this->keywords[strtoupper($word)]); + } + + protected function initializeKeywords() + { + $this->keywords = array_flip(array_map('strtoupper', $this->getKeywords())); + } + + abstract protected function getKeywords(); + + /** + * Name of this keyword list. + * + * @return string + */ + abstract public function getName(); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php new file mode 100644 index 0000000..8adac11 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MsSQLKeywords.php @@ -0,0 +1,243 @@ +. + */ + + +namespace Doctrine\DBAL\Platforms\Keywords; + +/** + * MsSQL Keywordlist + * + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + * @author David Coallier + */ +class MsSQLKeywords extends KeywordList +{ + public function getName() + { + return 'MsSQL'; + } + + protected function getKeywords() + { + return array( + 'ADD', + 'CURRENT_TIMESTAMP', + 'GROUP', + 'OPENQUERY', + 'SERIALIZABLE', + 'ALL', + 'CURRENT_USER', + 'HAVING', + 'OPENROWSET', + 'SESSION_USER', + 'ALTER', + 'CURSOR', + 'HOLDLOCK', + 'OPTION', + 'SET', + 'AND', + 'DATABASE', + 'IDENTITY', + 'OR', + 'SETUSER', + 'ANY', + 'DBCC', + 'IDENTITYCOL', + 'ORDER', + 'SHUTDOWN', + 'AS', + 'DEALLOCATE', + 'IDENTITY_INSERT', + 'OUTER', + 'SOME', + 'ASC', + 'DECLARE', + 'IF', + 'OVER', + 'STATISTICS', + 'AUTHORIZATION', + 'DEFAULT', + 'IN', + 'PERCENT', + 'SUM', + 'AVG', + 'DELETE', + 'INDEX', + 'PERM', + 'SYSTEM_USER', + 'BACKUP', + 'DENY', + 'INNER', + 'PERMANENT', + 'TABLE', + 'BEGIN', + 'DESC', + 'INSERT', + 'PIPE', + 'TAPE', + 'BETWEEN', + 'DISK', + 'INTERSECT', + 'PLAN', + 'TEMP', + 'BREAK', + 'DISTINCT', + 'INTO', + 'PRECISION', + 'TEMPORARY', + 'BROWSE', + 'DISTRIBUTED', + 'IS', + 'PREPARE', + 'TEXTSIZE', + 'BULK', + 'DOUBLE', + 'ISOLATION', + 'PRIMARY', + 'THEN', + 'BY', + 'DROP', + 'JOIN', + 'PRINT', + 'TO', + 'CASCADE', + 'DUMMY', + 'KEY', + 'PRIVILEGES', + 'TOP', + 'CASE', + 'DUMP', + 'KILL', + 'PROC', + 'TRAN', + 'CHECK', + 'ELSE', + 'LEFT', + 'PROCEDURE', + 'TRANSACTION', + 'CHECKPOINT', + 'END', + 'LEVEL', + 'PROCESSEXIT', + 'TRIGGER', + 'CLOSE', + 'ERRLVL', + 'LIKE', + 'PUBLIC', + 'TRUNCATE', + 'CLUSTERED', + 'ERROREXIT', + 'LINENO', + 'RAISERROR', + 'TSEQUAL', + 'COALESCE', + 'ESCAPE', + 'LOAD', + 'READ', + 'UNCOMMITTED', + 'COLUMN', + 'EXCEPT', + 'MAX', + 'READTEXT', + 'UNION', + 'COMMIT', + 'EXEC', + 'MIN', + 'RECONFIGURE', + 'UNIQUE', + 'COMMITTED', + 'EXECUTE', + 'MIRROREXIT', + 'REFERENCES', + 'UPDATE', + 'COMPUTE', + 'EXISTS', + 'NATIONAL', + 'REPEATABLE', + 'UPDATETEXT', + 'CONFIRM', + 'EXIT', + 'NOCHECK', + 'REPLICATION', + 'USE', + 'CONSTRAINT', + 'FETCH', + 'NONCLUSTERED', + 'RESTORE', + 'USER', + 'CONTAINS', + 'FILE', + 'NOT', + 'RESTRICT', + 'VALUES', + 'CONTAINSTABLE', + 'FILLFACTOR', + 'NULL', + 'RETURN', + 'VARYING', + 'CONTINUE', + 'FLOPPY', + 'NULLIF', + 'REVOKE', + 'VIEW', + 'CONTROLROW', + 'FOR', + 'OF', + 'RIGHT', + 'WAITFOR', + 'CONVERT', + 'FOREIGN', + 'OFF', + 'ROLLBACK', + 'WHEN', + 'COUNT', + 'FREETEXT', + 'OFFSETS', + 'ROWCOUNT', + 'WHERE', + 'CREATE', + 'FREETEXTTABLE', + 'ON', + 'ROWGUIDCOL', + 'WHILE', + 'CROSS', + 'FROM', + 'ONCE', + 'RULE', + 'WITH', + 'CURRENT', + 'FULL', + 'ONLY', + 'SAVE', + 'WORK', + 'CURRENT_DATE', + 'GOTO', + 'OPEN', + 'SCHEMA', + 'WRITETEXT', + 'CURRENT_TIME', + 'GRANT', + 'OPENDATASOURCE', + 'SELECT', + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQLKeywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQLKeywords.php new file mode 100644 index 0000000..71704f6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/MySQLKeywords.php @@ -0,0 +1,268 @@ +. + */ + + +namespace Doctrine\DBAL\Platforms\Keywords; + +/** + * MySQL Keywordlist + * + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + * @author David Coallier + */ +class MySQLKeywords extends KeywordList +{ + public function getName() + { + return 'MySQL'; + } + + protected function getKeywords() + { + return array( + 'ADD', + 'ALL', + 'ALTER', + 'ANALYZE', + 'AND', + 'AS', + 'ASC', + 'ASENSITIVE', + 'BEFORE', + 'BETWEEN', + 'BIGINT', + 'BINARY', + 'BLOB', + 'BOTH', + 'BY', + 'CALL', + 'CASCADE', + 'CASE', + 'CHANGE', + 'CHAR', + 'CHARACTER', + 'CHECK', + 'COLLATE', + 'COLUMN', + 'CONDITION', + 'CONNECTION', + 'CONSTRAINT', + 'CONTINUE', + 'CONVERT', + 'CREATE', + 'CROSS', + 'CURRENT_DATE', + 'CURRENT_TIME', + 'CURRENT_TIMESTAMP', + 'CURRENT_USER', + 'CURSOR', + 'DATABASE', + 'DATABASES', + 'DAY_HOUR', + 'DAY_MICROSECOND', + 'DAY_MINUTE', + 'DAY_SECOND', + 'DEC', + 'DECIMAL', + 'DECLARE', + 'DEFAULT', + 'DELAYED', + 'DELETE', + 'DESC', + 'DESCRIBE', + 'DETERMINISTIC', + 'DISTINCT', + 'DISTINCTROW', + 'DIV', + 'DOUBLE', + 'DROP', + 'DUAL', + 'EACH', + 'ELSE', + 'ELSEIF', + 'ENCLOSED', + 'ESCAPED', + 'EXISTS', + 'EXIT', + 'EXPLAIN', + 'FALSE', + 'FETCH', + 'FLOAT', + 'FLOAT4', + 'FLOAT8', + 'FOR', + 'FORCE', + 'FOREIGN', + 'FROM', + 'FULLTEXT', + 'GOTO', + 'GRANT', + 'GROUP', + 'HAVING', + 'HIGH_PRIORITY', + 'HOUR_MICROSECOND', + 'HOUR_MINUTE', + 'HOUR_SECOND', + 'IF', + 'IGNORE', + 'IN', + 'INDEX', + 'INFILE', + 'INNER', + 'INOUT', + 'INSENSITIVE', + 'INSERT', + 'INT', + 'INT1', + 'INT2', + 'INT3', + 'INT4', + 'INT8', + 'INTEGER', + 'INTERVAL', + 'INTO', + 'IS', + 'ITERATE', + 'JOIN', + 'KEY', + 'KEYS', + 'KILL', + 'LABEL', + 'LEADING', + 'LEAVE', + 'LEFT', + 'LIKE', + 'LIMIT', + 'LINES', + 'LOAD', + 'LOCALTIME', + 'LOCALTIMESTAMP', + 'LOCK', + 'LONG', + 'LONGBLOB', + 'LONGTEXT', + 'LOOP', + 'LOW_PRIORITY', + 'MATCH', + 'MEDIUMBLOB', + 'MEDIUMINT', + 'MEDIUMTEXT', + 'MIDDLEINT', + 'MINUTE_MICROSECOND', + 'MINUTE_SECOND', + 'MOD', + 'MODIFIES', + 'NATURAL', + 'NOT', + 'NO_WRITE_TO_BINLOG', + 'NULL', + 'NUMERIC', + 'ON', + 'OPTIMIZE', + 'OPTION', + 'OPTIONALLY', + 'OR', + 'ORDER', + 'OUT', + 'OUTER', + 'OUTFILE', + 'PRECISION', + 'PRIMARY', + 'PROCEDURE', + 'PURGE', + 'RAID0', + 'READ', + 'READS', + 'REAL', + 'REFERENCES', + 'REGEXP', + 'RELEASE', + 'RENAME', + 'REPEAT', + 'REPLACE', + 'REQUIRE', + 'RESTRICT', + 'RETURN', + 'REVOKE', + 'RIGHT', + 'RLIKE', + 'SCHEMA', + 'SCHEMAS', + 'SECOND_MICROSECOND', + 'SELECT', + 'SENSITIVE', + 'SEPARATOR', + 'SET', + 'SHOW', + 'SMALLINT', + 'SONAME', + 'SPATIAL', + 'SPECIFIC', + 'SQL', + 'SQLEXCEPTION', + 'SQLSTATE', + 'SQLWARNING', + 'SQL_BIG_RESULT', + 'SQL_CALC_FOUND_ROWS', + 'SQL_SMALL_RESULT', + 'SSL', + 'STARTING', + 'STRAIGHT_JOIN', + 'TABLE', + 'TERMINATED', + 'THEN', + 'TINYBLOB', + 'TINYINT', + 'TINYTEXT', + 'TO', + 'TRAILING', + 'TRIGGER', + 'TRUE', + 'UNDO', + 'UNION', + 'UNIQUE', + 'UNLOCK', + 'UNSIGNED', + 'UPDATE', + 'USAGE', + 'USE', + 'USING', + 'UTC_DATE', + 'UTC_TIME', + 'UTC_TIMESTAMP', + 'VALUES', + 'VARBINARY', + 'VARCHAR', + 'VARCHARACTER', + 'VARYING', + 'WHEN', + 'WHERE', + 'WHILE', + 'WITH', + 'WRITE', + 'X509', + 'XOR', + 'YEAR_MONTH', + 'ZEROFILL', + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php new file mode 100644 index 0000000..525286e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/OracleKeywords.php @@ -0,0 +1,156 @@ +. + */ + + +namespace Doctrine\DBAL\Platforms\Keywords; + +/** + * Oracle Keywordlist + * + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + * @author David Coallier + */ +class OracleKeywords extends KeywordList +{ + public function getName() + { + return 'Oracle'; + } + + protected function getKeywords() + { + return array( + 'ACCESS', + 'ELSE', + 'MODIFY', + 'START', + 'ADD', + 'EXCLUSIVE', + 'NOAUDIT', + 'SELECT', + 'ALL', + 'EXISTS', + 'NOCOMPRESS', + 'SESSION', + 'ALTER', + 'FILE', + 'NOT', + 'SET', + 'AND', + 'FLOAT', + 'NOTFOUND ', + 'SHARE', + 'ANY', + 'FOR', + 'NOWAIT', + 'SIZE', + 'ARRAYLEN', + 'FROM', + 'NULL', + 'SMALLINT', + 'AS', + 'GRANT', + 'NUMBER', + 'SQLBUF', + 'ASC', + 'GROUP', + 'OF', + 'SUCCESSFUL', + 'AUDIT', + 'HAVING', + 'OFFLINE ', + 'SYNONYM', + 'BETWEEN', + 'IDENTIFIED', + 'ON', + 'SYSDATE', + 'BY', + 'IMMEDIATE', + 'ONLINE', + 'TABLE', + 'CHAR', + 'IN', + 'OPTION', + 'THEN', + 'CHECK', + 'INCREMENT', + 'OR', + 'TO', + 'CLUSTER', + 'INDEX', + 'ORDER', + 'TRIGGER', + 'COLUMN', + 'INITIAL', + 'PCTFREE', + 'UID', + 'COMMENT', + 'INSERT', + 'PRIOR', + 'UNION', + 'COMPRESS', + 'INTEGER', + 'PRIVILEGES', + 'UNIQUE', + 'CONNECT', + 'INTERSECT', + 'PUBLIC', + 'UPDATE', + 'CREATE', + 'INTO', + 'RAW', + 'USER', + 'CURRENT', + 'IS', + 'RENAME', + 'VALIDATE', + 'DATE', + 'LEVEL', + 'RESOURCE', + 'VALUES', + 'DECIMAL', + 'LIKE', + 'REVOKE', + 'VARCHAR', + 'DEFAULT', + 'LOCK', + 'ROW', + 'VARCHAR2', + 'DELETE', + 'LONG', + 'ROWID', + 'VIEW', + 'DESC', + 'MAXEXTENTS', + 'ROWLABEL', + 'WHENEVER', + 'DISTINCT', + 'MINUS', + 'ROWNUM', + 'WHERE', + 'DROP', + 'MODE', + 'ROWS', + 'WITH', + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQLKeywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQLKeywords.php new file mode 100644 index 0000000..7950f6a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/PostgreSQLKeywords.php @@ -0,0 +1,131 @@ +. + */ + + +namespace Doctrine\DBAL\Platforms\Keywords; + +/** + * PostgreSQL Keywordlist + * + * @license BSD http://www.opensource.org/licenses/bsd-license.php + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + * @author Marcelo Santos Araujo + */ +class PostgreSQLKeywords extends KeywordList +{ + public function getName() + { + return 'PostgreSQL'; + } + + protected function getKeywords() + { + return array( + 'ALL', + 'ANALYSE', + 'ANALYZE', + 'AND', + 'ANY', + 'AS', + 'ASC', + 'AUTHORIZATION', + 'BETWEEN', + 'BINARY', + 'BOTH', + 'CASE', + 'CAST', + 'CHECK', + 'COLLATE', + 'COLUMN', + 'CONSTRAINT', + 'CREATE', + 'CURRENT_DATE', + 'CURRENT_TIME', + 'CURRENT_TIMESTAMP', + 'CURRENT_USER', + 'DEFAULT', + 'DEFERRABLE', + 'DESC', + 'DISTINCT', + 'DO', + 'ELSE', + 'END', + 'EXCEPT', + 'FALSE', + 'FOR', + 'FOREIGN', + 'FREEZE', + 'FROM', + 'FULL', + 'GRANT', + 'GROUP', + 'HAVING', + 'ILIKE', + 'IN', + 'INITIALLY', + 'INNER', + 'INTERSECT', + 'INTO', + 'IS', + 'ISNULL', + 'JOIN', + 'LEADING', + 'LEFT', + 'LIKE', + 'LIMIT', + 'LOCALTIME', + 'LOCALTIMESTAMP', + 'NATURAL', + 'NEW', + 'NOT', + 'NOTNULL', + 'NULL', + 'OFF', + 'OFFSET', + 'OLD', + 'ON', + 'ONLY', + 'OR', + 'ORDER', + 'OUTER', + 'OVERLAPS', + 'PLACING', + 'PRIMARY', + 'REFERENCES', + 'SELECT', + 'SESSION_USER', + 'SIMILAR', + 'SOME', + 'TABLE', + 'THEN', + 'TO', + 'TRAILING', + 'TRUE', + 'UNION', + 'UNIQUE', + 'USER', + 'USING', + 'VERBOSE', + 'WHEN', + 'WHERE' + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/ReservedKeywordsValidator.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/ReservedKeywordsValidator.php new file mode 100644 index 0000000..a61922b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/ReservedKeywordsValidator.php @@ -0,0 +1,116 @@ +. + */ + + +namespace Doctrine\DBAL\Platforms\Keywords; + +use Doctrine\DBAL\Schema\Visitor\Visitor; +use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Schema\Column; +use Doctrine\DBAL\Schema\ForeignKeyConstraint; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Schema\Sequence; +use Doctrine\DBAL\Schema\Index; + +class ReservedKeywordsValidator implements Visitor +{ + /** + * @var KeywordList[] + */ + private $keywordLists = array(); + + /** + * @var array + */ + private $violations = array(); + + public function __construct(array $keywordLists) + { + $this->keywordLists = $keywordLists; + } + + public function getViolations() + { + return $this->violations; + } + + /** + * @param string $word + * @return array + */ + private function isReservedWord($word) + { + if ($word[0] == "`") { + $word = str_replace('`', '', $word); + } + + $keywordLists = array(); + foreach ($this->keywordLists as $keywordList) { + if ($keywordList->isKeyword($word)) { + $keywordLists[] = $keywordList->getName(); + } + } + return $keywordLists; + } + + private function addViolation($asset, $violatedPlatforms) + { + if ( ! $violatedPlatforms) { + return; + } + + $this->violations[] = $asset . ' keyword violations: ' . implode(', ', $violatedPlatforms); + } + + public function acceptColumn(Table $table, Column $column) + { + $this->addViolation( + 'Table ' . $table->getName() . ' column ' . $column->getName(), + $this->isReservedWord($column->getName()) + ); + } + + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + + } + + public function acceptIndex(Table $table, Index $index) + { + + } + + public function acceptSchema(Schema $schema) + { + + } + + public function acceptSequence(Sequence $sequence) + { + + } + + public function acceptTable(Table $table) + { + $this->addViolation( + 'Table ' . $table->getName(), + $this->isReservedWord($table->getName()) + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLiteKeywords.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLiteKeywords.php new file mode 100644 index 0000000..d45b994 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/Keywords/SQLiteKeywords.php @@ -0,0 +1,164 @@ +. + */ + + +namespace Doctrine\DBAL\Platforms\Keywords; + +/** + * SQLite Keywords + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + */ +class SQLiteKeywords extends KeywordList +{ + public function getName() + { + return 'SQLite'; + } + + protected function getKeywords() + { + return array( + 'ABORT', + 'ACTION', + 'ADD', + 'AFTER', + 'ALL', + 'ALTER', + 'ANALYZE', + 'AND', + 'AS', + 'ASC', + 'ATTACH', + 'AUTOINCREMENT', + 'BEFORE', + 'BEGIN', + 'BETWEEN', + 'BY', + 'CASCADE', + 'CASE', + 'CAST', + 'CHECK', + 'COLLATE', + 'COLUMN', + 'COMMIT', + 'CONFLICT', + 'CONSTRAINT', + 'CREATE', + 'CROSS', + 'CURRENT_DATE', + 'CURRENT_TIME', + 'CURRENT_TIMESTAMP', + 'DATABASE', + 'DEFAULT', + 'DEFERRABLE', + 'DEFERRED', + 'DELETE', + 'DESC', + 'DETACH', + 'DISTINCT', + 'DROP', + 'EACH', + 'ELSE', + 'END', + 'ESCAPE', + 'EXCEPT', + 'EXCLUSIVE', + 'EXISTS', + 'EXPLAIN', + 'FAIL', + 'FOR', + 'FOREIGN', + 'FROM', + 'FULL', + 'GLOB', + 'GROUP', + 'HAVING', + 'IF', + 'IGNORE', + 'IMMEDIATE', + 'IN', + 'INDEX', + 'INDEXED', + 'INITIALLY', + 'INNER', + 'INSERT', + 'INSTEAD', + 'INTERSECT', + 'INTO', + 'IS', + 'ISNULL', + 'JOIN', + 'KEY', + 'LEFT', + 'LIKE', + 'LIMIT', + 'MATCH', + 'NATURAL', + 'NO', + 'NOT', + 'NOTNULL', + 'NULL', + 'OF', + 'OFFSET', + 'ON', + 'OR', + 'ORDER', + 'OUTER', + 'PLAN', + 'PRAGMA', + 'PRIMARY', + 'QUERY', + 'RAISE', + 'REFERENCES', + 'REGEXP', + 'REINDEX', + 'RELEASE', + 'RENAME', + 'REPLACE', + 'RESTRICT', + 'RIGHT', + 'ROLLBACK', + 'ROW', + 'SAVEPOINT', + 'SELECT', + 'SET', + 'TABLE', + 'TEMP', + 'TEMPORARY', + 'THEN', + 'TO', + 'TRANSACTION', + 'TRIGGER', + 'UNION', + 'UNIQUE', + 'UPDATE', + 'USING', + 'VACUUM', + 'VALUES', + 'VIEW', + 'VIRTUAL', + 'WHEN', + 'WHERE' + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php new file mode 100644 index 0000000..d803589 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -0,0 +1,720 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\DBALException, + Doctrine\DBAL\Schema\TableDiff, + Doctrine\DBAL\Schema\Index, + Doctrine\DBAL\Schema\Table; + +/** + * The MySqlPlatform provides the behavior, features and SQL dialect of the + * MySQL database platform. This platform represents a MySQL 5.0 or greater platform that + * uses the InnoDB storage engine. + * + * @since 2.0 + * @author Roman Borschel + * @author Benjamin Eberlei + * @todo Rename: MySQLPlatform + */ +class MySqlPlatform extends AbstractPlatform +{ + /** + * {@inheritDoc} + */ + public function getIdentifierQuoteCharacter() + { + return '`'; + } + + /** + * {@inheritDoc} + */ + public function getRegexpExpression() + { + return 'RLIKE'; + } + + /** + * {@inheritDoc} + */ + public function getGuidExpression() + { + return 'UUID()'; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos == false) { + return 'LOCATE(' . $substr . ', ' . $str . ')'; + } + + return 'LOCATE(' . $substr . ', ' . $str . ', '.$startPos.')'; + } + + /** + * {@inheritDoc} + */ + public function getConcatExpression() + { + $args = func_get_args(); + return 'CONCAT(' . join(', ', (array) $args) . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return 'DATEDIFF(' . $date1 . ', ' . $date2 . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateAddDaysExpression($date, $days) + { + return 'DATE_ADD(' . $date . ', INTERVAL ' . $days . ' DAY)'; + } + + /** + * {@inheritDoc} + */ + public function getDateSubDaysExpression($date, $days) + { + return 'DATE_SUB(' . $date . ', INTERVAL ' . $days . ' DAY)'; + } + + /** + * {@inheritDoc} + */ + public function getDateAddMonthExpression($date, $months) + { + return 'DATE_ADD(' . $date . ', INTERVAL ' . $months . ' MONTH)'; + } + + /** + * {@inheritDoc} + */ + public function getDateSubMonthExpression($date, $months) + { + return 'DATE_SUB(' . $date . ', INTERVAL ' . $months . ' MONTH)'; + } + + public function getListDatabasesSQL() + { + return 'SHOW DATABASES'; + } + + public function getListTableConstraintsSQL($table) + { + return 'SHOW INDEX FROM ' . $table; + } + + /** + * {@inheritDoc} + * + * Two approaches to listing the table indexes. The information_schema is + * preferred, because it doesn't cause problems with SQL keywords such as "order" or "table". + * + * @param string $table + * @param string $currentDatabase + * @return string + */ + public function getListTableIndexesSQL($table, $currentDatabase = null) + { + if ($currentDatabase) { + return "SELECT TABLE_NAME AS `Table`, NON_UNIQUE AS Non_Unique, INDEX_NAME AS Key_name, ". + "SEQ_IN_INDEX AS Seq_in_index, COLUMN_NAME AS Column_Name, COLLATION AS Collation, ". + "CARDINALITY AS Cardinality, SUB_PART AS Sub_Part, PACKED AS Packed, " . + "NULLABLE AS `Null`, INDEX_TYPE AS Index_Type, COMMENT AS Comment " . + "FROM information_schema.STATISTICS WHERE TABLE_NAME = '" . $table . "' AND TABLE_SCHEMA = '" . $currentDatabase . "'"; + } + + return 'SHOW INDEX FROM ' . $table; + } + + public function getListViewsSQL($database) + { + return "SELECT * FROM information_schema.VIEWS WHERE TABLE_SCHEMA = '".$database."'"; + } + + public function getListTableForeignKeysSQL($table, $database = null) + { + $sql = "SELECT DISTINCT k.`CONSTRAINT_NAME`, k.`COLUMN_NAME`, k.`REFERENCED_TABLE_NAME`, ". + "k.`REFERENCED_COLUMN_NAME` /*!50116 , c.update_rule, c.delete_rule */ ". + "FROM information_schema.key_column_usage k /*!50116 ". + "INNER JOIN information_schema.referential_constraints c ON ". + " c.constraint_name = k.constraint_name AND ". + " c.table_name = '$table' */ WHERE k.table_name = '$table'"; + + if ($database) { + $sql .= " AND k.table_schema = '$database' /*!50116 AND c.constraint_schema = '$database' */"; + } + + $sql .= " AND k.`REFERENCED_COLUMN_NAME` is not NULL"; + + return $sql; + } + + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + public function getDropViewSQL($name) + { + return 'DROP VIEW '. $name; + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $field) + { + if ( ! empty($field['length']) && is_numeric($field['length'])) { + $length = $field['length']; + if ($length <= 255) { + return 'TINYTEXT'; + } + + if ($length <= 65532) { + return 'TEXT'; + } + + if ($length <= 16777215) { + return 'MEDIUMTEXT'; + } + } + + return 'LONGTEXT'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + { + if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] == true) { + return 'TIMESTAMP'; + } + + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIME'; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $field) + { + return 'TINYINT(1)'; + } + + /** + * Obtain DBMS specific SQL code portion needed to set the COLLATION + * of a field declaration to be used in statements like CREATE TABLE. + * + * @param string $collation name of the collation + * + * @return string DBMS specific SQL code portion needed to set the COLLATION + * of a field declaration. + */ + public function getCollationFieldDeclaration($collation) + { + return 'COLLATE ' . $collation; + } + + /** + * {@inheritDoc} + * + * MySql prefers "autoincrement" identity columns since sequences can only + * be emulated with a table. + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + * + * MySql supports this through AUTO_INCREMENT columns. + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsInlineColumnComments() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getShowDatabasesSQL() + { + return 'SHOW DATABASES'; + } + + public function getListTablesSQL() + { + return "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"; + } + + public function getListTableColumnsSQL($table, $database = null) + { + if ($database) { + return "SELECT COLUMN_NAME AS Field, COLUMN_TYPE AS Type, IS_NULLABLE AS `Null`, ". + "COLUMN_KEY AS `Key`, COLUMN_DEFAULT AS `Default`, EXTRA AS Extra, COLUMN_COMMENT AS Comment, " . + "CHARACTER_SET_NAME AS CharacterSet, COLLATION_NAME AS CollactionName ". + "FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '" . $database . "' AND TABLE_NAME = '" . $table . "'"; + } + + return 'DESCRIBE ' . $table; + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($name) + { + return 'DROP DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($tableName, array $columns, array $options = array()) + { + $queryFields = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { + foreach ($options['uniqueConstraints'] as $index => $definition) { + $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); + } + } + + // add all indexes + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach($options['indexes'] as $index => $definition) { + $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition); + } + } + + // attach all primary keys + if (isset($options['primary']) && ! empty($options['primary'])) { + $keyColumns = array_unique(array_values($options['primary'])); + $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; + } + + $query = 'CREATE '; + if (!empty($options['temporary'])) { + $query .= 'TEMPORARY '; + } + $query .= 'TABLE ' . $tableName . ' (' . $queryFields . ') '; + + if (isset($options['comment'])) { + $query .= 'COMMENT = ' . $options['comment'] . ' '; + } + + if ( ! isset($options['charset'])) { + $options['charset'] = 'utf8'; + } + + if ( ! isset($options['collate'])) { + $options['collate'] = 'utf8_unicode_ci'; + } + + $query .= 'DEFAULT CHARACTER SET ' . $options['charset']; + $query .= ' COLLATE ' . $options['collate']; + + if ( ! isset($options['engine'])) { + $options['engine'] = 'InnoDB'; + } + $query .= ' ENGINE = ' . $options['engine']; + + $sql[] = $query; + + if (isset($options['foreignKeys'])) { + foreach ((array) $options['foreignKeys'] as $definition) { + $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); + } + } + + return $sql; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $columnSql = array(); + $queryParts = array(); + if ($diff->newName !== false) { + $queryParts[] = 'RENAME TO ' . $diff->newName; + } + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'DROP ' . $column->getQuotedName($this); + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + /* @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */ + $column = $columnDiff->column; + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'CHANGE ' . ($columnDiff->oldColumnName) . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $columnArray = $column->toArray(); + $columnArray['comment'] = $this->getColumnComment($column); + $queryParts[] = 'CHANGE ' . $oldColumnName . ' ' + . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); + } + + $sql = array(); + $tableSql = array(); + + if ( ! $this->onSchemaAlterTable($diff, $tableSql)) { + if (count($queryParts) > 0) { + $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . implode(", ", $queryParts); + } + $sql = array_merge( + $this->getPreAlterTableIndexForeignKeySQL($diff), + $sql, + $this->getPostAlterTableIndexForeignKeySQL($diff) + ); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * {@inheritDoc} + */ + protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) + { + $sql = array(); + $table = $diff->name; + + foreach ($diff->removedIndexes as $remKey => $remIndex) { + + foreach ($diff->addedIndexes as $addKey => $addIndex) { + if ($remIndex->getColumns() == $addIndex->getColumns()) { + + $columns = $addIndex->getColumns(); + $type = ''; + if ($addIndex->isUnique()) { + $type = 'UNIQUE '; + } + + $query = 'ALTER TABLE ' . $table . ' DROP INDEX ' . $remIndex->getName() . ', '; + $query .= 'ADD ' . $type . 'INDEX ' . $addIndex->getName(); + $query .= ' (' . $this->getIndexFieldDeclarationListSQL($columns) . ')'; + + $sql[] = $query; + + unset($diff->removedIndexes[$remKey]); + unset($diff->addedIndexes[$addKey]); + + break; + } + } + } + + $sql = array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff)); + + return $sql; + } + + /** + * {@inheritDoc} + */ + protected function getCreateIndexSQLFlags(Index $index) + { + $type = ''; + if ($index->isUnique()) { + $type .= 'UNIQUE '; + } else if ($index->hasFlag('fulltext')) { + $type .= 'FULLTEXT '; + } + + return $type; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $field) + { + return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $field) + { + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $field) + { + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + { + $autoinc = ''; + if ( ! empty($columnDef['autoincrement'])) { + $autoinc = ' AUTO_INCREMENT'; + } + $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : ''; + + return $unsigned . $autoinc; + } + + /** + * {@inheritDoc} + */ + public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey) + { + $query = ''; + if ($foreignKey->hasOption('match')) { + $query .= ' MATCH ' . $foreignKey->getOption('match'); + } + $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey); + return $query; + } + + /** + * {@inheritDoc} + */ + public function getDropIndexSQL($index, $table=null) + { + if ($index instanceof Index) { + $indexName = $index->getQuotedName($this); + } else if(is_string($index)) { + $indexName = $index; + } else { + throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } else if(!is_string($table)) { + throw new \InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); + } + + if ($index instanceof Index && $index->isPrimary()) { + // mysql primary keys are always named "PRIMARY", + // so we cannot use them in statements because of them being keyword. + return $this->getDropPrimaryKeySQL($table); + } + + return 'DROP INDEX ' . $indexName . ' ON ' . $table; + } + + /** + * @param string $table + * + * @return string + */ + protected function getDropPrimaryKeySQL($table) + { + return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; + } + + /** + * {@inheritDoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'mysql'; + } + + /** + * {@inheritDoc} + */ + public function getReadLockSQL() + { + return 'LOCK IN SHARE MODE'; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = array( + 'tinyint' => 'boolean', + 'smallint' => 'smallint', + 'mediumint' => 'integer', + 'int' => 'integer', + 'integer' => 'integer', + 'bigint' => 'bigint', + 'tinytext' => 'text', + 'mediumtext' => 'text', + 'longtext' => 'text', + 'text' => 'text', + 'varchar' => 'string', + 'string' => 'string', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'timestamp' => 'datetime', + 'time' => 'time', + 'float' => 'float', + 'double' => 'float', + 'real' => 'float', + 'decimal' => 'decimal', + 'numeric' => 'decimal', + 'year' => 'date', + 'longblob' => 'blob', + 'blob' => 'blob', + 'mediumblob' => 'blob', + 'tinyblob' => 'blob', + 'binary' => 'blob', + 'varbinary' => 'blob', + 'set' => 'simple_array', + ); + } + + /** + * {@inheritDoc} + */ + public function getVarcharMaxLength() + { + return 65535; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return 'Doctrine\DBAL\Platforms\Keywords\MySQLKeywords'; + } + + /** + * {@inheritDoc} + * + * MySQL commits a transaction implicitly when DROP TABLE is executed, however not + * if DROP TEMPORARY TABLE is executed. + */ + public function getDropTemporaryTableSQL($table) + { + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } else if(!is_string($table)) { + throw new \InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); + } + + return 'DROP TEMPORARY TABLE ' . $table; + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $field) + { + return 'LONGBLOB'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php new file mode 100644 index 0000000..cd5c774 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/OraclePlatform.php @@ -0,0 +1,822 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\Schema\ForeignKeyConstraint; +use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\Sequence; +use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Schema\TableDiff; +use Doctrine\DBAL\DBALException; + +/** + * OraclePlatform. + * + * @since 2.0 + * @author Roman Borschel + * @author Lukas Smith (PEAR MDB2 library) + * @author Benjamin Eberlei + */ +class OraclePlatform extends AbstractPlatform +{ + /** + * Assertion for Oracle identifiers + * + * @link http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements008.htm + * + * @param string + * + * @throws DBALException + */ + static public function assertValidIdentifier($identifier) + { + if ( ! preg_match('(^(([a-zA-Z]{1}[a-zA-Z0-9_$#]{0,})|("[^"]+"))$)', $identifier)) { + throw new DBALException("Invalid Oracle identifier"); + } + } + + /** + * {@inheritDoc} + */ + public function getSubstringExpression($value, $position, $length = null) + { + if ($length !== null) { + return "SUBSTR($value, $position, $length)"; + } + + return "SUBSTR($value, $position)"; + } + + /** + * {@inheritDoc} + */ + public function getNowExpression($type = 'timestamp') + { + switch ($type) { + case 'date': + case 'time': + case 'timestamp': + default: + return 'TO_CHAR(CURRENT_TIMESTAMP, \'YYYY-MM-DD HH24:MI:SS\')'; + } + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos == false) { + return 'INSTR('.$str.', '.$substr.')'; + } + + return 'INSTR('.$str.', '.$substr.', '.$startPos.')'; + } + + /** + * {@inheritDoc} + */ + public function getGuidExpression() + { + return 'SYS_GUID()'; + } + + /** + * {@inheritDoc} + * + * Note: Since Oracle timestamp differences are calculated down to the microsecond we have to truncate + * them to the difference in days. This is obviously a restriction of the original functionality, but we + * need to make this a portable function. + */ + public function getDateDiffExpression($date1, $date2) + { + return "TRUNC(TO_NUMBER(SUBSTR((" . $date1 . "-" . $date2 . "), 1, INSTR(" . $date1 . "-" . $date2 .", ' '))))"; + } + + /** + * {@inheritDoc} + */ + public function getDateAddDaysExpression($date, $days) + { + return '(' . $date . '+' . $days . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateSubDaysExpression($date, $days) + { + return '(' . $date . '-' . $days . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateAddMonthExpression($date, $months) + { + return "ADD_MONTHS(" . $date . ", " . $months . ")"; + } + + /** + * {@inheritDoc} + */ + public function getDateSubMonthExpression($date, $months) + { + return "ADD_MONTHS(" . $date . ", -" . $months . ")"; + } + + /** + * {@inheritDoc} + */ + public function getBitAndComparisonExpression($value1, $value2) + { + return 'BITAND('.$value1 . ', ' . $value2 . ')'; + } + + /** + * {@inheritDoc} + */ + public function getBitOrComparisonExpression($value1, $value2) + { + return '(' . $value1 . '-' . + $this->getBitAndComparisonExpression($value1, $value2) + . '+' . $value2 . ')'; + } + + /** + * {@inheritDoc} + * + * Need to specifiy minvalue, since start with is hidden in the system and MINVALUE <= START WITH. + * Therefore we can use MINVALUE to be able to get a hint what START WITH was for later introspection + * in {@see listSequences()} + */ + public function getCreateSequenceSQL(Sequence $sequence) + { + return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . + ' START WITH ' . $sequence->getInitialValue() . + ' MINVALUE ' . $sequence->getInitialValue() . + ' INCREMENT BY ' . $sequence->getAllocationSize(); + } + + /** + * {@inheritDoc} + */ + public function getAlterSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence) + { + return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize(); + } + + /** + * {@inheritDoc} + */ + public function getSequenceNextValSQL($sequenceName) + { + return 'SELECT ' . $sequenceName . '.nextval FROM DUAL'; + } + + /** + * {@inheritDoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + protected function _getTransactionIsolationLevelSQL($level) + { + switch ($level) { + case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED: + return 'READ UNCOMMITTED'; + case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED: + return 'READ COMMITTED'; + case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ: + case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE: + return 'SERIALIZABLE'; + default: + return parent::_getTransactionIsolationLevelSQL($level); + } + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $field) + { + return 'NUMBER(1)'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $field) + { + return 'NUMBER(10)'; + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $field) + { + return 'NUMBER(20)'; + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $field) + { + return 'NUMBER(5)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIMESTAMP(0)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIMESTAMP(0) WITH TIME ZONE'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + { + return ''; + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(2000)') + : ($length ? 'VARCHAR2(' . $length . ')' : 'VARCHAR2(4000)'); + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $field) + { + return 'CLOB'; + } + + public function getListDatabasesSQL() + { + return 'SELECT username FROM all_users'; + } + + public function getListSequencesSQL($database) + { + return "SELECT sequence_name, min_value, increment_by FROM sys.all_sequences ". + "WHERE SEQUENCE_OWNER = '".strtoupper($database)."'"; + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($table, array $columns, array $options = array()) + { + $indexes = isset($options['indexes']) ? $options['indexes'] : array(); + $options['indexes'] = array(); + $sql = parent::_getCreateTableSQL($table, $columns, $options); + + foreach ($columns as $name => $column) { + if (isset($column['sequence'])) { + $sql[] = $this->getCreateSequenceSQL($column['sequence'], 1); + } + + if (isset($column['autoincrement']) && $column['autoincrement'] || + (isset($column['autoinc']) && $column['autoinc'])) { + $sql = array_merge($sql, $this->getCreateAutoincrementSql($name, $table)); + } + } + + if (isset($indexes) && ! empty($indexes)) { + foreach ($indexes as $index) { + $sql[] = $this->getCreateIndexSQL($index, $table); + } + } + + return $sql; + } + + /** + * {@inheritDoc} + * + * @license New BSD License + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaOracleReader.html + */ + public function getListTableIndexesSQL($table, $currentDatabase = null) + { + $table = strtoupper($table); + + return "SELECT uind.index_name AS name, " . + " uind.index_type AS type, " . + " decode( uind.uniqueness, 'NONUNIQUE', 0, 'UNIQUE', 1 ) AS is_unique, " . + " uind_col.column_name AS column_name, " . + " uind_col.column_position AS column_pos, " . + " (SELECT ucon.constraint_type FROM user_constraints ucon WHERE ucon.constraint_name = uind.index_name) AS is_primary ". + "FROM user_indexes uind, user_ind_columns uind_col " . + "WHERE uind.index_name = uind_col.index_name AND uind_col.table_name = '$table' ORDER BY uind_col.column_position ASC"; + } + + public function getListTablesSQL() + { + return 'SELECT * FROM sys.user_tables'; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return 'SELECT view_name, text FROM sys.user_views'; + } + + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + public function getDropViewSQL($name) + { + return 'DROP VIEW '. $name; + } + + public function getCreateAutoincrementSql($name, $table, $start = 1) + { + $table = strtoupper($table); + $sql = array(); + + $indexName = $table . '_AI_PK'; + + $idx = new Index($indexName, array($name), true, true); + + $sql[] = 'DECLARE + constraints_Count NUMBER; +BEGIN + SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = \''.$table.'\' AND CONSTRAINT_TYPE = \'P\'; + IF constraints_Count = 0 OR constraints_Count = \'\' THEN + EXECUTE IMMEDIATE \''.$this->getCreateConstraintSQL($idx, $table).'\'; + END IF; +END;'; + + $sequenceName = $table . '_SEQ'; + $sequence = new Sequence($sequenceName, $start); + $sql[] = $this->getCreateSequenceSQL($sequence); + + $triggerName = $table . '_AI_PK'; + $sql[] = 'CREATE TRIGGER ' . $triggerName . ' + BEFORE INSERT + ON ' . $table . ' + FOR EACH ROW +DECLARE + last_Sequence NUMBER; + last_InsertID NUMBER; +BEGIN + SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL; + IF (:NEW.' . $name . ' IS NULL OR :NEW.'.$name.' = 0) THEN + SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $name . ' FROM DUAL; + ELSE + SELECT NVL(Last_Number, 0) INTO last_Sequence + FROM User_Sequences + WHERE Sequence_Name = \'' . $sequenceName . '\'; + SELECT :NEW.' . $name . ' INTO last_InsertID FROM DUAL; + WHILE (last_InsertID > last_Sequence) LOOP + SELECT ' . $sequenceName . '.NEXTVAL INTO last_Sequence FROM DUAL; + END LOOP; + END IF; +END;'; + + return $sql; + } + + public function getDropAutoincrementSql($table) + { + $table = strtoupper($table); + $trigger = $table . '_AI_PK'; + + $sql[] = 'DROP TRIGGER ' . $trigger; + $sql[] = $this->getDropSequenceSQL($table.'_SEQ'); + + $indexName = $table . '_AI_PK'; + $sql[] = $this->getDropConstraintSQL($indexName, $table); + + return $sql; + } + + public function getListTableForeignKeysSQL($table) + { + $table = strtoupper($table); + + return "SELECT alc.constraint_name, + alc.DELETE_RULE, + alc.search_condition, + cols.column_name \"local_column\", + cols.position, + r_alc.table_name \"references_table\", + r_cols.column_name \"foreign_column\" + FROM user_cons_columns cols +LEFT JOIN user_constraints alc + ON alc.constraint_name = cols.constraint_name +LEFT JOIN user_constraints r_alc + ON alc.r_constraint_name = r_alc.constraint_name +LEFT JOIN user_cons_columns r_cols + ON r_alc.constraint_name = r_cols.constraint_name + AND cols.position = r_cols.position + WHERE alc.constraint_name = cols.constraint_name + AND alc.constraint_type = 'R' + AND alc.table_name = '".$table."'"; + } + + public function getListTableConstraintsSQL($table) + { + $table = strtoupper($table); + return 'SELECT * FROM user_constraints WHERE table_name = \'' . $table . '\''; + } + + public function getListTableColumnsSQL($table, $database = null) + { + $table = strtoupper($table); + + $tabColumnsTableName = "user_tab_columns"; + $ownerCondition = ''; + + if (null !== $database){ + $database = strtoupper($database); + $tabColumnsTableName = "all_tab_columns"; + $ownerCondition = "AND c.owner = '".$database."'"; + } + + return "SELECT c.*, d.comments FROM $tabColumnsTableName c ". + "INNER JOIN user_col_comments d ON d.TABLE_NAME = c.TABLE_NAME AND d.COLUMN_NAME = c.COLUMN_NAME ". + "WHERE c.table_name = '" . $table . "' ".$ownerCondition." ORDER BY c.column_name"; + } + + /** + * {@inheritDoc} + */ + public function getDropSequenceSQL($sequence) + { + if ($sequence instanceof Sequence) { + $sequence = $sequence->getQuotedName($this); + } + + return 'DROP SEQUENCE ' . $sequence; + } + + /** + * {@inheritDoc} + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + if ($foreignKey instanceof ForeignKeyConstraint) { + $foreignKey = $foreignKey->getQuotedName($this); + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey; + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($database) + { + return 'DROP USER ' . $database . ' CASCADE'; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $sql = array(); + $commentsSQL = array(); + $columnSql = array(); + + $fields = array(); + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $fields[] = $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + if ($comment = $this->getColumnComment($column)) { + $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment); + } + } + + if (count($fields)) { + $sql[] = 'ALTER TABLE ' . $diff->name . ' ADD (' . implode(', ', $fields) . ')'; + } + + $fields = array(); + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + $column = $columnDiff->column; + $fields[] = $column->getQuotedName($this). ' ' . $this->getColumnDeclarationSQL('', $column->toArray()); + if ($columnDiff->hasChanged('comment') && $comment = $this->getColumnComment($column)) { + $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment); + } + } + + if (count($fields)) { + $sql[] = 'ALTER TABLE ' . $diff->name . ' MODIFY (' . implode(', ', $fields) . ')'; + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName .' TO ' . $column->getQuotedName($this); + } + + $fields = array(); + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $fields[] = $column->getQuotedName($this); + } + + if (count($fields)) { + $sql[] = 'ALTER TABLE ' . $diff->name . ' DROP (' . implode(', ', $fields).')'; + } + + $tableSql = array(); + + if ( ! $this->onSchemaAlterTable($diff, $tableSql)) { + if ($diff->newName !== false) { + $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName; + } + + $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff), $commentsSQL); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * {@inheritDoc} + */ + public function prefersSequences() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsCommentOnStatement() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'oracle'; + } + + /** + * {@inheritDoc} + */ + protected function doModifyLimitQuery($query, $limit, $offset = null) + { + $limit = (int) $limit; + $offset = (int) $offset; + + if (preg_match('/^\s*SELECT/i', $query)) { + if (!preg_match('/\sFROM\s/i', $query)) { + $query .= " FROM dual"; + } + if ($limit > 0) { + $max = $offset + $limit; + $column = '*'; + if ($offset > 0) { + $min = $offset + 1; + $query = 'SELECT * FROM (SELECT a.' . $column . ', rownum AS doctrine_rownum FROM (' . + $query . + ') a WHERE rownum <= ' . $max . ') WHERE doctrine_rownum >= ' . $min; + } else { + $query = 'SELECT a.' . $column . ' FROM (' . $query . ') a WHERE ROWNUM <= ' . $max; + } + } + } + + return $query; + } + + /** + * {@inheritDoc} + * + * Oracle returns all column names in SQL result sets in uppercase. + */ + public function getSQLResultCasing($column) + { + return strtoupper($column); + } + + public function getCreateTemporaryTableSnippetSQL() + { + return "CREATE GLOBAL TEMPORARY TABLE"; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzFormatString() + { + return 'Y-m-d H:i:sP'; + } + + /** + * {@inheritDoc} + */ + public function getDateFormatString() + { + return 'Y-m-d 00:00:00'; + } + + /** + * {@inheritDoc} + */ + public function getTimeFormatString() + { + return '1900-01-01 H:i:s'; + } + + /** + * {@inheritDoc} + */ + public function fixSchemaElementName($schemaElementName) + { + if (strlen($schemaElementName) > 30) { + // Trim it + return substr($schemaElementName, 0, 30); + } + + return $schemaElementName; + } + + /** + * {@inheritDoc} + */ + public function getMaxIdentifierLength() + { + return 30; + } + + /** + * {@inheritDoc} + */ + public function supportsSequences() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsForeignKeyOnUpdate() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function supportsReleaseSavepoints() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + return 'TRUNCATE TABLE '.$tableName; + } + + /** + * {@inheritDoc} + */ + public function getDummySelectSQL() + { + return 'SELECT 1 FROM DUAL'; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = array( + 'integer' => 'integer', + 'number' => 'integer', + 'pls_integer' => 'boolean', + 'binary_integer' => 'boolean', + 'varchar' => 'string', + 'varchar2' => 'string', + 'nvarchar2' => 'string', + 'char' => 'string', + 'nchar' => 'string', + 'date' => 'datetime', + 'timestamp' => 'datetime', + 'timestamptz' => 'datetimetz', + 'float' => 'float', + 'long' => 'string', + 'clob' => 'text', + 'nclob' => 'text', + 'raw' => 'text', + 'long raw' => 'text', + 'rowid' => 'string', + 'urowid' => 'string', + 'blob' => 'blob', + ); + } + + /** + * {@inheritDoc} + */ + public function releaseSavePoint($savepoint) + { + return ''; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return 'Doctrine\DBAL\Platforms\Keywords\OracleKeywords'; + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $field) + { + return 'BLOB'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php new file mode 100644 index 0000000..0dbdb1b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php @@ -0,0 +1,762 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\Schema\TableDiff, + Doctrine\DBAL\Schema\Table; + +/** + * PostgreSqlPlatform. + * + * @since 2.0 + * @author Roman Borschel + * @author Lukas Smith (PEAR MDB2 library) + * @author Benjamin Eberlei + * @todo Rename: PostgreSQLPlatform + */ +class PostgreSqlPlatform extends AbstractPlatform +{ + /** + * {@inheritDoc} + */ + public function getSubstringExpression($value, $from, $length = null) + { + if ($length === null) { + return 'SUBSTR(' . $value . ', ' . $from . ')'; + } + + return 'SUBSTR(' . $value . ', ' . $from . ', ' . $length . ')'; + } + + /** + * {@inheritDoc} + */ + public function getNowExpression() + { + return 'LOCALTIMESTAMP(0)'; + } + + /** + * {@inheritDoc} + */ + public function getRegexpExpression() + { + return 'SIMILAR TO'; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos !== false) { + $str = $this->getSubstringExpression($str, $startPos); + + return 'CASE WHEN (POSITION('.$substr.' IN '.$str.') = 0) THEN 0 ELSE (POSITION('.$substr.' IN '.$str.') + '.($startPos-1).') END'; + } + + return 'POSITION('.$substr.' IN '.$str.')'; + } + + /** + * {@inheritDoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return '(DATE(' . $date1 . ')-DATE(' . $date2 . '))'; + } + + /** + * {@inheritDoc} + */ + public function getDateAddDaysExpression($date, $days) + { + return "(" . $date ." + (" . $days . " || ' day')::interval)"; + } + + /** + * {@inheritDoc} + */ + public function getDateSubDaysExpression($date, $days) + { + return "(" . $date ." - (" . $days . " || ' day')::interval)"; + } + + /** + * {@inheritDoc} + */ + public function getDateAddMonthExpression($date, $months) + { + return "(" . $date ." + (" . $months . " || ' month')::interval)"; + } + + /** + * {@inheritDoc} + */ + public function getDateSubMonthExpression($date, $months) + { + return "(" . $date ." - (" . $months . " || ' month')::interval)"; + } + + /** + * {@inheritDoc} + */ + public function supportsSequences() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsSchemas() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsCommentOnStatement() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function prefersSequences() + { + return true; + } + + public function getListDatabasesSQL() + { + return 'SELECT datname FROM pg_database'; + } + + public function getListSequencesSQL($database) + { + return "SELECT + c.relname, n.nspname AS schemaname + FROM + pg_class c, pg_namespace n + WHERE relkind = 'S' AND n.oid = c.relnamespace AND + (n.nspname NOT LIKE 'pg_%' AND n.nspname != 'information_schema')"; + } + + public function getListTablesSQL() + { + return "SELECT tablename AS table_name, schemaname AS schema_name + FROM pg_tables WHERE schemaname NOT LIKE 'pg_%' AND schemaname != 'information_schema' AND tablename != 'geometry_columns' AND tablename != 'spatial_ref_sys'"; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return 'SELECT viewname, definition FROM pg_views'; + } + + public function getListTableForeignKeysSQL($table, $database = null) + { + return "SELECT r.conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef + FROM pg_catalog.pg_constraint r + WHERE r.conrelid = + ( + SELECT c.oid + FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n + WHERE " .$this->getTableWhereClause($table) ." AND n.oid = c.relnamespace + ) + AND r.contype = 'f'"; + } + + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + public function getDropViewSQL($name) + { + return 'DROP VIEW '. $name; + } + + public function getListTableConstraintsSQL($table) + { + return "SELECT + relname + FROM + pg_class + WHERE oid IN ( + SELECT indexrelid + FROM pg_index, pg_class + WHERE pg_class.relname = '$table' + AND pg_class.oid = pg_index.indrelid + AND (indisunique = 't' OR indisprimary = 't') + )"; + } + + /** + * {@inheritDoc} + * + * @license New BSD License + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html + */ + public function getListTableIndexesSQL($table, $currentDatabase = null) + { + return "SELECT relname, pg_index.indisunique, pg_index.indisprimary, + pg_index.indkey, pg_index.indrelid + FROM pg_class, pg_index + WHERE oid IN ( + SELECT indexrelid + FROM pg_index si, pg_class sc, pg_namespace sn + WHERE " . $this->getTableWhereClause($table, 'sc', 'sn')." AND sc.oid=si.indrelid AND sc.relnamespace = sn.oid + ) AND pg_index.indexrelid = oid"; + } + + /** + * @param string $table + * @param string $classAlias + * @param string $namespaceAlias + * + * @return string + */ + private function getTableWhereClause($table, $classAlias = 'c', $namespaceAlias = 'n') + { + $whereClause = $namespaceAlias.".nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND "; + if (strpos($table, ".") !== false) { + list($schema, $table) = explode(".", $table); + $schema = "'" . $schema . "'"; + } else { + $schema = "ANY(string_to_array((select setting from pg_catalog.pg_settings where name = 'search_path'),','))"; + } + $whereClause .= "$classAlias.relname = '" . $table . "' AND $namespaceAlias.nspname = $schema"; + + return $whereClause; + } + + public function getListTableColumnsSQL($table, $database = null) + { + return "SELECT + a.attnum, + a.attname AS field, + t.typname AS type, + format_type(a.atttypid, a.atttypmod) AS complete_type, + (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type, + (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM pg_catalog.pg_type t2 + WHERE t2.typtype = 'd' AND t2.typname = format_type(a.atttypid, a.atttypmod)) AS domain_complete_type, + a.attnotnull AS isnotnull, + (SELECT 't' + FROM pg_index + WHERE c.oid = pg_index.indrelid + AND pg_index.indkey[0] = a.attnum + AND pg_index.indisprimary = 't' + ) AS pri, + (SELECT pg_attrdef.adsrc + FROM pg_attrdef + WHERE c.oid = pg_attrdef.adrelid + AND pg_attrdef.adnum=a.attnum + ) AS default, + (SELECT pg_description.description + FROM pg_description WHERE pg_description.objoid = c.oid AND a.attnum = pg_description.objsubid + ) AS comment + FROM pg_attribute a, pg_class c, pg_type t, pg_namespace n + WHERE ".$this->getTableWhereClause($table, 'c', 'n') ." + AND a.attnum > 0 + AND a.attrelid = c.oid + AND a.atttypid = t.oid + AND n.oid = c.relnamespace + ORDER BY a.attnum"; + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getAdvancedForeignKeyOptionsSQL(\Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey) + { + $query = ''; + + if ($foreignKey->hasOption('match')) { + $query .= ' MATCH ' . $foreignKey->getOption('match'); + } + + $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey); + + if ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) { + $query .= ' DEFERRABLE'; + } else { + $query .= ' NOT DEFERRABLE'; + } + + if ($foreignKey->hasOption('feferred') && $foreignKey->getOption('feferred') !== false) { + $query .= ' INITIALLY DEFERRED'; + } else { + $query .= ' INITIALLY IMMEDIATE'; + } + + return $query; + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $sql = array(); + $commentsSQL = array(); + $columnSql = array(); + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $query = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query; + if ($comment = $this->getColumnComment($column)) { + $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment); + } + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $query = 'DROP ' . $column->getQuotedName($this); + $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query; + } + + foreach ($diff->changedColumns as $columnDiff) { + /** @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */ + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + $oldColumnName = $columnDiff->oldColumnName; + $column = $columnDiff->column; + + if ($columnDiff->hasChanged('type')) { + $type = $column->getType(); + + // here was a server version check before, but DBAL API does not support this anymore. + $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSqlDeclaration($column->toArray(), $this); + $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query; + } + + if ($columnDiff->hasChanged('default')) { + $query = 'ALTER ' . $oldColumnName . ' SET ' . $this->getDefaultValueDeclarationSQL($column->toArray()); + $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query; + } + + if ($columnDiff->hasChanged('notnull')) { + $query = 'ALTER ' . $oldColumnName . ' ' . ($column->getNotNull() ? 'SET' : 'DROP') . ' NOT NULL'; + $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query; + } + + if ($columnDiff->hasChanged('autoincrement')) { + if ($column->getAutoincrement()) { + // add autoincrement + $seqName = $diff->name . '_' . $oldColumnName . '_seq'; + + $sql[] = "CREATE SEQUENCE " . $seqName; + $sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $oldColumnName . ") FROM " . $diff->name . "))"; + $query = "ALTER " . $oldColumnName . " SET DEFAULT nextval('" . $seqName . "')"; + $sql[] = "ALTER TABLE " . $diff->name . " " . $query; + } else { + // Drop autoincrement, but do NOT drop the sequence. It might be re-used by other tables or have + $query = "ALTER " . $oldColumnName . " " . "DROP DEFAULT"; + $sql[] = "ALTER TABLE " . $diff->name . " " . $query; + } + } + + if ($columnDiff->hasChanged('comment') && $comment = $this->getColumnComment($column)) { + $commentsSQL[] = $this->getCommentOnColumnSQL($diff->name, $column->getName(), $comment); + } + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME COLUMN ' . $oldColumnName . ' TO ' . $column->getQuotedName($this); + } + + $tableSql = array(); + + if ( ! $this->onSchemaAlterTable($diff, $tableSql)) { + if ($diff->newName !== false) { + $sql[] = 'ALTER TABLE ' . $diff->name . ' RENAME TO ' . $diff->newName; + } + + $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff), $commentsSQL); + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * {@inheritDoc} + */ + public function getCreateSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence) + { + return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize() . + ' MINVALUE ' . $sequence->getInitialValue() . + ' START ' . $sequence->getInitialValue(); + } + + /** + * {@inheritDoc} + */ + public function getAlterSequenceSQL(\Doctrine\DBAL\Schema\Sequence $sequence) + { + return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . + ' INCREMENT BY ' . $sequence->getAllocationSize(); + } + + /** + * {@inheritDoc} + */ + public function getDropSequenceSQL($sequence) + { + if ($sequence instanceof \Doctrine\DBAL\Schema\Sequence) { + $sequence = $sequence->getQuotedName($this); + } + return 'DROP SEQUENCE ' . $sequence; + } + + /** + * {@inheritDoc} + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + return $this->getDropConstraintSQL($foreignKey, $table); + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($tableName, array $columns, array $options = array()) + { + $queryFields = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['primary']) && ! empty($options['primary'])) { + $keyColumns = array_unique(array_values($options['primary'])); + $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; + } + + $query = 'CREATE TABLE ' . $tableName . ' (' . $queryFields . ')'; + + $sql[] = $query; + + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach ($options['indexes'] as $index) { + $sql[] = $this->getCreateIndexSQL($index, $tableName); + } + } + + if (isset($options['foreignKeys'])) { + foreach ((array) $options['foreignKeys'] as $definition) { + $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); + } + } + + return $sql; + } + + /** + * {@inheritDoc} + * + * Postgres wants boolean values converted to the strings 'true'/'false'. + */ + public function convertBooleans($item) + { + if (is_array($item)) { + foreach ($item as $key => $value) { + if (is_bool($value) || is_numeric($item)) { + $item[$key] = ($value) ? 'true' : 'false'; + } + } + } else { + if (is_bool($item) || is_numeric($item)) { + $item = ($item) ? 'true' : 'false'; + } + } + + return $item; + } + + public function getSequenceNextValSQL($sequenceName) + { + return "SELECT NEXTVAL('" . $sequenceName . "')"; + } + + /** + * {@inheritDoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL ' + . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $field) + { + return 'BOOLEAN'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $field) + { + if ( ! empty($field['autoincrement'])) { + return 'SERIAL'; + } + + return 'INT'; + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $field) + { + if ( ! empty($field['autoincrement'])) { + return 'BIGSERIAL'; + } + return 'BIGINT'; + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $field) + { + return 'SMALLINT'; + } + + /** + * {@inheritDoc} + */ + public function getGuidTypeDeclarationSQL(array $field) + { + return 'UUID'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIMESTAMP(0) WITHOUT TIME ZONE'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIMESTAMP(0) WITH TIME ZONE'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIME(0) WITHOUT TIME ZONE'; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + { + return ''; + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $field) + { + return 'TEXT'; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'postgresql'; + } + + /** + * {@inheritDoc} + * + * PostgreSQL returns all column names in SQL result sets in lowercase. + */ + public function getSQLResultCasing($column) + { + return strtolower($column); + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzFormatString() + { + return 'Y-m-d H:i:sO'; + } + + /** + * {@inheritDoc} + */ + public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) + { + return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)'; + } + + /** + * {@inheritDoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + return 'TRUNCATE '.$tableName.' '.(($cascade)?'CASCADE':''); + } + + /** + * {@inheritDoc} + */ + public function getReadLockSQL() + { + return 'FOR SHARE'; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = array( + 'smallint' => 'smallint', + 'int2' => 'smallint', + 'serial' => 'integer', + 'serial4' => 'integer', + 'int' => 'integer', + 'int4' => 'integer', + 'integer' => 'integer', + 'bigserial' => 'bigint', + 'serial8' => 'bigint', + 'bigint' => 'bigint', + 'int8' => 'bigint', + 'bool' => 'boolean', + 'boolean' => 'boolean', + 'text' => 'text', + 'varchar' => 'string', + 'interval' => 'string', + '_varchar' => 'string', + 'char' => 'string', + 'bpchar' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'timestamp' => 'datetime', + 'timestamptz' => 'datetimetz', + 'time' => 'time', + 'timetz' => 'time', + 'float' => 'float', + 'float4' => 'float', + 'float8' => 'float', + 'double' => 'float', + 'double precision' => 'float', + 'real' => 'float', + 'decimal' => 'decimal', + 'money' => 'decimal', + 'numeric' => 'decimal', + 'year' => 'date', + 'uuid' => 'guid', + 'bytea' => 'blob', + ); + } + + /** + * {@inheritDoc} + */ + public function getVarcharMaxLength() + { + return 65535; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return 'Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords'; + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $field) + { + return 'BYTEA'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php new file mode 100644 index 0000000..238e54f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php @@ -0,0 +1,51 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\Schema\Table; + +/** + * Platform to ensure compatibility of Doctrine with SQL Azure + * + * On top of SQL Server 2008 the following functionality is added: + * + * - Create tables with the FEDERATED ON syntax. + */ +class SQLAzurePlatform extends SQLServer2008Platform +{ + /** + * {@inheritDoc} + */ + public function getCreateTableSQL(Table $table, $createFlags=self::CREATE_INDEXES) + { + $sql = parent::getCreateTableSQL($table, $createFlags); + + if ($table->hasOption('azure.federatedOnColumnName')) { + $distributionName = $table->getOption('azure.federatedOnDistributionName'); + $columnName = $table->getOption('azure.federatedOnColumnName'); + $stmt = ' FEDERATED ON (' . $distributionName . ' = ' . $columnName . ')'; + + $sql[0] = $sql[0] . $stmt; + } + + return $sql; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php new file mode 100644 index 0000000..be3725b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php @@ -0,0 +1,54 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +/** + * Platform to ensure compatibility of Doctrine with SQLServer2005 version and + * higher. + * + * Differences to SQL Server 2008 are: + * + * - DATETIME2 datatype does not exist, only DATETIME which has a precision of + * 3. This is not supported by PHP DateTime, so we are emulating it by + * setting .000 manually. + * - Starting with SQLServer2005 VARCHAR(MAX), VARBINARY(MAX) and + * NVARCHAR(max) replace the old TEXT, NTEXT and IMAGE types. See + * {@link http://www.sql-server-helper.com/faq/sql-server-2005-varchar-max-p01.aspx} + * for more information. + */ +class SQLServer2005Platform extends SQLServerPlatform +{ + /** + * {@inheritDoc} + */ + public function supportsLimitOffset() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $field) + { + return 'VARCHAR(MAX)'; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2008Platform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2008Platform.php new file mode 100644 index 0000000..909ab84 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServer2008Platform.php @@ -0,0 +1,100 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +/** + * Platform to ensure compatibility of Doctrine with SQLServer2008 version. + * + * Differences to SQL Server 2005 and before are that a new DATETIME2 type was + * introduced that has a higher precision. + */ +class SQLServer2008Platform extends SQLServer2005Platform +{ + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + { + // 3 - microseconds precision length + // http://msdn.microsoft.com/en-us/library/ms187819.aspx + return 'DATETIME2(6)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIME(0)'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeFormatString() + { + return 'Y-m-d H:i:s.u'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzFormatString() + { + return 'Y-m-d H:i:s.u P'; + } + + /** + * {@inheritDoc} + */ + public function getDateFormatString() + { + return 'Y-m-d'; + } + + /** + * {@inheritDoc} + */ + public function getTimeFormatString() + { + return 'H:i:s'; + } + + /** + * {@inheritDoc} + * + * Adding Datetime2 Type + */ + protected function initializeDoctrineTypeMappings() + { + parent::initializeDoctrineTypeMappings(); + $this->doctrineTypeMapping['datetime2'] = 'datetime'; + $this->doctrineTypeMapping['date'] = 'date'; + $this->doctrineTypeMapping['time'] = 'time'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php new file mode 100644 index 0000000..6557fed --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php @@ -0,0 +1,905 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\Schema\TableDiff; +use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Schema\ForeignKeyConstraint; +use Doctrine\DBAL\Schema\Index; +use Doctrine\DBAL\Schema\Table; + +/** + * The SQLServerPlatform provides the behavior, features and SQL dialect of the + * Microsoft SQL Server database platform. + * + * @since 2.0 + * @author Roman Borschel + * @author Jonathan H. Wage + * @author Benjamin Eberlei + */ +class SQLServerPlatform extends AbstractPlatform +{ + /** + * {@inheritDoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return 'DATEDIFF(day, ' . $date2 . ',' . $date1 . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateAddDaysExpression($date, $days) + { + return 'DATEADD(day, ' . $days . ', ' . $date . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateSubDaysExpression($date, $days) + { + return 'DATEADD(day, -1 * ' . $days . ', ' . $date . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateAddMonthExpression($date, $months) + { + return 'DATEADD(month, ' . $months . ', ' . $date . ')'; + } + + /** + * {@inheritDoc} + */ + public function getDateSubMonthExpression($date, $months) + { + return 'DATEADD(month, -1 * ' . $months . ', ' . $date . ')'; + } + + /** + * {@inheritDoc} + * + * MsSql prefers "autoincrement" identity columns since sequences can only + * be emulated with a table. + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + * + * MsSql supports this through AUTO_INCREMENT columns. + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function supportsReleaseSavepoints() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function getCreateDatabaseSQL($name) + { + return 'CREATE DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getDropDatabaseSQL($name) + { + return 'DROP DATABASE ' . $name; + } + + /** + * {@inheritDoc} + */ + public function supportsCreateDropDatabase() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function getDropForeignKeySQL($foreignKey, $table) + { + if ($foreignKey instanceof ForeignKeyConstraint) { + $foreignKey = $foreignKey->getQuotedName($this); + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey; + } + + /** + * {@inheritDoc} + */ + public function getDropIndexSQL($index, $table = null) + { + if ($index instanceof Index) { + $index = $index->getQuotedName($this); + } else if (!is_string($index)) { + throw new \InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); + } + + if (!isset($table)) { + return 'DROP INDEX ' . $index; + } + + if ($table instanceof Table) { + $table = $table->getQuotedName($this); + } + + return "IF EXISTS (SELECT * FROM sysobjects WHERE name = '$index') + ALTER TABLE " . $table . " DROP CONSTRAINT " . $index . " + ELSE + DROP INDEX " . $index . " ON " . $table; + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($tableName, array $columns, array $options = array()) + { + // @todo does other code breaks because of this? + // force primary keys to be not null + foreach ($columns as &$column) { + if (isset($column['primary']) && $column['primary']) { + $column['notnull'] = true; + } + } + + $columnListSql = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['uniqueConstraints']) && !empty($options['uniqueConstraints'])) { + foreach ($options['uniqueConstraints'] as $name => $definition) { + $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); + } + } + + if (isset($options['primary']) && !empty($options['primary'])) { + $flags = ''; + if (isset($options['primary_index']) && $options['primary_index']->hasFlag('nonclustered')) { + $flags = ' NONCLUSTERED'; + } + $columnListSql .= ', PRIMARY KEY' . $flags . ' (' . implode(', ', array_unique(array_values($options['primary']))) . ')'; + } + + $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql; + + $check = $this->getCheckDeclarationSQL($columns); + if (!empty($check)) { + $query .= ', ' . $check; + } + $query .= ')'; + + $sql[] = $query; + + if (isset($options['indexes']) && !empty($options['indexes'])) { + foreach ($options['indexes'] as $index) { + $sql[] = $this->getCreateIndexSQL($index, $tableName); + } + } + + if (isset($options['foreignKeys'])) { + foreach ((array) $options['foreignKeys'] as $definition) { + $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); + } + } + + return $sql; + } + + /** + * {@inheritDoc} + */ + public function getCreatePrimaryKeySQL(Index $index, $table) + { + $flags = ''; + if ($index->hasFlag('nonclustered')) { + $flags = ' NONCLUSTERED'; + } + return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY' . $flags . ' (' . $this->getIndexFieldDeclarationListSQL($index->getColumns()) . ')'; + } + + /** + * {@inheritDoc} + */ + public function getUniqueConstraintDeclarationSQL($name, Index $index) + { + $constraint = parent::getUniqueConstraintDeclarationSQL($name, $index); + + $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index); + + return $constraint; + } + + /** + * {@inheritDoc} + */ + public function getCreateIndexSQL(Index $index, $table) + { + $constraint = parent::getCreateIndexSQL($index, $table); + + if ($index->isUnique()) { + $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index); + } + + return $constraint; + } + + /** + * {@inheritDoc} + */ + protected function getCreateIndexSQLFlags(Index $index) + { + $type = ''; + if ($index->isUnique()) { + $type .= 'UNIQUE '; + } + + if ($index->hasFlag('clustered')) { + $type .= 'CLUSTERED '; + } else if ($index->hasFlag('nonclustered')) { + $type .= 'NONCLUSTERED '; + } + + return $type; + } + + /** + * Extend unique key constraint with required filters + * + * @param string $sql + * @param Index $index + * + * @return string + */ + private function _appendUniqueConstraintDefinition($sql, Index $index) + { + $fields = array(); + foreach ($index->getColumns() as $field => $definition) { + if (!is_array($definition)) { + $field = $definition; + } + + $fields[] = $field . ' IS NOT NULL'; + } + + return $sql . ' WHERE ' . implode(' AND ', $fields); + } + + /** + * {@inheritDoc} + */ + public function getAlterTableSQL(TableDiff $diff) + { + $queryParts = array(); + $sql = array(); + $columnSql = array(); + + foreach ($diff->addedColumns as $column) { + if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + } + + foreach ($diff->removedColumns as $column) { + if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { + continue; + } + + $queryParts[] = 'DROP COLUMN ' . $column->getQuotedName($this); + } + + foreach ($diff->changedColumns as $columnDiff) { + if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { + continue; + } + + /* @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */ + $column = $columnDiff->column; + $queryParts[] = 'ALTER COLUMN ' . + $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + } + + foreach ($diff->renamedColumns as $oldColumnName => $column) { + if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { + continue; + } + + $sql[] = "sp_RENAME '". $diff->name. ".". $oldColumnName . "' , '".$column->getQuotedName($this)."', 'COLUMN'"; + $queryParts[] = 'ALTER COLUMN ' . + $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); + } + + $tableSql = array(); + + if ($this->onSchemaAlterTable($diff, $tableSql)) { + return array_merge($tableSql, $columnSql); + } + + foreach ($queryParts as $query) { + $sql[] = 'ALTER TABLE ' . $diff->name . ' ' . $query; + } + + $sql = array_merge($sql, $this->_getAlterTableIndexForeignKeySQL($diff)); + + if ($diff->newName !== false) { + $sql[] = "sp_RENAME '" . $diff->name . "', '" . $diff->newName . "'"; + } + + return array_merge($sql, $tableSql, $columnSql); + } + + /** + * {@inheritDoc} + */ + public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) + { + return 'INSERT INTO ' . $quotedTableName . ' DEFAULT VALUES'; + } + + /** + * {@inheritDoc} + */ + public function getShowDatabasesSQL() + { + return 'SHOW DATABASES'; + } + + /** + * {@inheritDoc} + */ + public function getListTablesSQL() + { + // "sysdiagrams" table must be ignored as it's internal SQL Server table for Database Diagrams + return "SELECT name FROM sysobjects WHERE type = 'U' AND name != 'sysdiagrams' ORDER BY name"; + } + + /** + * {@inheritDoc} + */ + public function getListTableColumnsSQL($table, $database = null) + { + return "exec sp_columns @table_name = '" . $table . "'"; + } + + /** + * {@inheritDoc} + */ + public function getListTableForeignKeysSQL($table, $database = null) + { + return "SELECT f.name AS ForeignKey, + SCHEMA_NAME (f.SCHEMA_ID) AS SchemaName, + OBJECT_NAME (f.parent_object_id) AS TableName, + COL_NAME (fc.parent_object_id,fc.parent_column_id) AS ColumnName, + SCHEMA_NAME (o.SCHEMA_ID) ReferenceSchemaName, + OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName, + COL_NAME(fc.referenced_object_id,fc.referenced_column_id) AS ReferenceColumnName, + f.delete_referential_action_desc, + f.update_referential_action_desc + FROM sys.foreign_keys AS f + INNER JOIN sys.foreign_key_columns AS fc + INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id + ON f.OBJECT_ID = fc.constraint_object_id + WHERE OBJECT_NAME (f.parent_object_id) = '" . $table . "'"; + } + + /** + * {@inheritDoc} + */ + public function getListTableIndexesSQL($table, $currentDatabase = null) + { + return "exec sp_helpindex '" . $table . "'"; + } + + /** + * {@inheritDoc} + */ + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return "SELECT name FROM sysobjects WHERE type = 'V' ORDER BY name"; + } + + /** + * {@inheritDoc} + */ + public function getDropViewSQL($name) + { + return 'DROP VIEW ' . $name; + } + + /** + * {@inheritDoc} + */ + public function getRegexpExpression() + { + return 'RLIKE'; + } + + /** + * {@inheritDoc} + */ + public function getGuidExpression() + { + return 'UUID()'; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos == false) { + return 'CHARINDEX(' . $substr . ', ' . $str . ')'; + } + + return 'CHARINDEX(' . $substr . ', ' . $str . ', ' . $startPos . ')'; + } + + /** + * {@inheritDoc} + */ + public function getModExpression($expression1, $expression2) + { + return $expression1 . ' % ' . $expression2; + } + + /** + * {@inheritDoc} + */ + public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false) + { + if ( ! $char) { + switch ($pos) { + case self::TRIM_LEADING: + $trimFn = 'LTRIM'; + break; + + case self::TRIM_TRAILING: + $trimFn = 'RTRIM'; + break; + + default: + return 'LTRIM(RTRIM(' . $str . '))'; + } + + return $trimFn . '(' . $str . ')'; + } + + /** Original query used to get those expressions + declare @c varchar(100) = 'xxxBarxxx', @trim_char char(1) = 'x'; + declare @pat varchar(10) = '%[^' + @trim_char + ']%'; + select @c as string + , @trim_char as trim_char + , stuff(@c, 1, patindex(@pat, @c) - 1, null) as trim_leading + , reverse(stuff(reverse(@c), 1, patindex(@pat, reverse(@c)) - 1, null)) as trim_trailing + , reverse(stuff(reverse(stuff(@c, 1, patindex(@pat, @c) - 1, null)), 1, patindex(@pat, reverse(stuff(@c, 1, patindex(@pat, @c) - 1, null))) - 1, null)) as trim_both; + */ + $pattern = "'%[^' + $char + ']%'"; + + if ($pos == self::TRIM_LEADING) { + return 'stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)'; + } + + if ($pos == self::TRIM_TRAILING) { + return 'reverse(stuff(reverse(' . $str . '), 1, patindex(' . $pattern . ', reverse(' . $str . ')) - 1, null))'; + } + + return 'reverse(stuff(reverse(stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)), 1, patindex(' . $pattern . ', reverse(stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null))) - 1, null))'; + } + + /** + * {@inheritDoc} + */ + public function getConcatExpression() + { + $args = func_get_args(); + + return '(' . implode(' + ', $args) . ')'; + } + + public function getListDatabasesSQL() + { + return 'SELECT * FROM SYS.DATABASES'; + } + + /** + * {@inheritDoc} + */ + public function getSubstringExpression($value, $from, $length = null) + { + if (!is_null($length)) { + return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')'; + } + + return 'SUBSTRING(' . $value . ', ' . $from . ', LEN(' . $value . ') - ' . $from . ' + 1)'; + } + + /** + * {@inheritDoc} + */ + public function getLengthExpression($column) + { + return 'LEN(' . $column . ')'; + } + + /** + * {@inheritDoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $field) + { + return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $field) + { + return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $field) + { + return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getGuidTypeDeclarationSQL(array $field) + { + return 'UNIQUEIDENTIFIER'; + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'NCHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'NVARCHAR(' . $length . ')' : 'NVARCHAR(255)'); + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $field) + { + return 'TEXT'; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + { + $autoinc = ''; + if (!empty($columnDef['autoincrement'])) { + $autoinc = ' IDENTITY'; + } + $unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : ''; + + return $unsigned . $autoinc; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $field) + { + return 'BIT'; + } + + /** + * {@inheritDoc} + * + * @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html + */ + protected function doModifyLimitQuery($query, $limit, $offset = null) + { + if ($limit > 0) { + if ($offset == 0) { + $query = preg_replace('/^(SELECT\s(DISTINCT\s)?)/i', '\1TOP ' . $limit . ' ', $query); + } else { + $orderby = stristr($query, 'ORDER BY'); + + if ( ! $orderby) { + $over = 'ORDER BY (SELECT 0)'; + } else { + $over = preg_replace('/\"[^,]*\".\"([^,]*)\"/i', '"inner_tbl"."$1"', $orderby); + } + + // Remove ORDER BY clause from $query + $query = preg_replace('/\s+ORDER BY(.*)/', '', $query); + $query = preg_replace('/^SELECT\s/', '', $query); + + $start = $offset + 1; + $end = $offset + $limit; + + $query = "SELECT * FROM (SELECT ROW_NUMBER() OVER ($over) AS doctrine_rownum, $query) AS doctrine_tbl WHERE doctrine_rownum BETWEEN $start AND $end"; + } + } + + return $query; + } + + /** + * {@inheritDoc} + */ + public function supportsLimitOffset() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function convertBooleans($item) + { + if (is_array($item)) { + foreach ($item as $key => $value) { + if (is_bool($value) || is_numeric($item)) { + $item[$key] = ($value) ? 1 : 0; + } + } + } else if (is_bool($item) || is_numeric($item)) { + $item = ($item) ? 1 : 0; + } + + return $item; + } + + /** + * {@inheritDoc} + */ + public function getCreateTemporaryTableSnippetSQL() + { + return "CREATE TABLE"; + } + + /** + * {@inheritDoc} + */ + public function getTemporaryTableName($tableName) + { + return '#' . $tableName; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeFormatString() + { + return 'Y-m-d H:i:s.000'; + } + + /** + * {@inheritDoc} + */ + public function getDateFormatString() + { + return 'Y-m-d H:i:s.000'; + } + + /** + * {@inheritDoc} + */ + public function getTimeFormatString() + { + return 'Y-m-d H:i:s.000'; + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTzFormatString() + { + return $this->getDateTimeFormatString(); + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'mssql'; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = array( + 'bigint' => 'bigint', + 'numeric' => 'decimal', + 'bit' => 'boolean', + 'smallint' => 'smallint', + 'decimal' => 'decimal', + 'smallmoney' => 'integer', + 'int' => 'integer', + 'tinyint' => 'smallint', + 'money' => 'integer', + 'float' => 'float', + 'real' => 'float', + 'double' => 'float', + 'double precision' => 'float', + 'datetimeoffset' => 'datetimetz', + 'smalldatetime' => 'datetime', + 'datetime' => 'datetime', + 'char' => 'string', + 'varchar' => 'string', + 'text' => 'text', + 'nchar' => 'string', + 'nvarchar' => 'string', + 'ntext' => 'text', + 'binary' => 'text', + 'varbinary' => 'blob', + 'image' => 'text', + 'uniqueidentifier' => 'guid', + ); + } + + /** + * {@inheritDoc} + */ + public function createSavePoint($savepoint) + { + return 'SAVE TRANSACTION ' . $savepoint; + } + + /** + * {@inheritDoc} + */ + public function releaseSavePoint($savepoint) + { + return ''; + } + + /** + * {@inheritDoc} + */ + public function rollbackSavePoint($savepoint) + { + return 'ROLLBACK TRANSACTION ' . $savepoint; + } + + /** + * {@inheritDoc} + */ + public function appendLockHint($fromClause, $lockMode) + { + // @todo coorect + if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_READ) { + return $fromClause . ' WITH (tablockx)'; + } + + if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) { + return $fromClause . ' WITH (tablockx)'; + } + + return $fromClause; + } + + /** + * {@inheritDoc} + */ + public function getForUpdateSQL() + { + return ' '; + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return 'Doctrine\DBAL\Platforms\Keywords\MsSQLKeywords'; + } + + /** + * {@inheritDoc} + */ + public function quoteSingleIdentifier($str) + { + return "[" . str_replace("]", "][", $str) . "]"; + } + + /** + * {@inheritDoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + return 'TRUNCATE TABLE '.$tableName; + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $field) + { + return 'VARBINARY(MAX)'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php new file mode 100644 index 0000000..7ed5201 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php @@ -0,0 +1,529 @@ +. + */ + +namespace Doctrine\DBAL\Platforms; + +use Doctrine\DBAL\DBALException; + +/** + * The SqlitePlatform class describes the specifics and dialects of the SQLite + * database platform. + * + * @since 2.0 + * @author Roman Borschel + * @author Benjamin Eberlei + * @todo Rename: SQLitePlatform + */ +class SqlitePlatform extends AbstractPlatform +{ + /** + * {@inheritDoc} + */ + public function getRegexpExpression() + { + return 'RLIKE'; + } + + /** + * {@inheritDoc} + */ + public function getNowExpression($type = 'timestamp') + { + switch ($type) { + case 'time': + return 'time(\'now\')'; + case 'date': + return 'date(\'now\')'; + case 'timestamp': + default: + return 'datetime(\'now\')'; + } + } + + /** + * {@inheritDoc} + */ + public function getTrimExpression($str, $pos = self::TRIM_UNSPECIFIED, $char = false) + { + $trimChar = ($char != false) ? (', ' . $char) : ''; + + switch ($pos) { + case self::TRIM_LEADING: + $trimFn = 'LTRIM'; + break; + + case self::TRIM_TRAILING: + $trimFn = 'RTRIM'; + break; + + default: + $trimFn = 'TRIM'; + } + + return $trimFn . '(' . $str . $trimChar . ')'; + } + + /** + * {@inheritDoc} + * + * SQLite only supports the 2 parameter variant of this function + */ + public function getSubstringExpression($value, $position, $length = null) + { + if ($length !== null) { + return 'SUBSTR(' . $value . ', ' . $position . ', ' . $length . ')'; + } + + return 'SUBSTR(' . $value . ', ' . $position . ', LENGTH(' . $value . '))'; + } + + /** + * {@inheritDoc} + */ + public function getLocateExpression($str, $substr, $startPos = false) + { + if ($startPos == false) { + return 'LOCATE('.$str.', '.$substr.')'; + } + + return 'LOCATE('.$str.', '.$substr.', '.$startPos.')'; + } + + /** + * {@inheritDoc} + */ + public function getDateDiffExpression($date1, $date2) + { + return 'ROUND(JULIANDAY('.$date1 . ')-JULIANDAY('.$date2.'))'; + } + + /** + * {@inheritDoc} + */ + public function getDateAddDaysExpression($date, $days) + { + return "DATE(" . $date . ",'+". $days . " day')"; + } + + /** + * {@inheritDoc} + */ + public function getDateSubDaysExpression($date, $days) + { + return "DATE(" . $date . ",'-". $days . " day')"; + } + + /** + * {@inheritDoc} + */ + public function getDateAddMonthExpression($date, $months) + { + return "DATE(" . $date . ",'+". $months . " month')"; + } + + /** + * {@inheritDoc} + */ + public function getDateSubMonthExpression($date, $months) + { + return "DATE(" . $date . ",'-". $months . " month')"; + } + + /** + * {@inheritDoc} + */ + protected function _getTransactionIsolationLevelSQL($level) + { + switch ($level) { + case \Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED: + return 0; + case \Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED: + case \Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ: + case \Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE: + return 1; + default: + return parent::_getTransactionIsolationLevelSQL($level); + } + } + + /** + * {@inheritDoc} + */ + public function getSetTransactionIsolationSQL($level) + { + return 'PRAGMA read_uncommitted = ' . $this->_getTransactionIsolationLevelSQL($level); + } + + /** + * {@inheritDoc} + */ + public function prefersIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getBooleanTypeDeclarationSQL(array $field) + { + return 'BOOLEAN'; + } + + /** + * {@inheritDoc} + */ + public function getIntegerTypeDeclarationSQL(array $field) + { + return $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getBigIntTypeDeclarationSQL(array $field) + { + return $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getTinyIntTypeDeclarationSql(array $field) + { + return $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getSmallIntTypeDeclarationSQL(array $field) + { + return $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getMediumIntTypeDeclarationSql(array $field) + { + return $this->_getCommonIntegerTypeDeclarationSQL($field); + } + + /** + * {@inheritDoc} + */ + public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATETIME'; + } + + /** + * {@inheritDoc} + */ + public function getDateTypeDeclarationSQL(array $fieldDeclaration) + { + return 'DATE'; + } + + /** + * {@inheritDoc} + */ + public function getTimeTypeDeclarationSQL(array $fieldDeclaration) + { + return 'TIME'; + } + + /** + * {@inheritDoc} + */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) + { + return 'INTEGER'; + } + + /** + * {@inheritDoc} + */ + protected function _getCreateTableSQL($name, array $columns, array $options = array()) + { + $name = str_replace(".", "__", $name); + $queryFields = $this->getColumnDeclarationListSQL($columns); + + if (isset($options['primary']) && ! empty($options['primary'])) { + $keyColumns = array_unique(array_values($options['primary'])); + $queryFields.= ', PRIMARY KEY('.implode(', ', $keyColumns).')'; + } + + $query[] = 'CREATE TABLE ' . $name . ' (' . $queryFields . ')'; + + if (isset($options['indexes']) && ! empty($options['indexes'])) { + foreach ($options['indexes'] as $index => $indexDef) { + $query[] = $this->getCreateIndexSQL($indexDef, $name); + } + } + + if (isset($options['unique']) && ! empty($options['unique'])) { + foreach ($options['unique'] as $index => $indexDef) { + $query[] = $this->getCreateIndexSQL($indexDef, $name); + } + } + + return $query; + } + + /** + * {@inheritDoc} + */ + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') + : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); + } + + /** + * {@inheritDoc} + */ + public function getClobTypeDeclarationSQL(array $field) + { + return 'CLOB'; + } + + public function getListTableConstraintsSQL($table) + { + $table = str_replace(".", "__", $table); + + return "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = '$table' AND sql NOT NULL ORDER BY name"; + } + + public function getListTableColumnsSQL($table, $currentDatabase = null) + { + $table = str_replace(".", "__", $table); + + return "PRAGMA table_info($table)"; + } + + /** + * {@inheritDoc} + */ + public function getListTableIndexesSQL($table, $currentDatabase = null) + { + $table = str_replace(".", "__", $table); + + return "PRAGMA index_list($table)"; + } + + public function getListTablesSQL() + { + return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' AND name != 'geometry_columns' AND name != 'spatial_ref_sys' " + . "UNION ALL SELECT name FROM sqlite_temp_master " + . "WHERE type = 'table' ORDER BY name"; + } + + /** + * {@inheritDoc} + */ + public function getListViewsSQL($database) + { + return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL"; + } + + public function getCreateViewSQL($name, $sql) + { + return 'CREATE VIEW ' . $name . ' AS ' . $sql; + } + + public function getDropViewSQL($name) + { + return 'DROP VIEW '. $name; + } + + /** + * {@inheritDoc} + * + * SQLite does support foreign key constraints, but only in CREATE TABLE statements... + * This really limits their usefulness and requires SQLite specific handling, so + * we simply say that SQLite does NOT support foreign keys for now... + */ + public function supportsForeignKeyConstraints() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function supportsAlterTable() + { + return false; + } + + /** + * {@inheritDoc} + */ + public function supportsIdentityColumns() + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'sqlite'; + } + + /** + * {@inheritDoc} + */ + public function getTruncateTableSQL($tableName, $cascade = false) + { + $tableName = str_replace(".", "__", $tableName); + return 'DELETE FROM '.$tableName; + } + + /** + * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction() + * + * @param int|float $value + * + * @return float + */ + static public function udfSqrt($value) + { + return sqrt($value); + } + + /** + * User-defined function for Sqlite that implements MOD(a, b) + * + * @param integer $a + * @param integer $b + * + * @return integer + */ + static public function udfMod($a, $b) + { + return ($a % $b); + } + + /** + * @param string $str + * @param string $substr + * @param integer $offset + * + * @return integer + */ + static public function udfLocate($str, $substr, $offset = 0) + { + $pos = strpos($str, $substr, $offset); + if ($pos !== false) { + return $pos+1; + } + + return 0; + } + + public function getForUpdateSql() + { + return ''; + } + + /** + * {@inheritDoc} + */ + protected function initializeDoctrineTypeMappings() + { + $this->doctrineTypeMapping = array( + 'boolean' => 'boolean', + 'tinyint' => 'boolean', + 'smallint' => 'smallint', + 'mediumint' => 'integer', + 'int' => 'integer', + 'integer' => 'integer', + 'serial' => 'integer', + 'bigint' => 'bigint', + 'bigserial' => 'bigint', + 'clob' => 'text', + 'tinytext' => 'text', + 'mediumtext' => 'text', + 'longtext' => 'text', + 'text' => 'text', + 'varchar' => 'string', + 'longvarchar' => 'string', + 'varchar2' => 'string', + 'nvarchar' => 'string', + 'image' => 'string', + 'ntext' => 'string', + 'char' => 'string', + 'date' => 'date', + 'datetime' => 'datetime', + 'timestamp' => 'datetime', + 'time' => 'time', + 'float' => 'float', + 'double' => 'float', + 'double precision' => 'float', + 'real' => 'float', + 'decimal' => 'decimal', + 'numeric' => 'decimal', + 'blob' => 'blob', + ); + } + + /** + * {@inheritDoc} + */ + protected function getReservedKeywordsClass() + { + return 'Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords'; + } + + /** + * {@inheritDoc} + */ + public function getBlobTypeDeclarationSQL(array $field) + { + return 'BLOB'; + } + + /** + * {@inheritDoc} + */ + public function getTemporaryTableName($tableName) + { + $tableName = str_replace(".", "__", $tableName); + + return $tableName; + } + + /** + * {@inheritDoc} + * + * Sqlite Platform emulates schema by underscoring each dot and generating tables + * into the default database. + * + * This hack is implemented to be able to use SQLite as testdriver when + * using schema supporting databases. + */ + public function canEmulateSchemas() + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Connection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Connection.php new file mode 100644 index 0000000..410fa82 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Connection.php @@ -0,0 +1,119 @@ +. + */ + + +namespace Doctrine\DBAL\Portability; + +use Doctrine\Common\EventManager; +use Doctrine\DBAL\Configuration; +use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Cache\QueryCacheProfile; + +class Connection extends \Doctrine\DBAL\Connection +{ + const PORTABILITY_ALL = 255; + const PORTABILITY_NONE = 0; + const PORTABILITY_RTRIM = 1; + const PORTABILITY_EMPTY_TO_NULL = 4; + const PORTABILITY_FIX_CASE = 8; + + const PORTABILITY_ORACLE = 9; + const PORTABILITY_POSTGRESQL = 13; + const PORTABILITY_SQLITE = 13; + const PORTABILITY_OTHERVENDORS = 12; + const PORTABILITY_DRIZZLE = 13; + const PORTABILITY_SQLSRV = 13; + + /** + * @var int + */ + private $portability = self::PORTABILITY_NONE; + + /** + * @var int + */ + private $case; + + public function connect() + { + $ret = parent::connect(); + if ($ret) { + $params = $this->getParams(); + if (isset($params['portability'])) { + if ($this->_platform->getName() === "oracle") { + $params['portability'] = $params['portability'] & self::PORTABILITY_ORACLE; + } else if ($this->_platform->getName() === "postgresql") { + $params['portability'] = $params['portability'] & self::PORTABILITY_POSTGRESQL; + } else if ($this->_platform->getName() === "sqlite") { + $params['portability'] = $params['portability'] & self::PORTABILITY_SQLITE; + } else if ($this->_platform->getName() === "drizzle") { + $params['portability'] = self::PORTABILITY_DRIZZLE; + } else if ($this->_platform->getName() === 'sqlsrv') { + $params['portability'] = $params['portabililty'] & self::PORTABILITY_SQLSRV; + } else { + $params['portability'] = $params['portability'] & self::PORTABILITY_OTHERVENDORS; + } + $this->portability = $params['portability']; + } + if (isset($params['fetch_case']) && $this->portability & self::PORTABILITY_FIX_CASE) { + if ($this->_conn instanceof \Doctrine\DBAL\Driver\PDOConnection) { + // make use of c-level support for case handling + $this->_conn->setAttribute(\PDO::ATTR_CASE, $params['fetch_case']); + } else { + $this->case = ($params['fetch_case'] == \PDO::CASE_LOWER) ? CASE_LOWER : CASE_UPPER; + } + } + } + return $ret; + } + + public function getPortability() + { + return $this->portability; + } + + public function getFetchCase() + { + return $this->case; + } + + public function executeQuery($query, array $params = array(), $types = array(), QueryCacheProfile $qcp = null) + { + return new Statement(parent::executeQuery($query, $params, $types, $qcp), $this); + } + + /** + * Prepares an SQL statement. + * + * @param string $statement The SQL statement to prepare. + * @return \Doctrine\DBAL\Driver\Statement The prepared statement. + */ + public function prepare($statement) + { + return new Statement(parent::prepare($statement), $this); + } + + public function query() + { + $this->connect(); + + $stmt = call_user_func_array(array($this->_conn, 'query'), func_get_args()); + return new Statement($stmt, $this); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Statement.php new file mode 100644 index 0000000..98076bd --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Portability/Statement.php @@ -0,0 +1,195 @@ +. + */ + +namespace Doctrine\DBAL\Portability; + +use PDO; + +/** + * Portability Wrapper for a Statement + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + */ +class Statement implements \IteratorAggregate, \Doctrine\DBAL\Driver\Statement +{ + + /** + * @var int + */ + private $portability; + + /** + * @var \Doctrine\DBAL\Driver\Statement + */ + private $stmt; + + /** + * @var int + */ + private $case; + + /** + * @var int + */ + private $defaultFetchMode = PDO::FETCH_BOTH; + + /** + * Wraps Statement and applies portability measures + * + * @param \Doctrine\DBAL\Driver\Statement $stmt + * @param \Doctrine\DBAL\Connection $conn + */ + public function __construct($stmt, Connection $conn) + { + $this->stmt = $stmt; + $this->portability = $conn->getPortability(); + $this->case = $conn->getFetchCase(); + } + + public function bindParam($column, &$variable, $type = null,$length = null) + { + return $this->stmt->bindParam($column, $variable, $type); + } + + public function bindValue($param, $value, $type = null) + { + return $this->stmt->bindValue($param, $value, $type); + } + + public function closeCursor() + { + return $this->stmt->closeCursor(); + } + + public function columnCount() + { + return $this->stmt->columnCount(); + } + + public function errorCode() + { + return $this->stmt->errorCode(); + } + + public function errorInfo() + { + return $this->stmt->errorInfo(); + } + + public function execute($params = null) + { + return $this->stmt->execute($params); + } + + public function setFetchMode($fetchMode, $arg1 = null, $arg2 = null) + { + $this->defaultFetchMode = $fetchMode; + $this->stmt->setFetchMode($fetchMode, $arg1, $arg2); + } + + public function getIterator() + { + $data = $this->fetchAll(); + return new \ArrayIterator($data); + } + + public function fetch($fetchMode = null) + { + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + + $row = $this->stmt->fetch($fetchMode); + + $row = $this->fixRow($row, + $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM), + !is_null($this->case) && ($fetchMode == PDO::FETCH_ASSOC || $fetchMode == PDO::FETCH_BOTH) && ($this->portability & Connection::PORTABILITY_FIX_CASE) + ); + + return $row; + } + + public function fetchAll($fetchMode = null, $columnIndex = 0) + { + $fetchMode = $fetchMode ?: $this->defaultFetchMode; + + if ($columnIndex != 0) { + $rows = $this->stmt->fetchAll($fetchMode, $columnIndex); + } else { + $rows = $this->stmt->fetchAll($fetchMode); + } + + $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); + $fixCase = !is_null($this->case) && ($fetchMode == PDO::FETCH_ASSOC || $fetchMode == PDO::FETCH_BOTH) && ($this->portability & Connection::PORTABILITY_FIX_CASE); + if ( ! $iterateRow && !$fixCase) { + return $rows; + } + + foreach ($rows as $num => $row) { + $rows[$num] = $this->fixRow($row, $iterateRow, $fixCase); + } + + return $rows; + } + + protected function fixRow($row, $iterateRow, $fixCase) + { + if ( ! $row) { + return $row; + } + + if ($fixCase) { + $row = array_change_key_case($row, $this->case); + } + + if ($iterateRow) { + foreach ($row as $k => $v) { + if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) && $v === '') { + $row[$k] = null; + } else if (($this->portability & Connection::PORTABILITY_RTRIM) && is_string($v)) { + $row[$k] = rtrim($v); + } + } + } + return $row; + } + + public function fetchColumn($columnIndex = 0) + { + $value = $this->stmt->fetchColumn($columnIndex); + + if ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) { + if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) && $value === '') { + $value = null; + } else if (($this->portability & Connection::PORTABILITY_RTRIM) && is_string($value)) { + $value = rtrim($value); + } + } + + return $value; + } + + public function rowCount() + { + return $this->stmt->rowCount(); + } + +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php new file mode 100644 index 0000000..5d55b22 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php @@ -0,0 +1,130 @@ +. + */ + +namespace Doctrine\DBAL\Query\Expression; + +/** + * Composite expression is responsible to build a group of similar expression. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.1 + * @author Guilherme Blanco + * @author Benjamin Eberlei + */ +class CompositeExpression implements \Countable +{ + /** + * Constant that represents an AND composite expression + */ + const TYPE_AND = 'AND'; + + /** + * Constant that represents an OR composite expression + */ + const TYPE_OR = 'OR'; + + /** + * @var string Holds the instance type of composite expression + */ + private $type; + + /** + * @var array Each expression part of the composite expression + */ + private $parts = array(); + + /** + * Constructor. + * + * @param string $type Instance type of composite expression + * @param array $parts Composition of expressions to be joined on composite expression + */ + public function __construct($type, array $parts = array()) + { + $this->type = $type; + + $this->addMultiple($parts); + } + + /** + * Adds multiple parts to composite expression. + * + * @param array $parts + * + * @return CompositeExpression + */ + public function addMultiple(array $parts = array()) + { + foreach ((array) $parts as $part) { + $this->add($part); + } + + return $this; + } + + /** + * Adds an expression to composite expression. + * + * @param mixed $part + * @return CompositeExpression + */ + public function add($part) + { + if ( ! empty($part) || ($part instanceof self && $part->count() > 0)) { + $this->parts[] = $part; + } + + return $this; + } + + /** + * Retrieves the amount of expressions on composite expression. + * + * @return integer + */ + public function count() + { + return count($this->parts); + } + + /** + * Retrieve the string representation of this composite expression. + * + * @return string + */ + public function __toString() + { + if (count($this->parts) === 1) { + return (string) $this->parts[0]; + } + + return '(' . implode(') ' . $this->type . ' (', $this->parts) . ')'; + } + + /** + * Return type of this composite expression (AND/OR) + * + * @return string + */ + public function getType() + { + return $this->type; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php new file mode 100644 index 0000000..4f50232 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php @@ -0,0 +1,264 @@ +. + */ + +namespace Doctrine\DBAL\Query\Expression; + +use Doctrine\DBAL\Connection; + +/** + * ExpressionBuilder class is responsible to dynamically create SQL query parts. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.1 + * @author Guilherme Blanco + * @author Benjamin Eberlei + */ +class ExpressionBuilder +{ + const EQ = '='; + const NEQ = '<>'; + const LT = '<'; + const LTE = '<='; + const GT = '>'; + const GTE = '>='; + + /** + * @var Doctrine\DBAL\Connection DBAL Connection + */ + private $connection = null; + + /** + * Initializes a new ExpressionBuilder. + * + * @param \Doctrine\DBAL\Connection $connection DBAL Connection + */ + public function __construct(Connection $connection) + { + $this->connection = $connection; + } + + /** + * Creates a conjunction of the given boolean expressions. + * + * Example: + * + * [php] + * // (u.type = ?) AND (u.role = ?) + * $expr->andX('u.type = ?', 'u.role = ?')); + * + * @param mixed $x Optional clause. Defaults = null, but requires + * at least one defined when converting to string. + * @return CompositeExpression + */ + public function andX($x = null) + { + return new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args()); + } + + /** + * Creates a disjunction of the given boolean expressions. + * + * Example: + * + * [php] + * // (u.type = ?) OR (u.role = ?) + * $qb->where($qb->expr()->orX('u.type = ?', 'u.role = ?')); + * + * @param mixed $x Optional clause. Defaults = null, but requires + * at least one defined when converting to string. + * @return CompositeExpression + */ + public function orX($x = null) + { + return new CompositeExpression(CompositeExpression::TYPE_OR, func_get_args()); + } + + /** + * Creates a comparison expression. + * + * @param mixed $x Left expression + * @param string $operator One of the ExpressionBuilder::* constants. + * @param mixed $y Right expression + * @return string + */ + public function comparison($x, $operator, $y) + { + return $x . ' ' . $operator . ' ' . $y; + } + + /** + * Creates an equality comparison expression with the given arguments. + * + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a = . Example: + * + * [php] + * // u.id = ? + * $expr->eq('u.id', '?'); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return string + */ + public function eq($x, $y) + { + return $this->comparison($x, self::EQ, $y); + } + + /** + * Creates a non equality comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a <> . Example: + * + * [php] + * // u.id <> 1 + * $q->where($q->expr()->neq('u.id', '1')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return string + */ + public function neq($x, $y) + { + return $this->comparison($x, self::NEQ, $y); + } + + /** + * Creates a lower-than comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a < . Example: + * + * [php] + * // u.id < ? + * $q->where($q->expr()->lt('u.id', '?')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return string + */ + public function lt($x, $y) + { + return $this->comparison($x, self::LT, $y); + } + + /** + * Creates a lower-than-equal comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a <= . Example: + * + * [php] + * // u.id <= ? + * $q->where($q->expr()->lte('u.id', '?')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return string + */ + public function lte($x, $y) + { + return $this->comparison($x, self::LTE, $y); + } + + /** + * Creates a greater-than comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a > . Example: + * + * [php] + * // u.id > ? + * $q->where($q->expr()->gt('u.id', '?')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return string + */ + public function gt($x, $y) + { + return $this->comparison($x, self::GT, $y); + } + + /** + * Creates a greater-than-equal comparison expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a >= . Example: + * + * [php] + * // u.id >= ? + * $q->where($q->expr()->gte('u.id', '?')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return string + */ + public function gte($x, $y) + { + return $this->comparison($x, self::GTE, $y); + } + + /** + * Creates an IS NULL expression with the given arguments. + * + * @param string $x Field in string format to be restricted by IS NULL + * + * @return string + */ + public function isNull($x) + { + return $x . ' IS NULL'; + } + + /** + * Creates an IS NOT NULL expression with the given arguments. + * + * @param string $x Field in string format to be restricted by IS NOT NULL + * + * @return string + */ + public function isNotNull($x) + { + return $x . ' IS NOT NULL'; + } + + /** + * Creates a LIKE() comparison expression with the given arguments. + * + * @param string $x Field in string format to be inspected by LIKE() comparison. + * @param mixed $y Argument to be used in LIKE() comparison. + * + * @return string + */ + public function like($x, $y) + { + return $this->comparison($x, 'LIKE', $y); + } + + /** + * Quotes a given input parameter. + * + * @param mixed $input Parameter to be quoted. + * @param string $type Type of the parameter. + * + * @return string + */ + public function literal($input, $type = null) + { + return $this->connection->quote($input, $type); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php new file mode 100644 index 0000000..e0c5af1 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryBuilder.php @@ -0,0 +1,1087 @@ +. + */ + +namespace Doctrine\DBAL\Query; + +use Doctrine\DBAL\Query\Expression\CompositeExpression, + Doctrine\DBAL\Connection; + +/** + * QueryBuilder class is responsible to dynamically create SQL queries. + * + * Important: Verify that every feature you use will work with your database vendor. + * SQL Query Builder does not attempt to validate the generated SQL at all. + * + * The query builder does no validation whatsoever if certain features even work with the + * underlying database vendor. Limit queries and joins are NOT applied to UPDATE and DELETE statements + * even if some vendors such as MySQL support it. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.1 + * @author Guilherme Blanco + * @author Benjamin Eberlei + */ +class QueryBuilder +{ + /* The query types. */ + const SELECT = 0; + const DELETE = 1; + const UPDATE = 2; + + /** The builder states. */ + const STATE_DIRTY = 0; + const STATE_CLEAN = 1; + + /** + * @var Doctrine\DBAL\Connection DBAL Connection + */ + private $connection = null; + + /** + * @var array The array of SQL parts collected. + */ + private $sqlParts = array( + 'select' => array(), + 'from' => array(), + 'join' => array(), + 'set' => array(), + 'where' => null, + 'groupBy' => array(), + 'having' => null, + 'orderBy' => array() + ); + + /** + * @var string The complete SQL string for this query. + */ + private $sql; + + /** + * @var array The query parameters. + */ + private $params = array(); + + /** + * @var array The parameter type map of this query. + */ + private $paramTypes = array(); + + /** + * @var integer The type of query this is. Can be select, update or delete. + */ + private $type = self::SELECT; + + /** + * @var integer The state of the query object. Can be dirty or clean. + */ + private $state = self::STATE_CLEAN; + + /** + * @var integer The index of the first result to retrieve. + */ + private $firstResult = null; + + /** + * @var integer The maximum number of results to retrieve. + */ + private $maxResults = null; + + /** + * The counter of bound parameters used with {@see bindValue) + * + * @var int + */ + private $boundCounter = 0; + + /** + * Initializes a new QueryBuilder. + * + * @param \Doctrine\DBAL\Connection $connection DBAL Connection + */ + public function __construct(Connection $connection) + { + $this->connection = $connection; + } + + /** + * Gets an ExpressionBuilder used for object-oriented construction of query expressions. + * This producer method is intended for convenient inline usage. Example: + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u') + * ->from('users', 'u') + * ->where($qb->expr()->eq('u.id', 1)); + * + * + * For more complex expression construction, consider storing the expression + * builder object in a local variable. + * + * @return \Doctrine\DBAL\Query\Expression\ExpressionBuilder + */ + public function expr() + { + return $this->connection->getExpressionBuilder(); + } + + /** + * Get the type of the currently built query. + * + * @return integer + */ + public function getType() + { + return $this->type; + } + + /** + * Get the associated DBAL Connection for this query builder. + * + * @return \Doctrine\DBAL\Connection + */ + public function getConnection() + { + return $this->connection; + } + + /** + * Get the state of this query builder instance. + * + * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN. + */ + public function getState() + { + return $this->state; + } + + /** + * Execute this query using the bound parameters and their types. + * + * Uses {@see Connection::executeQuery} for select statements and {@see Connection::executeUpdate} + * for insert, update and delete statements. + * + * @return mixed + */ + public function execute() + { + if ($this->type == self::SELECT) { + return $this->connection->executeQuery($this->getSQL(), $this->params, $this->paramTypes); + } else { + return $this->connection->executeUpdate($this->getSQL(), $this->params, $this->paramTypes); + } + } + + /** + * Get the complete SQL string formed by the current specifications of this QueryBuilder. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * echo $qb->getSQL(); // SELECT u FROM User u + * + * + * @return string The sql query string. + */ + public function getSQL() + { + if ($this->sql !== null && $this->state === self::STATE_CLEAN) { + return $this->sql; + } + + $sql = ''; + + switch ($this->type) { + case self::DELETE: + $sql = $this->getSQLForDelete(); + break; + + case self::UPDATE: + $sql = $this->getSQLForUpdate(); + break; + + case self::SELECT: + default: + $sql = $this->getSQLForSelect(); + break; + } + + $this->state = self::STATE_CLEAN; + $this->sql = $sql; + + return $sql; + } + + /** + * Sets a query parameter for the query being constructed. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u') + * ->from('users', 'u') + * ->where('u.id = :user_id') + * ->setParameter(':user_id', 1); + * + * + * @param string|integer $key The parameter position or name. + * @param mixed $value The parameter value. + * @param string|null $type PDO::PARAM_* + * @return QueryBuilder This QueryBuilder instance. + */ + public function setParameter($key, $value, $type = null) + { + if ($type !== null) { + $this->paramTypes[$key] = $type; + } + + $this->params[$key] = $value; + + return $this; + } + + /** + * Sets a collection of query parameters for the query being constructed. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u') + * ->from('users', 'u') + * ->where('u.id = :user_id1 OR u.id = :user_id2') + * ->setParameters(array( + * ':user_id1' => 1, + * ':user_id2' => 2 + * )); + * + * + * @param array $params The query parameters to set. + * @param array $types The query parameters types to set. + * @return QueryBuilder This QueryBuilder instance. + */ + public function setParameters(array $params, array $types = array()) + { + $this->paramTypes = $types; + $this->params = $params; + + return $this; + } + + /** + * Gets all defined query parameters for the query being constructed. + * + * @return array The currently defined query parameters. + */ + public function getParameters() + { + return $this->params; + } + + /** + * Gets a (previously set) query parameter of the query being constructed. + * + * @param mixed $key The key (index or name) of the bound parameter. + * @return mixed The value of the bound parameter. + */ + public function getParameter($key) + { + return isset($this->params[$key]) ? $this->params[$key] : null; + } + + /** + * Sets the position of the first result to retrieve (the "offset"). + * + * @param integer $firstResult The first result to return. + * @return \Doctrine\DBAL\Query\QueryBuilder This QueryBuilder instance. + */ + public function setFirstResult($firstResult) + { + $this->state = self::STATE_DIRTY; + $this->firstResult = $firstResult; + return $this; + } + + /** + * Gets the position of the first result the query object was set to retrieve (the "offset"). + * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder. + * + * @return integer The position of the first result. + */ + public function getFirstResult() + { + return $this->firstResult; + } + + /** + * Sets the maximum number of results to retrieve (the "limit"). + * + * @param integer $maxResults The maximum number of results to retrieve. + * @return \Doctrine\DBAL\Query\QueryBuilder This QueryBuilder instance. + */ + public function setMaxResults($maxResults) + { + $this->state = self::STATE_DIRTY; + $this->maxResults = $maxResults; + return $this; + } + + /** + * Gets the maximum number of results the query object was set to retrieve (the "limit"). + * Returns NULL if {@link setMaxResults} was not applied to this query builder. + * + * @return integer Maximum number of results. + */ + public function getMaxResults() + { + return $this->maxResults; + } + + /** + * Either appends to or replaces a single, generic query part. + * + * The available parts are: 'select', 'from', 'set', 'where', + * 'groupBy', 'having' and 'orderBy'. + * + * @param string $sqlPartName + * @param string $sqlPart + * @param boolean $append + * @return \Doctrine\DBAL\Query\QueryBuilder This QueryBuilder instance. + */ + public function add($sqlPartName, $sqlPart, $append = false) + { + $isArray = is_array($sqlPart); + $isMultiple = is_array($this->sqlParts[$sqlPartName]); + + if ($isMultiple && !$isArray) { + $sqlPart = array($sqlPart); + } + + $this->state = self::STATE_DIRTY; + + if ($append) { + if ($sqlPartName == "orderBy" || $sqlPartName == "groupBy" || $sqlPartName == "select" || $sqlPartName == "set") { + foreach ($sqlPart as $part) { + $this->sqlParts[$sqlPartName][] = $part; + } + } else if ($isArray && is_array($sqlPart[key($sqlPart)])) { + $key = key($sqlPart); + $this->sqlParts[$sqlPartName][$key][] = $sqlPart[$key]; + } else if ($isMultiple) { + $this->sqlParts[$sqlPartName][] = $sqlPart; + } else { + $this->sqlParts[$sqlPartName] = $sqlPart; + } + + return $this; + } + + $this->sqlParts[$sqlPartName] = $sqlPart; + + return $this; + } + + /** + * Specifies an item that is to be returned in the query result. + * Replaces any previously specified selections, if any. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.id', 'p.id') + * ->from('users', 'u') + * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id'); + * + * + * @param mixed $select The selection expressions. + * @return QueryBuilder This QueryBuilder instance. + */ + public function select($select = null) + { + $this->type = self::SELECT; + + if (empty($select)) { + return $this; + } + + $selects = is_array($select) ? $select : func_get_args(); + + return $this->add('select', $selects, false); + } + + /** + * Adds an item that is to be returned in the query result. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.id') + * ->addSelect('p.id') + * ->from('users', 'u') + * ->leftJoin('u', 'phonenumbers', 'u.id = p.user_id'); + * + * + * @param mixed $select The selection expression. + * @return QueryBuilder This QueryBuilder instance. + */ + public function addSelect($select = null) + { + $this->type = self::SELECT; + + if (empty($select)) { + return $this; + } + + $selects = is_array($select) ? $select : func_get_args(); + + return $this->add('select', $selects, true); + } + + /** + * Turns the query being built into a bulk delete query that ranges over + * a certain table. + * + * + * $qb = $conn->createQueryBuilder() + * ->delete('users', 'u') + * ->where('u.id = :user_id'); + * ->setParameter(':user_id', 1); + * + * + * @param string $delete The table whose rows are subject to the deletion. + * @param string $alias The table alias used in the constructed query. + * @return QueryBuilder This QueryBuilder instance. + */ + public function delete($delete = null, $alias = null) + { + $this->type = self::DELETE; + + if ( ! $delete) { + return $this; + } + + return $this->add('from', array( + 'table' => $delete, + 'alias' => $alias + )); + } + + /** + * Turns the query being built into a bulk update query that ranges over + * a certain table + * + * + * $qb = $conn->createQueryBuilder() + * ->update('users', 'u') + * ->set('u.password', md5('password')) + * ->where('u.id = ?'); + * + * + * @param string $update The table whose rows are subject to the update. + * @param string $alias The table alias used in the constructed query. + * @return QueryBuilder This QueryBuilder instance. + */ + public function update($update = null, $alias = null) + { + $this->type = self::UPDATE; + + if ( ! $update) { + return $this; + } + + return $this->add('from', array( + 'table' => $update, + 'alias' => $alias + )); + } + + /** + * Create and add a query root corresponding to the table identified by the + * given alias, forming a cartesian product with any existing query roots. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.id') + * ->from('users', 'u') + * + * + * @param string $from The table + * @param string $alias The alias of the table + * @return QueryBuilder This QueryBuilder instance. + */ + public function from($from, $alias) + { + return $this->add('from', array( + 'table' => $from, + 'alias' => $alias + ), true); + } + + /** + * Creates and adds a join to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->join('u', 'phonenumbers', 'p', 'p.is_primary = 1'); + * + * + * @param string $fromAlias The alias that points to a from clause + * @param string $join The table name to join + * @param string $alias The alias of the join table + * @param string $condition The condition for the join + * @return QueryBuilder This QueryBuilder instance. + */ + public function join($fromAlias, $join, $alias, $condition = null) + { + return $this->innerJoin($fromAlias, $join, $alias, $condition); + } + + /** + * Creates and adds a join to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->innerJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); + * + * + * @param string $fromAlias The alias that points to a from clause + * @param string $join The table name to join + * @param string $alias The alias of the join table + * @param string $condition The condition for the join + * @return QueryBuilder This QueryBuilder instance. + */ + public function innerJoin($fromAlias, $join, $alias, $condition = null) + { + return $this->add('join', array( + $fromAlias => array( + 'joinType' => 'inner', + 'joinTable' => $join, + 'joinAlias' => $alias, + 'joinCondition' => $condition + ) + ), true); + } + + /** + * Creates and adds a left join to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->leftJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); + * + * + * @param string $fromAlias The alias that points to a from clause + * @param string $join The table name to join + * @param string $alias The alias of the join table + * @param string $condition The condition for the join + * @return QueryBuilder This QueryBuilder instance. + */ + public function leftJoin($fromAlias, $join, $alias, $condition = null) + { + return $this->add('join', array( + $fromAlias => array( + 'joinType' => 'left', + 'joinTable' => $join, + 'joinAlias' => $alias, + 'joinCondition' => $condition + ) + ), true); + } + + /** + * Creates and adds a right join to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->rightJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); + * + * + * @param string $fromAlias The alias that points to a from clause + * @param string $join The table name to join + * @param string $alias The alias of the join table + * @param string $condition The condition for the join + * @return QueryBuilder This QueryBuilder instance. + */ + public function rightJoin($fromAlias, $join, $alias, $condition = null) + { + return $this->add('join', array( + $fromAlias => array( + 'joinType' => 'right', + 'joinTable' => $join, + 'joinAlias' => $alias, + 'joinCondition' => $condition + ) + ), true); + } + + /** + * Sets a new value for a column in a bulk update query. + * + * + * $qb = $conn->createQueryBuilder() + * ->update('users', 'u') + * ->set('u.password', md5('password')) + * ->where('u.id = ?'); + * + * + * @param string $key The column to set. + * @param string $value The value, expression, placeholder, etc. + * @return QueryBuilder This QueryBuilder instance. + */ + public function set($key, $value) + { + return $this->add('set', $key .' = ' . $value, true); + } + + /** + * Specifies one or more restrictions to the query result. + * Replaces any previously specified restrictions, if any. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->where('u.id = ?'); + * + * // You can optionally programatically build and/or expressions + * $qb = $conn->createQueryBuilder(); + * + * $or = $qb->expr()->orx(); + * $or->add($qb->expr()->eq('u.id', 1)); + * $or->add($qb->expr()->eq('u.id', 2)); + * + * $qb->update('users', 'u') + * ->set('u.password', md5('password')) + * ->where($or); + * + * + * @param mixed $predicates The restriction predicates. + * @return QueryBuilder This QueryBuilder instance. + */ + public function where($predicates) + { + if ( ! (func_num_args() == 1 && $predicates instanceof CompositeExpression) ) { + $predicates = new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args()); + } + + return $this->add('where', $predicates); + } + + /** + * Adds one or more restrictions to the query results, forming a logical + * conjunction with any previously specified restrictions. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u') + * ->from('users', 'u') + * ->where('u.username LIKE ?') + * ->andWhere('u.is_active = 1'); + * + * + * @param mixed $where The query restrictions. + * @return QueryBuilder This QueryBuilder instance. + * @see where() + */ + public function andWhere($where) + { + $where = $this->getQueryPart('where'); + $args = func_get_args(); + + if ($where instanceof CompositeExpression && $where->getType() === CompositeExpression::TYPE_AND) { + $where->addMultiple($args); + } else { + array_unshift($args, $where); + $where = new CompositeExpression(CompositeExpression::TYPE_AND, $args); + } + + return $this->add('where', $where, true); + } + + /** + * Adds one or more restrictions to the query results, forming a logical + * disjunction with any previously specified restrictions. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->where('u.id = 1') + * ->orWhere('u.id = 2'); + * + * + * @param mixed $where The WHERE statement + * @return QueryBuilder $qb + * @see where() + */ + public function orWhere($where) + { + $where = $this->getQueryPart('where'); + $args = func_get_args(); + + if ($where instanceof CompositeExpression && $where->getType() === CompositeExpression::TYPE_OR) { + $where->addMultiple($args); + } else { + array_unshift($args, $where); + $where = new CompositeExpression(CompositeExpression::TYPE_OR, $args); + } + + return $this->add('where', $where, true); + } + + /** + * Specifies a grouping over the results of the query. + * Replaces any previously specified groupings, if any. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->groupBy('u.id'); + * + * + * @param mixed $groupBy The grouping expression. + * @return QueryBuilder This QueryBuilder instance. + */ + public function groupBy($groupBy) + { + if (empty($groupBy)) { + return $this; + } + + $groupBy = is_array($groupBy) ? $groupBy : func_get_args(); + + return $this->add('groupBy', $groupBy, false); + } + + + /** + * Adds a grouping expression to the query. + * + * + * $qb = $conn->createQueryBuilder() + * ->select('u.name') + * ->from('users', 'u') + * ->groupBy('u.lastLogin'); + * ->addGroupBy('u.createdAt') + * + * + * @param mixed $groupBy The grouping expression. + * @return QueryBuilder This QueryBuilder instance. + */ + public function addGroupBy($groupBy) + { + if (empty($groupBy)) { + return $this; + } + + $groupBy = is_array($groupBy) ? $groupBy : func_get_args(); + + return $this->add('groupBy', $groupBy, true); + } + + /** + * Specifies a restriction over the groups of the query. + * Replaces any previous having restrictions, if any. + * + * @param mixed $having The restriction over the groups. + * @return QueryBuilder This QueryBuilder instance. + */ + public function having($having) + { + if ( ! (func_num_args() == 1 && $having instanceof CompositeExpression)) { + $having = new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args()); + } + + return $this->add('having', $having); + } + + /** + * Adds a restriction over the groups of the query, forming a logical + * conjunction with any existing having restrictions. + * + * @param mixed $having The restriction to append. + * @return QueryBuilder This QueryBuilder instance. + */ + public function andHaving($having) + { + $having = $this->getQueryPart('having'); + $args = func_get_args(); + + if ($having instanceof CompositeExpression && $having->getType() === CompositeExpression::TYPE_AND) { + $having->addMultiple($args); + } else { + array_unshift($args, $having); + $having = new CompositeExpression(CompositeExpression::TYPE_AND, $args); + } + + return $this->add('having', $having); + } + + /** + * Adds a restriction over the groups of the query, forming a logical + * disjunction with any existing having restrictions. + * + * @param mixed $having The restriction to add. + * @return QueryBuilder This QueryBuilder instance. + */ + public function orHaving($having) + { + $having = $this->getQueryPart('having'); + $args = func_get_args(); + + if ($having instanceof CompositeExpression && $having->getType() === CompositeExpression::TYPE_OR) { + $having->addMultiple($args); + } else { + array_unshift($args, $having); + $having = new CompositeExpression(CompositeExpression::TYPE_OR, $args); + } + + return $this->add('having', $having); + } + + /** + * Specifies an ordering for the query results. + * Replaces any previously specified orderings, if any. + * + * @param string $sort The ordering expression. + * @param string $order The ordering direction. + * @return QueryBuilder This QueryBuilder instance. + */ + public function orderBy($sort, $order = null) + { + return $this->add('orderBy', $sort . ' ' . (! $order ? 'ASC' : $order), false); + } + + /** + * Adds an ordering to the query results. + * + * @param string $sort The ordering expression. + * @param string $order The ordering direction. + * @return QueryBuilder This QueryBuilder instance. + */ + public function addOrderBy($sort, $order = null) + { + return $this->add('orderBy', $sort . ' ' . (! $order ? 'ASC' : $order), true); + } + + /** + * Get a query part by its name. + * + * @param string $queryPartName + * @return mixed $queryPart + */ + public function getQueryPart($queryPartName) + { + return $this->sqlParts[$queryPartName]; + } + + /** + * Get all query parts. + * + * @return array $sqlParts + */ + public function getQueryParts() + { + return $this->sqlParts; + } + + /** + * Reset SQL parts + * + * @param array $queryPartNames + * @return QueryBuilder + */ + public function resetQueryParts($queryPartNames = null) + { + if (is_null($queryPartNames)) { + $queryPartNames = array_keys($this->sqlParts); + } + + foreach ($queryPartNames as $queryPartName) { + $this->resetQueryPart($queryPartName); + } + + return $this; + } + + /** + * Reset single SQL part + * + * @param string $queryPartName + * @return QueryBuilder + */ + public function resetQueryPart($queryPartName) + { + $this->sqlParts[$queryPartName] = is_array($this->sqlParts[$queryPartName]) + ? array() : null; + + $this->state = self::STATE_DIRTY; + + return $this; + } + + private function getSQLForSelect() + { + $query = 'SELECT ' . implode(', ', $this->sqlParts['select']) . ' FROM '; + + $fromClauses = array(); + + // Loop through all FROM clauses + foreach ($this->sqlParts['from'] as $from) { + $fromClause = $from['table'] . ' ' . $from['alias']; + + if (isset($this->sqlParts['join'][$from['alias']])) { + foreach ($this->sqlParts['join'][$from['alias']] as $join) { + $fromClause .= ' ' . strtoupper($join['joinType']) + . ' JOIN ' . $join['joinTable'] . ' ' . $join['joinAlias'] + . ' ON ' . ((string) $join['joinCondition']); + } + } + + $fromClauses[$from['alias']] = $fromClause; + } + + // loop through all JOIN clasues for validation purpose + foreach ($this->sqlParts['join'] as $fromAlias => $joins) { + if ( ! isset($fromClauses[$fromAlias]) ) { + throw QueryException::unknownFromAlias($fromAlias, array_keys($fromClauses)); + } + } + + $query .= implode(', ', $fromClauses) + . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '') + . ($this->sqlParts['groupBy'] ? ' GROUP BY ' . implode(', ', $this->sqlParts['groupBy']) : '') + . ($this->sqlParts['having'] !== null ? ' HAVING ' . ((string) $this->sqlParts['having']) : '') + . ($this->sqlParts['orderBy'] ? ' ORDER BY ' . implode(', ', $this->sqlParts['orderBy']) : ''); + + return ($this->maxResults === null && $this->firstResult == null) + ? $query + : $this->connection->getDatabasePlatform()->modifyLimitQuery($query, $this->maxResults, $this->firstResult); + } + + /** + * Converts this instance into an UPDATE string in SQL. + * + * @return string + */ + private function getSQLForUpdate() + { + $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); + $query = 'UPDATE ' . $table + . ' SET ' . implode(", ", $this->sqlParts['set']) + . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); + + return $query; + } + + /** + * Converts this instance into a DELETE string in SQL. + * + * @return string + */ + private function getSQLForDelete() + { + $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); + $query = 'DELETE FROM ' . $table . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); + + return $query; + } + + /** + * Gets a string representation of this QueryBuilder which corresponds to + * the final SQL query being constructed. + * + * @return string The string representation of this QueryBuilder. + */ + public function __toString() + { + return $this->getSQL(); + } + + /** + * Create a new named parameter and bind the value $value to it. + * + * This method provides a shortcut for PDOStatement::bindValue + * when using prepared statements. + * + * The parameter $value specifies the value that you want to bind. If + * $placeholder is not provided bindValue() will automatically create a + * placeholder for you. An automatic placeholder will be of the name + * ':dcValue1', ':dcValue2' etc. + * + * For more information see {@link http://php.net/pdostatement-bindparam} + * + * Example: + * + * $value = 2; + * $q->eq( 'id', $q->bindValue( $value ) ); + * $stmt = $q->executeQuery(); // executed with 'id = 2' + * + * + * @license New BSD License + * @link http://www.zetacomponents.org + * @param mixed $value + * @param mixed $type + * @param string $placeHolder the name to bind with. The string must start with a colon ':'. + * @return string the placeholder name used. + */ + public function createNamedParameter( $value, $type = \PDO::PARAM_STR, $placeHolder = null ) + { + if ( $placeHolder === null ) { + $this->boundCounter++; + $placeHolder = ":dcValue" . $this->boundCounter; + } + $this->setParameter(substr($placeHolder, 1), $value, $type); + + return $placeHolder; + } + + /** + * Create a new positional parameter and bind the given value to it. + * + * Attention: If you are using positional parameters with the query builder you have + * to be very careful to bind all parameters in the order they appear in the SQL + * statement , otherwise they get bound in the wrong order which can lead to serious + * bugs in your code. + * + * Example: + * + * $qb = $conn->createQueryBuilder(); + * $qb->select('u.*') + * ->from('users', 'u') + * ->where('u.username = ' . $qb->createPositionalParameter('Foo', PDO::PARAM_STR)) + * ->orWhere('u.username = ' . $qb->createPositionalParameter('Bar', PDO::PARAM_STR)) + * + * + * @param mixed $value + * @param mixed $type + * @return string + */ + public function createPositionalParameter($value, $type = \PDO::PARAM_STR) + { + $this->boundCounter++; + $this->setParameter($this->boundCounter, $value, $type); + return "?"; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryException.php new file mode 100644 index 0000000..addc745 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Query/QueryException.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\DBAL\Query; + +use Doctrine\DBAL\DBALException; + +/** + * Driver interface. + * Interface that all DBAL drivers must implement. + * + * @since 2.1.4 + */ +class QueryException extends DBALException +{ + static public function unknownFromAlias($alias, $registeredAliases) + { + return new self("The given alias '" . $alias . "' is not part of " . + "any FROM clause table. The currently registered FROM-clause " . + "aliases are: " . implode(", ", $registeredAliases) . ". Join clauses " . + "are bound to from clauses to provide support for mixing of multiple " . + "from and join clauses."); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/README.markdown b/vendor/doctrine/dbal/lib/Doctrine/DBAL/README.markdown new file mode 100644 index 0000000..e69de29 diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php new file mode 100644 index 0000000..65ba25e --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/SQLParserUtils.php @@ -0,0 +1,183 @@ +. + */ + + +namespace Doctrine\DBAL; + +use Doctrine\DBAL\Connection; + +/** + * Utility class that parses sql statements with regard to types and parameters. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + */ +class SQLParserUtils +{ + /** + * Get an array of the placeholders in an sql statements as keys and their positions in the query string. + * + * Returns an integer => integer pair (indexed from zero) for a positional statement + * and a string => int[] pair for a named statement. + * + * @param string $statement + * @param bool $isPositional + * @return array + */ + static public function getPlaceholderPositions($statement, $isPositional = true) + { + $match = ($isPositional) ? '?' : ':'; + if (strpos($statement, $match) === false) { + return array(); + } + + $count = 0; + $inLiteral = false; // a valid query never starts with quotes + $stmtLen = strlen($statement); + $paramMap = array(); + for ($i = 0; $i < $stmtLen; $i++) { + if ($statement[$i] == $match && !$inLiteral) { + // real positional parameter detected + if ($isPositional) { + $paramMap[$count] = $i; + } else { + $name = ""; + // TODO: Something faster/better to match this than regex? + for ($j = $i + 1; ($j < $stmtLen && preg_match('(([a-zA-Z0-9_]{1}))', $statement[$j])); $j++) { + $name .= $statement[$j]; + } + $paramMap[$i] = $name; // named parameters can be duplicated! + $i = $j; + } + ++$count; + } else if ($statement[$i] == "'" || $statement[$i] == '"') { + $inLiteral = ! $inLiteral; // switch state! + } + } + + return $paramMap; + } + + /** + * For a positional query this method can rewrite the sql statement with regard to array parameters. + * + * @param string $query The SQL query to execute. + * @param array $params The parameters to bind to the query. + * @param array $types The types the previous parameters are in. + * + * @return array + */ + static public function expandListParameters($query, $params, $types) + { + $isPositional = is_int(key($params)); + $arrayPositions = array(); + $bindIndex = -1; + + foreach ($types as $name => $type) { + ++$bindIndex; + + if ($type !== Connection::PARAM_INT_ARRAY && $type !== Connection::PARAM_STR_ARRAY) { + continue; + } + + if ($isPositional) { + $name = $bindIndex; + } + + $arrayPositions[$name] = false; + } + + if (( ! $arrayPositions && $isPositional) || (count($params) != count($types))) { + return array($query, $params, $types); + } + + $paramPos = self::getPlaceholderPositions($query, $isPositional); + + if ($isPositional) { + $paramOffset = 0; + $queryOffset = 0; + + foreach ($paramPos as $needle => $needlePos) { + if ( ! isset($arrayPositions[$needle])) { + continue; + } + + $needle += $paramOffset; + $needlePos += $queryOffset; + $count = count($params[$needle]); + + $params = array_merge( + array_slice($params, 0, $needle), + $params[$needle], + array_slice($params, $needle + 1) + ); + + $types = array_merge( + array_slice($types, 0, $needle), + array_fill(0, $count, $types[$needle] - Connection::ARRAY_PARAM_OFFSET), // array needles are at PDO::PARAM_* + 100 + array_slice($types, $needle + 1) + ); + + $expandStr = implode(", ", array_fill(0, $count, "?")); + $query = substr($query, 0, $needlePos) . $expandStr . substr($query, $needlePos + 1); + + $paramOffset += ($count - 1); // Grows larger by number of parameters minus the replaced needle. + $queryOffset += (strlen($expandStr) - 1); + } + + return array($query, $params, $types); + } + + + $queryOffset = 0; + $typesOrd = array(); + $paramsOrd = array(); + + foreach ($paramPos as $pos => $paramName) { + $paramLen = strlen($paramName) + 1; + $value = $params[$paramName]; + + if ( ! isset($arrayPositions[$paramName])) { + $pos += $queryOffset; + $queryOffset -= ($paramLen - 1); + $paramsOrd[] = $value; + $typesOrd[] = $types[$paramName]; + $query = substr($query, 0, $pos) . '?' . substr($query, ($pos + $paramLen)); + + continue; + } + + $count = count($value); + $expandStr = $count > 0 ? implode(', ', array_fill(0, $count, '?')) : '?'; + + foreach ($value as $val) { + $paramsOrd[] = $val; + $typesOrd[] = $types[$paramName] - Connection::ARRAY_PARAM_OFFSET; + } + + $pos += $queryOffset; + $queryOffset += (strlen($expandStr) - $paramLen); + $query = substr($query, 0, $pos) . $expandStr . substr($query, ($pos + $paramLen)); + } + + return array($query, $paramsOrd, $typesOrd); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractAsset.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractAsset.php new file mode 100644 index 0000000..17a9c0f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractAsset.php @@ -0,0 +1,214 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * The abstract asset allows to reset the name of all assets without publishing this to the public userland. + * + * This encapsulation hack is necessary to keep a consistent state of the database schema. Say we have a list of tables + * array($tableName => Table($tableName)); if you want to rename the table, you have to make sure + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + */ +abstract class AbstractAsset +{ + /** + * @var string + */ + protected $_name; + + /** + * Namespace of the asset. If none isset the default namespace is assumed. + * + * @var string + */ + protected $_namespace; + + /** + * @var bool + */ + protected $_quoted = false; + + /** + * Set name of this asset + * + * @param string $name + */ + protected function _setName($name) + { + if ($this->isIdentifierQuoted($name)) { + $this->_quoted = true; + $name = $this->trimQuotes($name); + } + if (strpos($name, ".") !== false) { + $parts = explode(".", $name); + $this->_namespace = $parts[0]; + $name = $parts[1]; + } + $this->_name = $name; + } + + /** + * Is this asset in the default namespace? + * + * @param string $defaultNamespaceName + * @return bool + */ + public function isInDefaultNamespace($defaultNamespaceName) + { + return $this->_namespace == $defaultNamespaceName || $this->_namespace === null; + } + + /** + * Get namespace name of this asset. + * + * If NULL is returned this means the default namespace is used. + * + * @return string + */ + public function getNamespaceName() + { + return $this->_namespace; + } + + /** + * The shortest name is stripped of the default namespace. All other + * namespaced elements are returned as full-qualified names. + * + * @param string + * @return string + */ + public function getShortestName($defaultNamespaceName) + { + $shortestName = $this->getName(); + if ($this->_namespace == $defaultNamespaceName) { + $shortestName = $this->_name; + } + return strtolower($shortestName); + } + + /** + * The normalized name is full-qualified and lowerspaced. Lowerspacing is + * actually wrong, but we have to do it to keep our sanity. If you are + * using database objects that only differentiate in the casing (FOO vs + * Foo) then you will NOT be able to use Doctrine Schema abstraction. + * + * Every non-namespaced element is prefixed with the default namespace + * name which is passed as argument to this method. + * + * @return string + */ + public function getFullQualifiedName($defaultNamespaceName) + { + $name = $this->getName(); + if ( ! $this->_namespace) { + $name = $defaultNamespaceName . "." . $name; + } + return strtolower($name); + } + + /** + * Check if this asset's name is quoted + * + * @return bool + */ + public function isQuoted() + { + return $this->_quoted; + } + + /** + * Check if this identifier is quoted. + * + * @param string $identifier + * @return bool + */ + protected function isIdentifierQuoted($identifier) + { + return (isset($identifier[0]) && ($identifier[0] == '`' || $identifier[0] == '"')); + } + + /** + * Trim quotes from the identifier. + * + * @param string $identifier + * @return string + */ + protected function trimQuotes($identifier) + { + return str_replace(array('`', '"'), '', $identifier); + } + + /** + * Return name of this schema asset. + * + * @return string + */ + public function getName() + { + if ($this->_namespace) { + return $this->_namespace . "." . $this->_name; + } + return $this->_name; + } + + /** + * Get the quoted representation of this asset but only if it was defined with one. Otherwise + * return the plain unquoted value as inserted. + * + * @param AbstractPlatform $platform + * @return string + */ + public function getQuotedName(AbstractPlatform $platform) + { + $keywords = $platform->getReservedKeywordsList(); + $parts = explode(".", $this->getName()); + foreach ($parts as $k => $v) { + $parts[$k] = ($this->_quoted || $keywords->isKeyword($v)) ? $platform->quoteIdentifier($v) : $v; + } + + return implode(".", $parts); + } + + /** + * Generate an identifier from a list of column names obeying a certain string length. + * + * This is especially important for Oracle, since it does not allow identifiers larger than 30 chars, + * however building idents automatically for foreign keys, composite keys or such can easily create + * very long names. + * + * @param array $columnNames + * @param string $prefix + * @param int $maxSize + * @return string + */ + protected function _generateIdentifierName($columnNames, $prefix='', $maxSize=30) + { + $hash = implode("", array_map(function($column) { + return dechex(crc32($column)); + }, $columnNames)); + return substr(strtoupper($prefix . "_" . $hash), 0, $maxSize); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php new file mode 100644 index 0000000..7c64acc --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -0,0 +1,896 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Events; +use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs; +use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs; +use Doctrine\DBAL\Types; +use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Base class for schema managers. Schema managers are used to inspect and/or + * modify the database schema/structure. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @author Konsta Vesterinen + * @author Lukas Smith (PEAR MDB2 library) + * @author Roman Borschel + * @author Jonathan H. Wage + * @author Benjamin Eberlei + * @since 2.0 + */ +abstract class AbstractSchemaManager +{ + /** + * Holds instance of the Doctrine connection for this schema manager + * + * @var \Doctrine\DBAL\Connection + */ + protected $_conn; + + /** + * Holds instance of the database platform used for this schema manager + * + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + protected $_platform; + + /** + * Constructor. Accepts the Connection instance to manage the schema for + * + * @param \Doctrine\DBAL\Connection $conn + */ + public function __construct(\Doctrine\DBAL\Connection $conn) + { + $this->_conn = $conn; + $this->_platform = $this->_conn->getDatabasePlatform(); + } + + /** + * Return associated platform. + * + * @return \Doctrine\DBAL\Platforms\AbstractPlatform + */ + public function getDatabasePlatform() + { + return $this->_platform; + } + + /** + * Try any method on the schema manager. Normally a method throws an + * exception when your DBMS doesn't support it or if an error occurs. + * This method allows you to try and method on your SchemaManager + * instance and will return false if it does not work or is not supported. + * + * + * $result = $sm->tryMethod('dropView', 'view_name'); + * + * + * @return mixed + */ + public function tryMethod() + { + $args = func_get_args(); + $method = $args[0]; + unset($args[0]); + $args = array_values($args); + + try { + return call_user_func_array(array($this, $method), $args); + } catch (\Exception $e) { + return false; + } + } + + /** + * List the available databases for this connection + * + * @return array $databases + */ + public function listDatabases() + { + $sql = $this->_platform->getListDatabasesSQL(); + + $databases = $this->_conn->fetchAll($sql); + + return $this->_getPortableDatabasesList($databases); + } + + /** + * List the available sequences for this connection + * + * @return Sequence[] + */ + public function listSequences($database = null) + { + if (is_null($database)) { + $database = $this->_conn->getDatabase(); + } + $sql = $this->_platform->getListSequencesSQL($database); + + $sequences = $this->_conn->fetchAll($sql); + + return $this->filterAssetNames($this->_getPortableSequencesList($sequences)); + } + + /** + * List the columns for a given table. + * + * In contrast to other libraries and to the old version of Doctrine, + * this column definition does try to contain the 'primary' field for + * the reason that it is not portable accross different RDBMS. Use + * {@see listTableIndexes($tableName)} to retrieve the primary key + * of a table. We're a RDBMS specifies more details these are held + * in the platformDetails array. + * + * @param string $table The name of the table. + * @param string $database + * @return Column[] + */ + public function listTableColumns($table, $database = null) + { + if ( ! $database) { + $database = $this->_conn->getDatabase(); + } + + $sql = $this->_platform->getListTableColumnsSQL($table, $database); + + $tableColumns = $this->_conn->fetchAll($sql); + + return $this->_getPortableTableColumnList($table, $database, $tableColumns); + } + + /** + * List the indexes for a given table returning an array of Index instances. + * + * Keys of the portable indexes list are all lower-cased. + * + * @param string $table The name of the table + * @return Index[] $tableIndexes + */ + public function listTableIndexes($table) + { + $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); + + $tableIndexes = $this->_conn->fetchAll($sql); + + return $this->_getPortableTableIndexesList($tableIndexes, $table); + } + + /** + * Return true if all the given tables exist. + * + * @param array $tableNames + * @return bool + */ + public function tablesExist($tableNames) + { + $tableNames = array_map('strtolower', (array)$tableNames); + return count($tableNames) == count(\array_intersect($tableNames, array_map('strtolower', $this->listTableNames()))); + } + + /** + * Return a list of all tables in the current database + * + * @return array + */ + public function listTableNames() + { + $sql = $this->_platform->getListTablesSQL(); + + $tables = $this->_conn->fetchAll($sql); + $tableNames = $this->_getPortableTablesList($tables); + return $this->filterAssetNames($tableNames); + } + + /** + * Filter asset names if they are configured to return only a subset of all + * the found elements. + * + * @param array $assetNames + * @return array + */ + protected function filterAssetNames($assetNames) + { + $filterExpr = $this->getFilterSchemaAssetsExpression(); + if ( ! $filterExpr) { + return $assetNames; + } + return array_values ( + array_filter($assetNames, function ($assetName) use ($filterExpr) { + $assetName = ($assetName instanceof AbstractAsset) ? $assetName->getName() : $assetName; + return preg_match($filterExpr, $assetName); + }) + ); + } + + protected function getFilterSchemaAssetsExpression() + { + return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression(); + } + + /** + * List the tables for this connection + * + * @return Table[] + */ + public function listTables() + { + $tableNames = $this->listTableNames(); + + $tables = array(); + foreach ($tableNames as $tableName) { + $tables[] = $this->listTableDetails($tableName); + } + + return $tables; + } + + /** + * @param string $tableName + * @return Table + */ + public function listTableDetails($tableName) + { + $columns = $this->listTableColumns($tableName); + $foreignKeys = array(); + if ($this->_platform->supportsForeignKeyConstraints()) { + $foreignKeys = $this->listTableForeignKeys($tableName); + } + $indexes = $this->listTableIndexes($tableName); + + return new Table($tableName, $columns, $indexes, $foreignKeys, false, array()); + } + + /** + * List the views this connection has + * + * @return View[] + */ + public function listViews() + { + $database = $this->_conn->getDatabase(); + $sql = $this->_platform->getListViewsSQL($database); + $views = $this->_conn->fetchAll($sql); + + return $this->_getPortableViewsList($views); + } + + /** + * List the foreign keys for the given table + * + * @param string $table The name of the table + * @return ForeignKeyConstraint[] + */ + public function listTableForeignKeys($table, $database = null) + { + if (is_null($database)) { + $database = $this->_conn->getDatabase(); + } + $sql = $this->_platform->getListTableForeignKeysSQL($table, $database); + $tableForeignKeys = $this->_conn->fetchAll($sql); + + return $this->_getPortableTableForeignKeysList($tableForeignKeys); + } + + /* drop*() Methods */ + + /** + * Drops a database. + * + * NOTE: You can not drop the database this SchemaManager is currently connected to. + * + * @param string $database The name of the database to drop + */ + public function dropDatabase($database) + { + $this->_execSql($this->_platform->getDropDatabaseSQL($database)); + } + + /** + * Drop the given table + * + * @param string $table The name of the table to drop + */ + public function dropTable($table) + { + $this->_execSql($this->_platform->getDropTableSQL($table)); + } + + /** + * Drop the index from the given table + * + * @param Index|string $index The name of the index + * @param string|Table $table The name of the table + */ + public function dropIndex($index, $table) + { + if($index instanceof Index) { + $index = $index->getQuotedName($this->_platform); + } + + $this->_execSql($this->_platform->getDropIndexSQL($index, $table)); + } + + /** + * Drop the constraint from the given table + * + * @param Constraint $constraint + * @param string $table The name of the table + */ + public function dropConstraint(Constraint $constraint, $table) + { + $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table)); + } + + /** + * Drops a foreign key from a table. + * + * @param ForeignKeyConstraint|string $table The name of the table with the foreign key. + * @param Table|string $name The name of the foreign key. + * @return boolean $result + */ + public function dropForeignKey($foreignKey, $table) + { + $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table)); + } + + /** + * Drops a sequence with a given name. + * + * @param string $name The name of the sequence to drop. + */ + public function dropSequence($name) + { + $this->_execSql($this->_platform->getDropSequenceSQL($name)); + } + + /** + * Drop a view + * + * @param string $name The name of the view + * @return boolean $result + */ + public function dropView($name) + { + $this->_execSql($this->_platform->getDropViewSQL($name)); + } + + /* create*() Methods */ + + /** + * Creates a new database. + * + * @param string $database The name of the database to create. + */ + public function createDatabase($database) + { + $this->_execSql($this->_platform->getCreateDatabaseSQL($database)); + } + + /** + * Create a new table. + * + * @param Table $table + * @param int $createFlags + */ + public function createTable(Table $table) + { + $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS; + $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags)); + } + + /** + * Create a new sequence + * + * @param Sequence $sequence + * @throws \Doctrine\DBAL\ConnectionException if something fails at database level + */ + public function createSequence($sequence) + { + $this->_execSql($this->_platform->getCreateSequenceSQL($sequence)); + } + + /** + * Create a constraint on a table + * + * @param Constraint $constraint + * @param string|Table $table + */ + public function createConstraint(Constraint $constraint, $table) + { + $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table)); + } + + /** + * Create a new index on a table + * + * @param Index $index + * @param string $table name of the table on which the index is to be created + */ + public function createIndex(Index $index, $table) + { + $this->_execSql($this->_platform->getCreateIndexSQL($index, $table)); + } + + /** + * Create a new foreign key + * + * @param ForeignKeyConstraint $foreignKey ForeignKey instance + * @param string|Table $table name of the table on which the foreign key is to be created + */ + public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) + { + $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table)); + } + + /** + * Create a new view + * + * @param View $view + */ + public function createView(View $view) + { + $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql())); + } + + /* dropAndCreate*() Methods */ + + /** + * Drop and create a constraint + * + * @param Constraint $constraint + * @param string $table + * @see dropConstraint() + * @see createConstraint() + */ + public function dropAndCreateConstraint(Constraint $constraint, $table) + { + $this->tryMethod('dropConstraint', $constraint, $table); + $this->createConstraint($constraint, $table); + } + + /** + * Drop and create a new index on a table + * + * @param string|Table $table name of the table on which the index is to be created + * @param Index $index + */ + public function dropAndCreateIndex(Index $index, $table) + { + $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table); + $this->createIndex($index, $table); + } + + /** + * Drop and create a new foreign key + * + * @param ForeignKeyConstraint $foreignKey associative array that defines properties of the foreign key to be created. + * @param string|Table $table name of the table on which the foreign key is to be created + */ + public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) + { + $this->tryMethod('dropForeignKey', $foreignKey, $table); + $this->createForeignKey($foreignKey, $table); + } + + /** + * Drop and create a new sequence + * + * @param Sequence $sequence + * @throws \Doctrine\DBAL\ConnectionException if something fails at database level + */ + public function dropAndCreateSequence(Sequence $sequence) + { + $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform)); + $this->createSequence($sequence); + } + + /** + * Drop and create a new table. + * + * @param Table $table + */ + public function dropAndCreateTable(Table $table) + { + $this->tryMethod('dropTable', $table->getQuotedName($this->_platform)); + $this->createTable($table); + } + + /** + * Drop and creates a new database. + * + * @param string $database The name of the database to create. + */ + public function dropAndCreateDatabase($database) + { + $this->tryMethod('dropDatabase', $database); + $this->createDatabase($database); + } + + /** + * Drop and create a new view + * + * @param View $view + */ + public function dropAndCreateView(View $view) + { + $this->tryMethod('dropView', $view->getQuotedName($this->_platform)); + $this->createView($view); + } + + /* alterTable() Methods */ + + /** + * Alter an existing tables schema + * + * @param TableDiff $tableDiff + */ + public function alterTable(TableDiff $tableDiff) + { + $queries = $this->_platform->getAlterTableSQL($tableDiff); + if (is_array($queries) && count($queries)) { + foreach ($queries as $ddlQuery) { + $this->_execSql($ddlQuery); + } + } + } + + /** + * Rename a given table to another name + * + * @param string $name The current name of the table + * @param string $newName The new name of the table + */ + public function renameTable($name, $newName) + { + $tableDiff = new TableDiff($name); + $tableDiff->newName = $newName; + $this->alterTable($tableDiff); + } + + /** + * Methods for filtering return values of list*() methods to convert + * the native DBMS data definition to a portable Doctrine definition + */ + + protected function _getPortableDatabasesList($databases) + { + $list = array(); + foreach ($databases as $value) { + if ($value = $this->_getPortableDatabaseDefinition($value)) { + $list[] = $value; + } + } + return $list; + } + + protected function _getPortableDatabaseDefinition($database) + { + return $database; + } + + protected function _getPortableFunctionsList($functions) + { + $list = array(); + foreach ($functions as $value) { + if ($value = $this->_getPortableFunctionDefinition($value)) { + $list[] = $value; + } + } + return $list; + } + + protected function _getPortableFunctionDefinition($function) + { + return $function; + } + + protected function _getPortableTriggersList($triggers) + { + $list = array(); + foreach ($triggers as $value) { + if ($value = $this->_getPortableTriggerDefinition($value)) { + $list[] = $value; + } + } + return $list; + } + + protected function _getPortableTriggerDefinition($trigger) + { + return $trigger; + } + + protected function _getPortableSequencesList($sequences) + { + $list = array(); + foreach ($sequences as $value) { + if ($value = $this->_getPortableSequenceDefinition($value)) { + $list[] = $value; + } + } + return $list; + } + + /** + * @param array $sequence + * @return Sequence + */ + protected function _getPortableSequenceDefinition($sequence) + { + throw DBALException::notSupported('Sequences'); + } + + /** + * Independent of the database the keys of the column list result are lowercased. + * + * The name of the created column instance however is kept in its case. + * + * @param string $table The name of the table. + * @param string $database + * @param array $tableColumns + * @return array + */ + protected function _getPortableTableColumnList($table, $database, $tableColumns) + { + $eventManager = $this->_platform->getEventManager(); + + $list = array(); + foreach ($tableColumns as $tableColumn) { + $column = null; + $defaultPrevented = false; + + if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) { + $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn); + $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs); + + $defaultPrevented = $eventArgs->isDefaultPrevented(); + $column = $eventArgs->getColumn(); + } + + if ( ! $defaultPrevented) { + $column = $this->_getPortableTableColumnDefinition($tableColumn); + } + + if ($column) { + $name = strtolower($column->getQuotedName($this->_platform)); + $list[$name] = $column; + } + } + return $list; + } + + /** + * Get Table Column Definition + * + * @param array $tableColumn + * @return Column + */ + abstract protected function _getPortableTableColumnDefinition($tableColumn); + + /** + * Aggregate and group the index results according to the required data result. + * + * @param array $tableIndexRows + * @param string $tableName + * @return array + */ + protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null) + { + $result = array(); + foreach($tableIndexRows as $tableIndex) { + $indexName = $keyName = $tableIndex['key_name']; + if($tableIndex['primary']) { + $keyName = 'primary'; + } + $keyName = strtolower($keyName); + + if(!isset($result[$keyName])) { + $result[$keyName] = array( + 'name' => $indexName, + 'columns' => array($tableIndex['column_name']), + 'unique' => $tableIndex['non_unique'] ? false : true, + 'primary' => $tableIndex['primary'], + 'flags' => isset($tableIndex['flags']) ? $tableIndex['flags'] : array(), + ); + } else { + $result[$keyName]['columns'][] = $tableIndex['column_name']; + } + } + + $eventManager = $this->_platform->getEventManager(); + + $indexes = array(); + foreach($result as $indexKey => $data) { + $index = null; + $defaultPrevented = false; + + if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) { + $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn); + $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs); + + $defaultPrevented = $eventArgs->isDefaultPrevented(); + $index = $eventArgs->getIndex(); + } + + if ( ! $defaultPrevented) { + $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags']); + } + + if ($index) { + $indexes[$indexKey] = $index; + } + } + + return $indexes; + } + + protected function _getPortableTablesList($tables) + { + $list = array(); + foreach ($tables as $value) { + if ($value = $this->_getPortableTableDefinition($value)) { + $list[] = $value; + } + } + return $list; + } + + protected function _getPortableTableDefinition($table) + { + return $table; + } + + protected function _getPortableUsersList($users) + { + $list = array(); + foreach ($users as $value) { + if ($value = $this->_getPortableUserDefinition($value)) { + $list[] = $value; + } + } + return $list; + } + + protected function _getPortableUserDefinition($user) + { + return $user; + } + + protected function _getPortableViewsList($views) + { + $list = array(); + foreach ($views as $value) { + if ($view = $this->_getPortableViewDefinition($value)) { + $viewName = strtolower($view->getQuotedName($this->_platform)); + $list[$viewName] = $view; + } + } + return $list; + } + + protected function _getPortableViewDefinition($view) + { + return false; + } + + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $list = array(); + foreach ($tableForeignKeys as $value) { + if ($value = $this->_getPortableTableForeignKeyDefinition($value)) { + $list[] = $value; + } + } + return $list; + } + + protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + return $tableForeignKey; + } + + protected function _execSql($sql) + { + foreach ((array) $sql as $query) { + $this->_conn->executeUpdate($query); + } + } + + /** + * Create a schema instance for the current database. + * + * @return Schema + */ + public function createSchema() + { + $sequences = array(); + if($this->_platform->supportsSequences()) { + $sequences = $this->listSequences(); + } + $tables = $this->listTables(); + + return new Schema($tables, $sequences, $this->createSchemaConfig()); + } + + /** + * Create the configuration for this schema. + * + * @return SchemaConfig + */ + public function createSchemaConfig() + { + $schemaConfig = new SchemaConfig(); + $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength()); + + $searchPaths = $this->getSchemaSearchPaths(); + if (isset($searchPaths[0])) { + $schemaConfig->setName($searchPaths[0]); + } + + $params = $this->_conn->getParams(); + if (isset($params['defaultTableOptions'])) { + $schemaConfig->setDefaultTableOptions($params['defautTableOptions']); + } + + return $schemaConfig; + } + + /** + * The search path for namespaces in the currently connected database. + * + * The first entry is usually the default namespace in the Schema. All + * further namespaces contain tables/sequences which can also be addressed + * with a short, not full-qualified name. + * + * For databases that don't support subschema/namespaces this method + * returns the name of the currently connected database. + * + * @return array + */ + public function getSchemaSearchPaths() + { + return array($this->_conn->getDatabase()); + } + + /** + * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns + * the type given as default. + * + * @param string $comment + * @param string $currentType + * @return string + */ + public function extractDoctrineTypeFromComment($comment, $currentType) + { + if (preg_match("(\(DC2Type:([a-zA-Z0-9_]+)\))", $comment, $match)) { + $currentType = $match[1]; + } + return $currentType; + } + + public function removeDoctrineTypeFromComment($comment, $type) + { + return str_replace('(DC2Type:'.$type.')', '', $comment); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Column.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Column.php new file mode 100644 index 0000000..fa6f70b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Column.php @@ -0,0 +1,423 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use \Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Schema\Visitor\Visitor; + +/** + * Object representation of a database column + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class Column extends AbstractAsset +{ + /** + * @var \Doctrine\DBAL\Types\Type + */ + protected $_type; + + /** + * @var int + */ + protected $_length = null; + + /** + * @var int + */ + protected $_precision = 10; + + /** + * @var int + */ + protected $_scale = 0; + + /** + * @var bool + */ + protected $_unsigned = false; + + /** + * @var bool + */ + protected $_fixed = false; + + /** + * @var bool + */ + protected $_notnull = true; + + /** + * @var string + */ + protected $_default = null; + + /** + * @var bool + */ + protected $_autoincrement = false; + + /** + * @var array + */ + protected $_platformOptions = array(); + + /** + * @var string + */ + protected $_columnDefinition = null; + + /** + * @var string + */ + protected $_comment = null; + + /** + * @var array + */ + protected $_customSchemaOptions = array(); + + /** + * Create a new Column + * + * @param string $columnName + * @param \Doctrine\DBAL\Types\Type $type + * @param int $length + * @param bool $notNull + * @param mixed $default + * @param bool $unsigned + * @param bool $fixed + * @param int $precision + * @param int $scale + * @param array $platformOptions + */ + public function __construct($columnName, Type $type, array $options=array()) + { + $this->_setName($columnName); + $this->setType($type); + $this->setOptions($options); + } + + /** + * @param array $options + * @return Column + */ + public function setOptions(array $options) + { + foreach ($options as $name => $value) { + $method = "set".$name; + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * @param Type $type + * @return Column + */ + public function setType(Type $type) + { + $this->_type = $type; + return $this; + } + + /** + * @param int $length + * @return Column + */ + public function setLength($length) + { + if($length !== null) { + $this->_length = (int)$length; + } else { + $this->_length = null; + } + return $this; + } + + /** + * @param int $precision + * @return Column + */ + public function setPrecision($precision) + { + if (!is_numeric($precision)) { + $precision = 10; // defaults to 10 when no valid precision is given. + } + + $this->_precision = (int)$precision; + return $this; + } + + /** + * @param int $scale + * @return Column + */ + public function setScale($scale) + { + if (!is_numeric($scale)) { + $scale = 0; + } + + $this->_scale = (int)$scale; + return $this; + } + + /** + * + * @param bool $unsigned + * @return Column + */ + public function setUnsigned($unsigned) + { + $this->_unsigned = (bool)$unsigned; + return $this; + } + + /** + * + * @param bool $fixed + * @return Column + */ + public function setFixed($fixed) + { + $this->_fixed = (bool)$fixed; + return $this; + } + + /** + * @param bool $notnull + * @return Column + */ + public function setNotnull($notnull) + { + $this->_notnull = (bool)$notnull; + return $this; + } + + /** + * + * @param mixed $default + * @return Column + */ + public function setDefault($default) + { + $this->_default = $default; + return $this; + } + + /** + * + * @param array $platformOptions + * @return Column + */ + public function setPlatformOptions(array $platformOptions) + { + $this->_platformOptions = $platformOptions; + return $this; + } + + /** + * + * @param string $name + * @param mixed $value + * @return Column + */ + public function setPlatformOption($name, $value) + { + $this->_platformOptions[$name] = $value; + return $this; + } + + /** + * + * @param string + * @return Column + */ + public function setColumnDefinition($value) + { + $this->_columnDefinition = $value; + return $this; + } + + public function getType() + { + return $this->_type; + } + + public function getLength() + { + return $this->_length; + } + + public function getPrecision() + { + return $this->_precision; + } + + public function getScale() + { + return $this->_scale; + } + + public function getUnsigned() + { + return $this->_unsigned; + } + + public function getFixed() + { + return $this->_fixed; + } + + public function getNotnull() + { + return $this->_notnull; + } + + public function getDefault() + { + return $this->_default; + } + + public function getPlatformOptions() + { + return $this->_platformOptions; + } + + public function hasPlatformOption($name) + { + return isset($this->_platformOptions[$name]); + } + + public function getPlatformOption($name) + { + return $this->_platformOptions[$name]; + } + + public function getColumnDefinition() + { + return $this->_columnDefinition; + } + + public function getAutoincrement() + { + return $this->_autoincrement; + } + + public function setAutoincrement($flag) + { + $this->_autoincrement = $flag; + return $this; + } + + public function setComment($comment) + { + $this->_comment = $comment; + return $this; + } + + public function getComment() + { + return $this->_comment; + } + + /** + * @param string $name + * @param mixed $value + * @return Column + */ + public function setCustomSchemaOption($name, $value) + { + $this->_customSchemaOptions[$name] = $value; + return $this; + } + + /** + * @param string $name + * @return boolean + */ + public function hasCustomSchemaOption($name) + { + return isset($this->_customSchemaOptions[$name]); + } + + /** + * @param string $name + * @return mixed + */ + public function getCustomSchemaOption($name) + { + return $this->_customSchemaOptions[$name]; + } + + /** + * @param array $customSchemaOptions + * @return Column + */ + public function setCustomSchemaOptions(array $customSchemaOptions) + { + $this->_customSchemaOptions = $customSchemaOptions; + return $this; + } + + /** + * @return array + */ + public function getCustomSchemaOptions() + { + return $this->_customSchemaOptions; + } + + /** + * @param Visitor $visitor + */ + public function visit(\Doctrine\DBAL\Schema\Visitor $visitor) + { + $visitor->accept($this); + } + + /** + * @return array + */ + public function toArray() + { + return array_merge(array( + 'name' => $this->_name, + 'type' => $this->_type, + 'default' => $this->_default, + 'notnull' => $this->_notnull, + 'length' => $this->_length, + 'precision' => $this->_precision, + 'scale' => $this->_scale, + 'fixed' => $this->_fixed, + 'unsigned' => $this->_unsigned, + 'autoincrement' => $this->_autoincrement, + 'columnDefinition' => $this->_columnDefinition, + 'comment' => $this->_comment, + ), $this->_platformOptions, $this->_customSchemaOptions); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ColumnDiff.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ColumnDiff.php new file mode 100644 index 0000000..4fc4b9c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ColumnDiff.php @@ -0,0 +1,58 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * Represent the change of a column + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class ColumnDiff +{ + public $oldColumnName; + + /** + * @var Column + */ + public $column; + + /** + * @var array + */ + public $changedProperties = array(); + + public function __construct($oldColumnName, Column $column, array $changedProperties = array()) + { + $this->oldColumnName = $oldColumnName; + $this->column = $column; + $this->changedProperties = $changedProperties; + } + + public function hasChanged($propertyName) + { + return in_array($propertyName, $this->changedProperties); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Comparator.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Comparator.php new file mode 100644 index 0000000..a1c4951 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Comparator.php @@ -0,0 +1,415 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * Compare to Schemas and return an instance of SchemaDiff + * + * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class Comparator +{ + /** + * @param Schema $fromSchema + * @param Schema $toSchema + * @return SchemaDiff + */ + static public function compareSchemas( Schema $fromSchema, Schema $toSchema ) + { + $c = new self(); + return $c->compare($fromSchema, $toSchema); + } + + /** + * Returns a SchemaDiff object containing the differences between the schemas $fromSchema and $toSchema. + * + * The returned diferences are returned in such a way that they contain the + * operations to change the schema stored in $fromSchema to the schema that is + * stored in $toSchema. + * + * @param Schema $fromSchema + * @param Schema $toSchema + * + * @return SchemaDiff + */ + public function compare(Schema $fromSchema, Schema $toSchema) + { + $diff = new SchemaDiff(); + + $foreignKeysToTable = array(); + + foreach ( $toSchema->getTables() as $table ) { + $tableName = $table->getShortestName($toSchema->getName()); + if ( ! $fromSchema->hasTable($tableName)) { + $diff->newTables[$tableName] = $toSchema->getTable($tableName); + } else { + $tableDifferences = $this->diffTable($fromSchema->getTable($tableName), $toSchema->getTable($tableName)); + if ($tableDifferences !== false) { + $diff->changedTables[$tableName] = $tableDifferences; + } + } + } + + /* Check if there are tables removed */ + foreach ($fromSchema->getTables() as $table) { + $tableName = $table->getShortestName($fromSchema->getName()); + + $table = $fromSchema->getTable($tableName); + if ( ! $toSchema->hasTable($tableName) ) { + $diff->removedTables[$tableName] = $table; + } + + // also remember all foreign keys that point to a specific table + foreach ($table->getForeignKeys() as $foreignKey) { + $foreignTable = strtolower($foreignKey->getForeignTableName()); + if (!isset($foreignKeysToTable[$foreignTable])) { + $foreignKeysToTable[$foreignTable] = array(); + } + $foreignKeysToTable[$foreignTable][] = $foreignKey; + } + } + + foreach ($diff->removedTables as $tableName => $table) { + if (isset($foreignKeysToTable[$tableName])) { + $diff->orphanedForeignKeys = array_merge($diff->orphanedForeignKeys, $foreignKeysToTable[$tableName]); + } + } + + foreach ($toSchema->getSequences() as $sequence) { + $sequenceName = $sequence->getShortestName($toSchema->getName()); + if ( ! $fromSchema->hasSequence($sequenceName)) { + $diff->newSequences[] = $sequence; + } else { + if ($this->diffSequence($sequence, $fromSchema->getSequence($sequenceName))) { + $diff->changedSequences[] = $toSchema->getSequence($sequenceName); + } + } + } + + foreach ($fromSchema->getSequences() as $sequence) { + if ($this->isAutoIncrementSequenceInSchema($toSchema, $sequence)) { + continue; + } + + $sequenceName = $sequence->getShortestName($fromSchema->getName()); + + if ( ! $toSchema->hasSequence($sequenceName)) { + $diff->removedSequences[] = $sequence; + } + } + + return $diff; + } + + private function isAutoIncrementSequenceInSchema($schema, $sequence) + { + foreach ($schema->getTables() as $table) { + if ($sequence->isAutoIncrementsFor($table)) { + return true; + } + } + + return false; + } + + /** + * + * @param Sequence $sequence1 + * @param Sequence $sequence2 + */ + public function diffSequence(Sequence $sequence1, Sequence $sequence2) + { + if($sequence1->getAllocationSize() != $sequence2->getAllocationSize()) { + return true; + } + + if($sequence1->getInitialValue() != $sequence2->getInitialValue()) { + return true; + } + + return false; + } + + /** + * Returns the difference between the tables $table1 and $table2. + * + * If there are no differences this method returns the boolean false. + * + * @param Table $table1 + * @param Table $table2 + * + * @return bool|TableDiff + */ + public function diffTable(Table $table1, Table $table2) + { + $changes = 0; + $tableDifferences = new TableDiff($table1->getName()); + + $table1Columns = $table1->getColumns(); + $table2Columns = $table2->getColumns(); + + /* See if all the fields in table 1 exist in table 2 */ + foreach ( $table2Columns as $columnName => $column ) { + if ( !$table1->hasColumn($columnName) ) { + $tableDifferences->addedColumns[$columnName] = $column; + $changes++; + } + } + /* See if there are any removed fields in table 2 */ + foreach ( $table1Columns as $columnName => $column ) { + if ( !$table2->hasColumn($columnName) ) { + $tableDifferences->removedColumns[$columnName] = $column; + $changes++; + } + } + + foreach ( $table1Columns as $columnName => $column ) { + if ( $table2->hasColumn($columnName) ) { + $changedProperties = $this->diffColumn( $column, $table2->getColumn($columnName) ); + if (count($changedProperties) ) { + $columnDiff = new ColumnDiff($column->getName(), $table2->getColumn($columnName), $changedProperties); + $tableDifferences->changedColumns[$column->getName()] = $columnDiff; + $changes++; + } + } + } + + $this->detectColumnRenamings($tableDifferences); + + $table1Indexes = $table1->getIndexes(); + $table2Indexes = $table2->getIndexes(); + + foreach ($table2Indexes as $index2Name => $index2Definition) { + foreach ($table1Indexes as $index1Name => $index1Definition) { + if ($this->diffIndex($index1Definition, $index2Definition) === false) { + unset($table1Indexes[$index1Name]); + unset($table2Indexes[$index2Name]); + } else { + if ($index1Name == $index2Name) { + $tableDifferences->changedIndexes[$index2Name] = $table2Indexes[$index2Name]; + unset($table1Indexes[$index1Name]); + unset($table2Indexes[$index2Name]); + $changes++; + } + } + } + } + + foreach ($table1Indexes as $index1Name => $index1Definition) { + $tableDifferences->removedIndexes[$index1Name] = $index1Definition; + $changes++; + } + + foreach ($table2Indexes as $index2Name => $index2Definition) { + $tableDifferences->addedIndexes[$index2Name] = $index2Definition; + $changes++; + } + + $fromFkeys = $table1->getForeignKeys(); + $toFkeys = $table2->getForeignKeys(); + + foreach ($fromFkeys as $key1 => $constraint1) { + foreach ($toFkeys as $key2 => $constraint2) { + if($this->diffForeignKey($constraint1, $constraint2) === false) { + unset($fromFkeys[$key1]); + unset($toFkeys[$key2]); + } else { + if (strtolower($constraint1->getName()) == strtolower($constraint2->getName())) { + $tableDifferences->changedForeignKeys[] = $constraint2; + $changes++; + unset($fromFkeys[$key1]); + unset($toFkeys[$key2]); + } + } + } + } + + foreach ($fromFkeys as $key1 => $constraint1) { + $tableDifferences->removedForeignKeys[] = $constraint1; + $changes++; + } + + foreach ($toFkeys as $key2 => $constraint2) { + $tableDifferences->addedForeignKeys[] = $constraint2; + $changes++; + } + + return $changes ? $tableDifferences : false; + } + + /** + * Try to find columns that only changed their name, rename operations maybe cheaper than add/drop + * however ambiguouties between different possibilites should not lead to renaming at all. + * + * @param TableDiff $tableDifferences + */ + private function detectColumnRenamings(TableDiff $tableDifferences) + { + $renameCandidates = array(); + foreach ($tableDifferences->addedColumns as $addedColumnName => $addedColumn) { + foreach ($tableDifferences->removedColumns as $removedColumnName => $removedColumn) { + if (count($this->diffColumn($addedColumn, $removedColumn)) == 0) { + $renameCandidates[$addedColumn->getName()][] = array($removedColumn, $addedColumn, $addedColumnName); + } + } + } + + foreach ($renameCandidates as $candidateColumns) { + if (count($candidateColumns) == 1) { + list($removedColumn, $addedColumn) = $candidateColumns[0]; + $removedColumnName = strtolower($removedColumn->getName()); + $addedColumnName = strtolower($addedColumn->getName()); + + $tableDifferences->renamedColumns[$removedColumnName] = $addedColumn; + unset($tableDifferences->addedColumns[$addedColumnName]); + unset($tableDifferences->removedColumns[$removedColumnName]); + } + } + } + + /** + * @param ForeignKeyConstraint $key1 + * @param ForeignKeyConstraint $key2 + * @return bool + */ + public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint $key2) + { + if (array_map('strtolower', $key1->getLocalColumns()) != array_map('strtolower', $key2->getLocalColumns())) { + return true; + } + + if (array_map('strtolower', $key1->getForeignColumns()) != array_map('strtolower', $key2->getForeignColumns())) { + return true; + } + + if ($key1->onUpdate() != $key2->onUpdate()) { + return true; + } + + if ($key1->onDelete() != $key2->onDelete()) { + return true; + } + + return false; + } + + /** + * Returns the difference between the fields $field1 and $field2. + * + * If there are differences this method returns $field2, otherwise the + * boolean false. + * + * @param Column $column1 + * @param Column $column2 + * + * @return array + */ + public function diffColumn(Column $column1, Column $column2) + { + $changedProperties = array(); + if ( $column1->getType() != $column2->getType() ) { + $changedProperties[] = 'type'; + } + + if ($column1->getNotnull() != $column2->getNotnull()) { + $changedProperties[] = 'notnull'; + } + + if ($column1->getDefault() != $column2->getDefault()) { + $changedProperties[] = 'default'; + } + + if ($column1->getUnsigned() != $column2->getUnsigned()) { + $changedProperties[] = 'unsigned'; + } + + if ($column1->getType() instanceof \Doctrine\DBAL\Types\StringType) { + // check if value of length is set at all, default value assumed otherwise. + $length1 = $column1->getLength() ?: 255; + $length2 = $column2->getLength() ?: 255; + if ($length1 != $length2) { + $changedProperties[] = 'length'; + } + + if ($column1->getFixed() != $column2->getFixed()) { + $changedProperties[] = 'fixed'; + } + } + + if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) { + if (($column1->getPrecision()?:10) != ($column2->getPrecision()?:10)) { + $changedProperties[] = 'precision'; + } + if ($column1->getScale() != $column2->getScale()) { + $changedProperties[] = 'scale'; + } + } + + if ($column1->getAutoincrement() != $column2->getAutoincrement()) { + $changedProperties[] = 'autoincrement'; + } + + // only allow to delete comment if its set to '' not to null. + if ($column1->getComment() !== null && $column1->getComment() != $column2->getComment()) { + $changedProperties[] = 'comment'; + } + + $options1 = $column1->getCustomSchemaOptions(); + $options2 = $column2->getCustomSchemaOptions(); + + $commonKeys = array_keys(array_intersect_key($options1, $options2)); + + foreach ($commonKeys as $key) { + if ($options1[$key] !== $options2[$key]) { + $changedProperties[] = $key; + } + } + + $diffKeys = array_keys(array_diff_key($options1, $options2) + array_diff_key($options2, $options1)); + + $changedProperties = array_merge($changedProperties, $diffKeys); + + return $changedProperties; + } + + /** + * Finds the difference between the indexes $index1 and $index2. + * + * Compares $index1 with $index2 and returns $index2 if there are any + * differences or false in case there are no differences. + * + * @param Index $index1 + * @param Index $index2 + * @return bool + */ + public function diffIndex(Index $index1, Index $index2) + { + if ($index1->isFullfilledBy($index2) && $index2->isFullfilledBy($index1)) { + return false; + } + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Constraint.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Constraint.php new file mode 100644 index 0000000..f80410f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Constraint.php @@ -0,0 +1,42 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Marker interface for contraints + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +interface Constraint +{ + public function getName(); + + public function getQuotedName(AbstractPlatform $platform); + + public function getColumns(); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php new file mode 100644 index 0000000..e11c64c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DB2SchemaManager.php @@ -0,0 +1,214 @@ +. +*/ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs; +use Doctrine\DBAL\Events; + +/** + * IBM Db2 Schema Manager + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class DB2SchemaManager extends AbstractSchemaManager +{ + /** + * Return a list of all tables in the current database + * + * Apparently creator is the schema not the user who created it: + * {@link http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.sqlref/db2z_sysibmsystablestable.htm} + * + * @return array + */ + public function listTableNames() + { + $sql = $this->_platform->getListTablesSQL(); + $sql .= " AND CREATOR = UPPER('".$this->_conn->getUsername()."')"; + + $tables = $this->_conn->fetchAll($sql); + + return $this->_getPortableTablesList($tables); + } + + + /** + * Get Table Column Definition + * + * @param array $tableColumn + * @return Column + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $tableColumn = array_change_key_case($tableColumn, \CASE_LOWER); + + $length = null; + $fixed = null; + $unsigned = false; + $scale = false; + $precision = false; + + $type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']); + + switch (strtolower($tableColumn['typename'])) { + case 'varchar': + $length = $tableColumn['length']; + $fixed = false; + break; + case 'character': + $length = $tableColumn['length']; + $fixed = true; + break; + case 'clob': + $length = $tableColumn['length']; + break; + case 'decimal': + case 'double': + case 'real': + $scale = $tableColumn['scale']; + $precision = $tableColumn['length']; + break; + } + + $options = array( + 'length' => $length, + 'unsigned' => (bool)$unsigned, + 'fixed' => (bool)$fixed, + 'default' => ($tableColumn['default'] == "NULL") ? null : $tableColumn['default'], + 'notnull' => (bool) ($tableColumn['nulls'] == 'N'), + 'scale' => null, + 'precision' => null, + 'platformOptions' => array(), + ); + + if ($scale !== null && $precision !== null) { + $options['scale'] = $scale; + $options['precision'] = $precision; + } + + return new Column($tableColumn['colname'], \Doctrine\DBAL\Types\Type::getType($type), $options); + } + + protected function _getPortableTablesList($tables) + { + $tableNames = array(); + foreach ($tables as $tableRow) { + $tableRow = array_change_key_case($tableRow, \CASE_LOWER); + $tableNames[] = $tableRow['name']; + } + return $tableNames; + } + + protected function _getPortableTableIndexesList($tableIndexes, $tableName=null) + { + $eventManager = $this->_platform->getEventManager(); + + $indexes = array(); + foreach($tableIndexes as $indexKey => $data) { + $data = array_change_key_case($data, \CASE_LOWER); + $unique = ($data['uniquerule'] == "D") ? false : true; + $primary = ($data['uniquerule'] == "P"); + + $indexName = strtolower($data['name']); + if ($primary) { + $keyName = 'primary'; + } else { + $keyName = $indexName; + } + + $data = array( + 'name' => $indexName, + 'columns' => explode("+", ltrim($data['colnames'], '+')), + 'unique' => $unique, + 'primary' => $primary + ); + + $index = null; + $defaultPrevented = false; + + if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) { + $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn); + $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs); + + $defaultPrevented = $eventArgs->isDefaultPrevented(); + $index = $eventArgs->getIndex(); + } + + if ( ! $defaultPrevented) { + $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']); + } + + if ($index) { + $indexes[$indexKey] = $index; + } + } + + return $indexes; + } + + protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + $tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER); + + $tableForeignKey['deleterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['deleterule']); + $tableForeignKey['updaterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['updaterule']); + + return new ForeignKeyConstraint( + array_map('trim', (array)$tableForeignKey['fkcolnames']), + $tableForeignKey['reftbname'], + array_map('trim', (array)$tableForeignKey['pkcolnames']), + $tableForeignKey['relname'], + array( + 'onUpdate' => $tableForeignKey['updaterule'], + 'onDelete' => $tableForeignKey['deleterule'], + ) + ); + } + + protected function _getPortableForeignKeyRuleDef($def) + { + if ($def == "C") { + return "CASCADE"; + } else if ($def == "N") { + return "SET NULL"; + } + return null; + } + + protected function _getPortableViewDefinition($view) + { + $view = array_change_key_case($view, \CASE_LOWER); + // sadly this still segfaults on PDO_IBM, see http://pecl.php.net/bugs/bug.php?id=17199 + //$view['text'] = (is_resource($view['text']) ? stream_get_contents($view['text']) : $view['text']); + if (!is_resource($view['text'])) { + $pos = strpos($view['text'], ' AS '); + $sql = substr($view['text'], $pos+4); + } else { + $sql = ''; + } + + return new View($view['name'], $sql); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php new file mode 100644 index 0000000..f73b223 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php @@ -0,0 +1,96 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * Schema manager for the Drizzle RDBMS. + * + * @author Kim Hemsø Rasmussen + */ +class DrizzleSchemaManager extends AbstractSchemaManager +{ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $tableName = $tableColumn['COLUMN_NAME']; + $dbType = strtolower($tableColumn['DATA_TYPE']); + + $type = $this->_platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); + $tableColumn['COLUMN_COMMENT'] = $this->removeDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); + + $options = array( + 'notnull' => !(bool)$tableColumn['IS_NULLABLE'], + 'length' => (int)$tableColumn['CHARACTER_MAXIMUM_LENGTH'], + 'default' => empty($tableColumn['COLUMN_DEFAULT']) ? null : $tableColumn['COLUMN_DEFAULT'], + 'autoincrement' => (bool)$tableColumn['IS_AUTO_INCREMENT'], + 'scale' => (int)$tableColumn['NUMERIC_SCALE'], + 'precision' => (int)$tableColumn['NUMERIC_PRECISION'], + 'comment' => (isset($tableColumn['COLUMN_COMMENT']) ? $tableColumn['COLUMN_COMMENT'] : null), + ); + + return new Column($tableName, \Doctrine\DBAL\Types\Type::getType($type), $options); + } + + protected function _getPortableDatabaseDefinition($database) + { + return $database['SCHEMA_NAME']; + } + + protected function _getPortableTableDefinition($table) + { + return $table['TABLE_NAME']; + } + + public function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + $columns = array(); + foreach (explode(',', $tableForeignKey['CONSTRAINT_COLUMNS']) as $value) { + $columns[] = trim($value, ' `'); + } + + $ref_columns = array(); + foreach (explode(',', $tableForeignKey['REFERENCED_TABLE_COLUMNS']) as $value) { + $ref_columns[] = trim($value, ' `'); + } + + return new ForeignKeyConstraint( + $columns, + $tableForeignKey['REFERENCED_TABLE_NAME'], + $ref_columns, + $tableForeignKey['CONSTRAINT_NAME'], + array( + 'onUpdate' => $tableForeignKey['UPDATE_RULE'], + 'onDelete' => $tableForeignKey['DELETE_RULE'], + ) + ); + } + + protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) + { + $indexes = array(); + foreach ($tableIndexes as $k) { + $k['primary'] = (boolean)$k['primary']; + $indexes[] = $k; + } + + return parent::_getPortableTableIndexesList($indexes, $tableName); + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php new file mode 100644 index 0000000..481d693 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php @@ -0,0 +1,193 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Schema\Visitor\Visitor; +use Doctrine\DBAL\Platforms\AbstractPlatform; + +class ForeignKeyConstraint extends AbstractAsset implements Constraint +{ + /** + * @var Table + */ + protected $_localTable; + + /** + * @var array + */ + protected $_localColumnNames; + + /** + * @var string + */ + protected $_foreignTableName; + + /** + * @var array + */ + protected $_foreignColumnNames; + + /** + * @var string + */ + protected $_cascade = ''; + + /** + * @var array + */ + protected $_options; + + /** + * + * @param array $localColumnNames + * @param string $foreignTableName + * @param array $foreignColumnNames + * @param string $cascade + * @param string|null $name + */ + public function __construct(array $localColumnNames, $foreignTableName, array $foreignColumnNames, $name=null, array $options=array()) + { + $this->_setName($name); + $this->_localColumnNames = $localColumnNames; + $this->_foreignTableName = $foreignTableName; + $this->_foreignColumnNames = $foreignColumnNames; + $this->_options = $options; + } + + /** + * @return string + */ + public function getLocalTableName() + { + return $this->_localTable->getName(); + } + + /** + * @param Table $table + */ + public function setLocalTable(Table $table) + { + $this->_localTable = $table; + } + + /** + * @return array + */ + public function getLocalColumns() + { + return $this->_localColumnNames; + } + + public function getColumns() + { + return $this->_localColumnNames; + } + + /** + * @return string + */ + public function getForeignTableName() + { + return $this->_foreignTableName; + } + + /** + * Get the quoted representation of this asset but only if it was defined with one. Otherwise + * return the plain unquoted value as inserted. + * + * @param AbstractPlatform $platform + * @return string + */ + public function getQuotedForeignTableName(AbstractPlatform $platform) + { + $keywords = $platform->getReservedKeywordsList(); + $parts = explode(".", $this->getForeignTableName()); + foreach ($parts AS $k => $v) { + $parts[$k] = ($this->_quoted || $keywords->isKeyword($v)) ? $platform->quoteIdentifier($v) : $v; + } + + return implode(".", $parts); + } + + /** + * @return array + */ + public function getForeignColumns() + { + return $this->_foreignColumnNames; + } + + public function hasOption($name) + { + return isset($this->_options[$name]); + } + + public function getOption($name) + { + return $this->_options[$name]; + } + + /** + * Gets the options associated with this constraint + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Foreign Key onUpdate status + * + * @return string|null + */ + public function onUpdate() + { + return $this->_onEvent('onUpdate'); + } + + /** + * Foreign Key onDelete status + * + * @return string|null + */ + public function onDelete() + { + return $this->_onEvent('onDelete'); + } + + /** + * @param string $event + * @return string|null + */ + private function _onEvent($event) + { + if (isset($this->_options[$event])) { + $onEvent = strtoupper($this->_options[$event]); + if (!in_array($onEvent, array('NO ACTION', 'RESTRICT'))) { + return $onEvent; + } + } + return false; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Index.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Index.php new file mode 100644 index 0000000..56b9ea8 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Index.php @@ -0,0 +1,242 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Schema\Visitor\Visitor; + +class Index extends AbstractAsset implements Constraint +{ + /** + * @var array + */ + protected $_columns; + + /** + * @var bool + */ + protected $_isUnique = false; + + /** + * @var bool + */ + protected $_isPrimary = false; + + /** + * Platform specific flags for indexes. + * + * @var array + */ + protected $_flags = array(); + + /** + * @param string $indexName + * @param array $column + * @param bool $isUnique + * @param bool $isPrimary + */ + public function __construct($indexName, array $columns, $isUnique = false, $isPrimary = false, array $flags = array()) + { + $isUnique = ($isPrimary)?true:$isUnique; + + $this->_setName($indexName); + $this->_isUnique = $isUnique; + $this->_isPrimary = $isPrimary; + + foreach ($columns as $column) { + $this->_addColumn($column); + } + foreach ($flags as $flag) { + $this->addFlag($flag); + } + } + + /** + * @param string $column + */ + protected function _addColumn($column) + { + if(is_string($column)) { + $this->_columns[] = $column; + } else { + throw new \InvalidArgumentException("Expecting a string as Index Column"); + } + } + + /** + * @return array + */ + public function getColumns() + { + return $this->_columns; + } + + /** + * @return array + */ + public function getUnquotedColumns() + { + return array_map(array($this, 'trimQuotes'), $this->getColumns()); + } + + /** + * Is the index neither unique nor primary key? + * + * @return bool + */ + public function isSimpleIndex() + { + return !$this->_isPrimary && !$this->_isUnique; + } + + /** + * @return bool + */ + public function isUnique() + { + return $this->_isUnique; + } + + /** + * @return bool + */ + public function isPrimary() + { + return $this->_isPrimary; + } + + /** + * @param string $columnName + * @param int $pos + * @return bool + */ + public function hasColumnAtPosition($columnName, $pos = 0) + { + $columnName = $this->trimQuotes(strtolower($columnName)); + $indexColumns = array_map('strtolower', $this->getUnquotedColumns()); + return array_search($columnName, $indexColumns) === $pos; + } + + /** + * Check if this index exactly spans the given column names in the correct order. + * + * @param array $columnNames + * @return boolean + */ + public function spansColumns(array $columnNames) + { + $sameColumns = true; + for ($i = 0; $i < count($this->_columns); $i++) { + if (!isset($columnNames[$i]) || $this->trimQuotes(strtolower($this->_columns[$i])) != $this->trimQuotes(strtolower($columnNames[$i]))) { + $sameColumns = false; + } + } + return $sameColumns; + } + + /** + * Check if the other index already fullfills all the indexing and constraint needs of the current one. + * + * @param Index $other + * @return bool + */ + public function isFullfilledBy(Index $other) + { + // allow the other index to be equally large only. It being larger is an option + // but it creates a problem with scenarios of the kind PRIMARY KEY(foo,bar) UNIQUE(foo) + if (count($other->getColumns()) != count($this->getColumns())) { + return false; + } + + // Check if columns are the same, and even in the same order + $sameColumns = $this->spansColumns($other->getColumns()); + + if ($sameColumns) { + if ( ! $this->isUnique() && !$this->isPrimary()) { + // this is a special case: If the current key is neither primary or unique, any uniqe or + // primary key will always have the same effect for the index and there cannot be any constraint + // overlaps. This means a primary or unique index can always fullfill the requirements of just an + // index that has no constraints. + return true; + } else if ($other->isPrimary() != $this->isPrimary()) { + return false; + } else if ($other->isUnique() != $this->isUnique()) { + return false; + } + return true; + } + return false; + } + + /** + * Detect if the other index is a non-unique, non primary index that can be overwritten by this one. + * + * @param Index $other + * @return bool + */ + public function overrules(Index $other) + { + if ($other->isPrimary()) { + return false; + } else if ($this->isSimpleIndex() && $other->isUnique()) { + return false; + } + + if ($this->spansColumns($other->getColumns()) && ($this->isPrimary() || $this->isUnique())) { + return true; + } + return false; + } + + /** + * Add Flag for an index that translates to platform specific handling. + * + * @example $index->addFlag('CLUSTERED') + * @param string $flag + * @return Index + */ + public function addFlag($flag) + { + $this->flags[strtolower($flag)] = true; + return $this; + } + + /** + * Does this index have a specific flag? + * + * @param string $flag + * @return bool + */ + public function hasFlag($flag) + { + return isset($this->flags[strtolower($flag)]); + } + + /** + * Remove a flag + * + * @param string $flag + * @return void + */ + public function removeFlag($flag) + { + unset($this->flags[strtolower($flag)]); + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php new file mode 100644 index 0000000..a9a5964 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php @@ -0,0 +1,208 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * Schema manager for the MySql RDBMS. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @author Konsta Vesterinen + * @author Lukas Smith (PEAR MDB2 library) + * @author Roman Borschel + * @author Benjamin Eberlei + * @version $Revision$ + * @since 2.0 + */ +class MySqlSchemaManager extends AbstractSchemaManager +{ + protected function _getPortableViewDefinition($view) + { + return new View($view['TABLE_NAME'], $view['VIEW_DEFINITION']); + } + + protected function _getPortableTableDefinition($table) + { + return array_shift($table); + } + + protected function _getPortableUserDefinition($user) + { + return array( + 'user' => $user['User'], + 'password' => $user['Password'], + ); + } + + protected function _getPortableTableIndexesList($tableIndexes, $tableName=null) + { + foreach($tableIndexes as $k => $v) { + $v = array_change_key_case($v, CASE_LOWER); + if($v['key_name'] == 'PRIMARY') { + $v['primary'] = true; + } else { + $v['primary'] = false; + } + if (strpos($v['index_type'], 'FULLTEXT') !== false) { + $v['flags'] = array('FULLTEXT'); + } + $tableIndexes[$k] = $v; + } + + return parent::_getPortableTableIndexesList($tableIndexes, $tableName); + } + + protected function _getPortableSequenceDefinition($sequence) + { + return end($sequence); + } + + protected function _getPortableDatabaseDefinition($database) + { + return $database['Database']; + } + + /** + * Gets a portable column definition. + * + * The database type is mapped to a corresponding Doctrine mapping type. + * + * @param $tableColumn + * @return array + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); + + $dbType = strtolower($tableColumn['type']); + $dbType = strtok($dbType, '(), '); + if (isset($tableColumn['length'])) { + $length = $tableColumn['length']; + $decimal = ''; + } else { + $length = strtok('(), '); + $decimal = strtok('(), ') ? strtok('(), '):null; + } + $type = array(); + $fixed = null; + + if ( ! isset($tableColumn['name'])) { + $tableColumn['name'] = ''; + } + + $scale = null; + $precision = null; + + $type = $this->_platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); + $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + + switch ($dbType) { + case 'char': + $fixed = true; + break; + case 'float': + case 'double': + case 'real': + case 'numeric': + case 'decimal': + if(preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['type'], $match)) { + $precision = $match[1]; + $scale = $match[2]; + $length = null; + } + break; + case 'tinyint': + case 'smallint': + case 'mediumint': + case 'int': + case 'integer': + case 'bigint': + case 'tinyblob': + case 'mediumblob': + case 'longblob': + case 'blob': + case 'year': + $length = null; + break; + } + + $length = ((int) $length == 0) ? null : (int) $length; + + $options = array( + 'length' => $length, + 'unsigned' => (bool) (strpos($tableColumn['type'], 'unsigned') !== false), + 'fixed' => (bool) $fixed, + 'default' => isset($tableColumn['default']) ? $tableColumn['default'] : null, + 'notnull' => (bool) ($tableColumn['null'] != 'YES'), + 'scale' => null, + 'precision' => null, + 'autoincrement' => (bool) (strpos($tableColumn['extra'], 'auto_increment') !== false), + 'comment' => (isset($tableColumn['comment'])) ? $tableColumn['comment'] : null + ); + + if ($scale !== null && $precision !== null) { + $options['scale'] = $scale; + $options['precision'] = $precision; + } + + return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options); + } + + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $list = array(); + foreach ($tableForeignKeys as $key => $value) { + $value = array_change_key_case($value, CASE_LOWER); + if (!isset($list[$value['constraint_name']])) { + if (!isset($value['delete_rule']) || $value['delete_rule'] == "RESTRICT") { + $value['delete_rule'] = null; + } + if (!isset($value['update_rule']) || $value['update_rule'] == "RESTRICT") { + $value['update_rule'] = null; + } + + $list[$value['constraint_name']] = array( + 'name' => $value['constraint_name'], + 'local' => array(), + 'foreign' => array(), + 'foreignTable' => $value['referenced_table_name'], + 'onDelete' => $value['delete_rule'], + 'onUpdate' => $value['update_rule'], + ); + } + $list[$value['constraint_name']]['local'][] = $value['column_name']; + $list[$value['constraint_name']]['foreign'][] = $value['referenced_column_name']; + } + + $result = array(); + foreach($list as $constraint) { + $result[] = new ForeignKeyConstraint( + array_values($constraint['local']), $constraint['foreignTable'], + array_values($constraint['foreign']), $constraint['name'], + array( + 'onDelete' => $constraint['onDelete'], + 'onUpdate' => $constraint['onUpdate'], + ) + ); + } + + return $result; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php new file mode 100644 index 0000000..2a880d9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php @@ -0,0 +1,286 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * Oracle Schema Manager + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @author Konsta Vesterinen + * @author Lukas Smith (PEAR MDB2 library) + * @author Benjamin Eberlei + * @version $Revision$ + * @since 2.0 + */ +class OracleSchemaManager extends AbstractSchemaManager +{ + protected function _getPortableViewDefinition($view) + { + $view = \array_change_key_case($view, CASE_LOWER); + + return new View($view['view_name'], $view['text']); + } + + protected function _getPortableUserDefinition($user) + { + $user = \array_change_key_case($user, CASE_LOWER); + + return array( + 'user' => $user['username'], + ); + } + + protected function _getPortableTableDefinition($table) + { + $table = \array_change_key_case($table, CASE_LOWER); + + return $table['table_name']; + } + + /** + * @license New BSD License + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html + * @param array $tableIndexes + * @param string $tableName + * @return array + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName=null) + { + $indexBuffer = array(); + foreach ( $tableIndexes as $tableIndex ) { + $tableIndex = \array_change_key_case($tableIndex, CASE_LOWER); + + $keyName = strtolower($tableIndex['name']); + + if ( strtolower($tableIndex['is_primary']) == "p" ) { + $keyName = 'primary'; + $buffer['primary'] = true; + $buffer['non_unique'] = false; + } else { + $buffer['primary'] = false; + $buffer['non_unique'] = ( $tableIndex['is_unique'] == 0 ) ? true : false; + } + $buffer['key_name'] = $keyName; + $buffer['column_name'] = $tableIndex['column_name']; + $indexBuffer[] = $buffer; + } + return parent::_getPortableTableIndexesList($indexBuffer, $tableName); + } + + protected function _getPortableTableColumnDefinition($tableColumn) + { + $tableColumn = \array_change_key_case($tableColumn, CASE_LOWER); + + $dbType = strtolower($tableColumn['data_type']); + if(strpos($dbType, "timestamp(") === 0) { + if (strpos($dbType, "WITH TIME ZONE")) { + $dbType = "timestamptz"; + } else { + $dbType = "timestamp"; + } + } + + $type = array(); + $length = $unsigned = $fixed = null; + if ( ! empty($tableColumn['data_length'])) { + $length = $tableColumn['data_length']; + } + + if ( ! isset($tableColumn['column_name'])) { + $tableColumn['column_name'] = ''; + } + + if (stripos($tableColumn['data_default'], 'NULL') !== null) { + $tableColumn['data_default'] = null; + } + + $precision = null; + $scale = null; + + $type = $this->_platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comments'], $type); + $tableColumn['comments'] = $this->removeDoctrineTypeFromComment($tableColumn['comments'], $type); + + switch ($dbType) { + case 'number': + if ($tableColumn['data_precision'] == 20 && $tableColumn['data_scale'] == 0) { + $precision = 20; + $scale = 0; + $type = 'bigint'; + } elseif ($tableColumn['data_precision'] == 5 && $tableColumn['data_scale'] == 0) { + $type = 'smallint'; + $precision = 5; + $scale = 0; + } elseif ($tableColumn['data_precision'] == 1 && $tableColumn['data_scale'] == 0) { + $precision = 1; + $scale = 0; + $type = 'boolean'; + } elseif ($tableColumn['data_scale'] > 0) { + $precision = $tableColumn['data_precision']; + $scale = $tableColumn['data_scale']; + $type = 'decimal'; + } + $length = null; + break; + case 'pls_integer': + case 'binary_integer': + $length = null; + break; + case 'varchar': + case 'varchar2': + case 'nvarchar2': + $length = $tableColumn['char_length']; + $fixed = false; + break; + case 'char': + case 'nchar': + $length = $tableColumn['char_length']; + $fixed = true; + break; + case 'date': + case 'timestamp': + $length = null; + break; + case 'float': + $precision = $tableColumn['data_precision']; + $scale = $tableColumn['data_scale']; + $length = null; + break; + case 'clob': + case 'nclob': + $length = null; + break; + case 'blob': + case 'raw': + case 'long raw': + case 'bfile': + $length = null; + break; + case 'rowid': + case 'urowid': + default: + $length = null; + } + + $options = array( + 'notnull' => (bool) ($tableColumn['nullable'] === 'N'), + 'fixed' => (bool) $fixed, + 'unsigned' => (bool) $unsigned, + 'default' => $tableColumn['data_default'], + 'length' => $length, + 'precision' => $precision, + 'scale' => $scale, + 'comment' => (isset($tableColumn['comments'])) ? $tableColumn['comments'] : null, + 'platformDetails' => array(), + ); + + return new Column($tableColumn['column_name'], \Doctrine\DBAL\Types\Type::getType($type), $options); + } + + protected function _getPortableTableForeignKeysList($tableForeignKeys) + { + $list = array(); + foreach ($tableForeignKeys as $value) { + $value = \array_change_key_case($value, CASE_LOWER); + if (!isset($list[$value['constraint_name']])) { + if ($value['delete_rule'] == "NO ACTION") { + $value['delete_rule'] = null; + } + + $list[$value['constraint_name']] = array( + 'name' => $value['constraint_name'], + 'local' => array(), + 'foreign' => array(), + 'foreignTable' => $value['references_table'], + 'onDelete' => $value['delete_rule'], + ); + } + $list[$value['constraint_name']]['local'][$value['position']] = $value['local_column']; + $list[$value['constraint_name']]['foreign'][$value['position']] = $value['foreign_column']; + } + + $result = array(); + foreach($list as $constraint) { + $result[] = new ForeignKeyConstraint( + array_values($constraint['local']), $constraint['foreignTable'], + array_values($constraint['foreign']), $constraint['name'], + array('onDelete' => $constraint['onDelete']) + ); + } + + return $result; + } + + protected function _getPortableSequenceDefinition($sequence) + { + $sequence = \array_change_key_case($sequence, CASE_LOWER); + return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['min_value']); + } + + protected function _getPortableFunctionDefinition($function) + { + $function = \array_change_key_case($function, CASE_LOWER); + return $function['name']; + } + + protected function _getPortableDatabaseDefinition($database) + { + $database = \array_change_key_case($database, CASE_LOWER); + return $database['username']; + } + + public function createDatabase($database = null) + { + if (is_null($database)) { + $database = $this->_conn->getDatabase(); + } + + $params = $this->_conn->getParams(); + $username = $database; + $password = $params['password']; + + $query = 'CREATE USER ' . $username . ' IDENTIFIED BY ' . $password; + $result = $this->_conn->executeUpdate($query); + + $query = 'GRANT CREATE SESSION, CREATE TABLE, UNLIMITED TABLESPACE, CREATE SEQUENCE, CREATE TRIGGER TO ' . $username; + $result = $this->_conn->executeUpdate($query); + + return true; + } + + public function dropAutoincrement($table) + { + $sql = $this->_platform->getDropAutoincrementSql($table); + foreach ($sql as $query) { + $this->_conn->executeUpdate($query); + } + + return true; + } + + public function dropTable($name) + { + $this->dropAutoincrement($name); + + return parent::dropTable($name); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php new file mode 100644 index 0000000..800fee2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php @@ -0,0 +1,359 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * PostgreSQL Schema Manager + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @author Konsta Vesterinen + * @author Lukas Smith (PEAR MDB2 library) + * @author Benjamin Eberlei + * @since 2.0 + */ +class PostgreSqlSchemaManager extends AbstractSchemaManager +{ + /** + * @var array + */ + private $existingSchemaPaths; + + /** + * Get all the existing schema names. + * + * @return array + */ + public function getSchemaNames() + { + $rows = $this->_conn->fetchAll("SELECT nspname as schema_name FROM pg_namespace WHERE nspname !~ '^pg_.*' and nspname != 'information_schema'"); + return array_map(function($v) { return $v['schema_name']; }, $rows); + } + + /** + * Return an array of schema search paths + * + * This is a PostgreSQL only function. + * + * @return array + */ + public function getSchemaSearchPaths() + { + $params = $this->_conn->getParams(); + $schema = explode(",", $this->_conn->fetchColumn('SHOW search_path')); + if (isset($params['user'])) { + $schema = str_replace('"$user"', $params['user'], $schema); + } + return $schema; + } + + /** + * Get names of all existing schemas in the current users search path. + * + * This is a PostgreSQL only function. + * + * @return array + */ + public function getExistingSchemaSearchPaths() + { + if ($this->existingSchemaPaths === null) { + $this->determineExistingSchemaSearchPaths(); + } + return $this->existingSchemaPaths; + } + + /** + * Use this to set or reset the order of the existing schemas in the current search path of the user + * + * This is a PostgreSQL only function. + * + * @return void + */ + public function determineExistingSchemaSearchPaths() + { + $names = $this->getSchemaNames(); + $paths = $this->getSchemaSearchPaths(); + + $this->existingSchemaPaths = array_filter($paths, function ($v) use ($names) { + return in_array($v, $names); + }); + } + + protected function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + $onUpdate = null; + $onDelete = null; + + if (preg_match('(ON UPDATE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match)) { + $onUpdate = $match[1]; + } + if (preg_match('(ON DELETE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match)) { + $onDelete = $match[1]; + } + + if (preg_match('/FOREIGN KEY \((.+)\) REFERENCES (.+)\((.+)\)/', $tableForeignKey['condef'], $values)) { + // PostgreSQL returns identifiers that are keywords with quotes, we need them later, don't get + // the idea to trim them here. + $localColumns = array_map('trim', explode(",", $values[1])); + $foreignColumns = array_map('trim', explode(",", $values[3])); + $foreignTable = $values[2]; + } + + return new ForeignKeyConstraint( + $localColumns, $foreignTable, $foreignColumns, $tableForeignKey['conname'], + array('onUpdate' => $onUpdate, 'onDelete' => $onDelete) + ); + } + + public function dropDatabase($database) + { + $params = $this->_conn->getParams(); + $params["dbname"] = "postgres"; + $tmpPlatform = $this->_platform; + $tmpConn = $this->_conn; + + $this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params); + $this->_platform = $this->_conn->getDatabasePlatform(); + + parent::dropDatabase($database); + + $this->_platform = $tmpPlatform; + $this->_conn = $tmpConn; + } + + public function createDatabase($database) + { + $params = $this->_conn->getParams(); + $params["dbname"] = "postgres"; + $tmpPlatform = $this->_platform; + $tmpConn = $this->_conn; + + $this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params); + $this->_platform = $this->_conn->getDatabasePlatform(); + + parent::createDatabase($database); + + $this->_platform = $tmpPlatform; + $this->_conn = $tmpConn; + } + + protected function _getPortableTriggerDefinition($trigger) + { + return $trigger['trigger_name']; + } + + protected function _getPortableViewDefinition($view) + { + return new View($view['viewname'], $view['definition']); + } + + protected function _getPortableUserDefinition($user) + { + return array( + 'user' => $user['usename'], + 'password' => $user['passwd'] + ); + } + + protected function _getPortableTableDefinition($table) + { + $schemas = $this->getExistingSchemaSearchPaths(); + $firstSchema = array_shift($schemas); + + if ($table['schema_name'] == $firstSchema) { + return $table['table_name']; + } else { + return $table['schema_name'] . "." . $table['table_name']; + } + } + + /** + * @license New BSD License + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html + * @param array $tableIndexes + * @param string $tableName + * @return array + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName=null) + { + $buffer = array(); + foreach ($tableIndexes as $row) { + $colNumbers = explode(' ', $row['indkey']); + $colNumbersSql = 'IN (' . join(' ,', $colNumbers) . ' )'; + $columnNameSql = "SELECT attnum, attname FROM pg_attribute + WHERE attrelid={$row['indrelid']} AND attnum $colNumbersSql ORDER BY attnum ASC;"; + + $stmt = $this->_conn->executeQuery($columnNameSql); + $indexColumns = $stmt->fetchAll(); + + // required for getting the order of the columns right. + foreach ($colNumbers as $colNum) { + foreach ($indexColumns as $colRow) { + if ($colNum == $colRow['attnum']) { + $buffer[] = array( + 'key_name' => $row['relname'], + 'column_name' => trim($colRow['attname']), + 'non_unique' => !$row['indisunique'], + 'primary' => $row['indisprimary'] + ); + } + } + } + } + return parent::_getPortableTableIndexesList($buffer, $tableName); + } + + protected function _getPortableDatabaseDefinition($database) + { + return $database['datname']; + } + + protected function _getPortableSequenceDefinition($sequence) + { + if ($sequence['schemaname'] != 'public') { + $sequenceName = $sequence['schemaname'] . "." . $sequence['relname']; + } else { + $sequenceName = $sequence['relname']; + } + + $data = $this->_conn->fetchAll('SELECT min_value, increment_by FROM ' . $sequenceName); + return new Sequence($sequenceName, $data[0]['increment_by'], $data[0]['min_value']); + } + + protected function _getPortableTableColumnDefinition($tableColumn) + { + $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); + + if (strtolower($tableColumn['type']) === 'varchar') { + // get length from varchar definition + $length = preg_replace('~.*\(([0-9]*)\).*~', '$1', $tableColumn['complete_type']); + $tableColumn['length'] = $length; + } + + $matches = array(); + + $autoincrement = false; + if (preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches)) { + $tableColumn['sequence'] = $matches[1]; + $tableColumn['default'] = null; + $autoincrement = true; + } + + if (stripos($tableColumn['default'], 'NULL') === 0) { + $tableColumn['default'] = null; + } + + $length = (isset($tableColumn['length'])) ? $tableColumn['length'] : null; + if ($length == '-1' && isset($tableColumn['atttypmod'])) { + $length = $tableColumn['atttypmod'] - 4; + } + if ((int) $length <= 0) { + $length = null; + } + $fixed = null; + + if (!isset($tableColumn['name'])) { + $tableColumn['name'] = ''; + } + + $precision = null; + $scale = null; + + $dbType = strtolower($tableColumn['type']); + if (strlen($tableColumn['domain_type']) && !$this->_platform->hasDoctrineTypeMappingFor($tableColumn['type'])) { + $dbType = strtolower($tableColumn['domain_type']); + $tableColumn['complete_type'] = $tableColumn['domain_complete_type']; + } + + $type = $this->_platform->getDoctrineTypeMapping($dbType); + $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); + $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); + + switch ($dbType) { + case 'smallint': + case 'int2': + $length = null; + break; + case 'int': + case 'int4': + case 'integer': + $length = null; + break; + case 'bigint': + case 'int8': + $length = null; + break; + case 'bool': + case 'boolean': + $length = null; + break; + case 'text': + $fixed = false; + break; + case 'varchar': + case 'interval': + case '_varchar': + $fixed = false; + break; + case 'char': + case 'bpchar': + $fixed = true; + break; + case 'float': + case 'float4': + case 'float8': + case 'double': + case 'double precision': + case 'real': + case 'decimal': + case 'money': + case 'numeric': + if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['complete_type'], $match)) { + $precision = $match[1]; + $scale = $match[2]; + $length = null; + } + break; + case 'year': + $length = null; + break; + } + + if ($tableColumn['default'] && preg_match("('([^']+)'::)", $tableColumn['default'], $match)) { + $tableColumn['default'] = $match[1]; + } + + $options = array( + 'length' => $length, + 'notnull' => (bool) $tableColumn['isnotnull'], + 'default' => $tableColumn['default'], + 'primary' => (bool) ($tableColumn['pri'] == 't'), + 'precision' => $precision, + 'scale' => $scale, + 'fixed' => $fixed, + 'unsigned' => false, + 'autoincrement' => $autoincrement, + 'comment' => $tableColumn['comment'], + ); + + return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options); + } + +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php new file mode 100644 index 0000000..174dc11 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php @@ -0,0 +1,263 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Events; +use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs; +use Doctrine\DBAL\Driver\SQLSrv\SQLSrvException; + +/** + * SQL Server Schema Manager + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @author Konsta Vesterinen + * @author Lukas Smith (PEAR MDB2 library) + * @author Juozas Kaziukenas + * @since 2.0 + */ +class SQLServerSchemaManager extends AbstractSchemaManager +{ + /** + * @override + */ + protected function _getPortableTableColumnDefinition($tableColumn) + { + $dbType = strtolower($tableColumn['TYPE_NAME']); + + $autoincrement = false; + if (stripos($dbType, 'identity')) { + $dbType = trim(str_ireplace('identity', '', $dbType)); + $autoincrement = true; + } + + $type = array(); + $unsigned = $fixed = null; + + if (!isset($tableColumn['name'])) { + $tableColumn['name'] = ''; + } + + $default = $tableColumn['COLUMN_DEF']; + + while ($default != ($default2 = preg_replace("/^\((.*)\)$/", '$1', $default))) { + $default = trim($default2, "'"); + } + + $length = (int) $tableColumn['LENGTH']; + + $type = $this->_platform->getDoctrineTypeMapping($dbType); + switch ($type) { + case 'char': + if ($tableColumn['LENGTH'] == '1') { + $type = 'boolean'; + if (preg_match('/^(is|has)/', $tableColumn['name'])) { + $type = array_reverse($type); + } + } + $fixed = true; + break; + case 'text': + $fixed = false; + break; + } + switch ($dbType) { + case 'nchar': + case 'nvarchar': + case 'ntext': + // Unicode data requires 2 bytes per character + $length = $length / 2; + break; + } + + $options = array( + 'length' => ($length == 0 || !in_array($type, array('text', 'string'))) ? null : $length, + 'unsigned' => (bool) $unsigned, + 'fixed' => (bool) $fixed, + 'default' => $default !== 'NULL' ? $default : null, + 'notnull' => (bool) ($tableColumn['IS_NULLABLE'] != 'YES'), + 'scale' => $tableColumn['SCALE'], + 'precision' => $tableColumn['PRECISION'], + 'autoincrement' => $autoincrement, + ); + + return new Column($tableColumn['COLUMN_NAME'], \Doctrine\DBAL\Types\Type::getType($type), $options); + } + + /** + * @override + */ + protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null) + { + // TODO: Remove code duplication with AbstractSchemaManager; + $result = array(); + foreach ($tableIndexRows as $tableIndex) { + $indexName = $keyName = $tableIndex['index_name']; + if (strpos($tableIndex['index_description'], 'primary key') !== false) { + $keyName = 'primary'; + } + $keyName = strtolower($keyName); + + $flags = array(); + if (strpos($tableIndex['index_description'], 'clustered') !== false) { + $flags[] = 'clustered'; + } else if (strpos($tableIndex['index_description'], 'nonclustered') !== false) { + $flags[] = 'nonclustered'; + } + + $result[$keyName] = array( + 'name' => $indexName, + 'columns' => explode(', ', $tableIndex['index_keys']), + 'unique' => strpos($tableIndex['index_description'], 'unique') !== false, + 'primary' => strpos($tableIndex['index_description'], 'primary key') !== false, + 'flags' => $flags, + ); + } + + $eventManager = $this->_platform->getEventManager(); + + $indexes = array(); + foreach ($result as $indexKey => $data) { + $index = null; + $defaultPrevented = false; + + if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) { + $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn); + $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs); + + $defaultPrevented = $eventArgs->isDefaultPrevented(); + $index = $eventArgs->getIndex(); + } + + if ( ! $defaultPrevented) { + $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']); + } + + if ($index) { + $indexes[$indexKey] = $index; + } + } + + return $indexes; + } + + /** + * @override + */ + public function _getPortableTableForeignKeyDefinition($tableForeignKey) + { + return new ForeignKeyConstraint( + (array) $tableForeignKey['ColumnName'], + $tableForeignKey['ReferenceTableName'], + (array) $tableForeignKey['ReferenceColumnName'], + $tableForeignKey['ForeignKey'], + array( + 'onUpdate' => str_replace('_', ' ', $tableForeignKey['update_referential_action_desc']), + 'onDelete' => str_replace('_', ' ', $tableForeignKey['delete_referential_action_desc']), + ) + ); + } + + /** + * @override + */ + protected function _getPortableTableDefinition($table) + { + return $table['name']; + } + + /** + * @override + */ + protected function _getPortableDatabaseDefinition($database) + { + return $database['name']; + } + + /** + * @override + */ + protected function _getPortableViewDefinition($view) + { + // @todo + return new View($view['name'], null); + } + + /** + * List the indexes for a given table returning an array of Index instances. + * + * Keys of the portable indexes list are all lower-cased. + * + * @param string $table The name of the table + * @return Index[] $tableIndexes + */ + public function listTableIndexes($table) + { + $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); + + try { + $tableIndexes = $this->_conn->fetchAll($sql); + } catch(\PDOException $e) { + if ($e->getCode() == "IMSSP") { + return array(); + } else { + throw $e; + } + } catch(SQLSrvException $e) { + if (strpos($e->getMessage(), 'SQLSTATE [01000, 15472]') === 0) { + return array(); + } else { + throw $e; + } + } + + return $this->_getPortableTableIndexesList($tableIndexes, $table); + } + + /** + * @override + */ + public function alterTable(TableDiff $tableDiff) + { + if(count($tableDiff->removedColumns) > 0) { + foreach($tableDiff->removedColumns as $col){ + $columnConstraintSql = $this->getColumnConstraintSQL($tableDiff->name, $col->getName()); + foreach ($this->_conn->fetchAll($columnConstraintSql) as $constraint) { + $this->_conn->exec("ALTER TABLE $tableDiff->name DROP CONSTRAINT " . $constraint['Name']); + } + } + } + + return parent::alterTable($tableDiff); + } + + /** + * This function retrieves the constraints for a given column. + */ + private function getColumnConstraintSQL($table, $column) + { + return "SELECT SysObjects.[Name] + FROM SysObjects INNER JOIN (SELECT [Name],[ID] FROM SysObjects WHERE XType = 'U') AS Tab + ON Tab.[ID] = Sysobjects.[Parent_Obj] + INNER JOIN sys.default_constraints DefCons ON DefCons.[object_id] = Sysobjects.[ID] + INNER JOIN SysColumns Col ON Col.[ColID] = DefCons.[parent_column_id] AND Col.[ID] = Tab.[ID] + WHERE Col.[Name] = " . $this->_conn->quote($column) ." AND Tab.[Name] = " . $this->_conn->quote($table) . " + ORDER BY Col.[Name]"; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Schema.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Schema.php new file mode 100644 index 0000000..5a6ff75 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Schema.php @@ -0,0 +1,373 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Schema\Visitor\CreateSchemaSqlCollector; +use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector; +use Doctrine\DBAL\Schema\Visitor\Visitor; + +/** + * Object representation of a database schema + * + * Different vendors have very inconsistent naming with regard to the concept + * of a "schema". Doctrine understands a schema as the entity that conceptually + * wraps a set of database objects such as tables, sequences, indexes and + * foreign keys that belong to each other into a namespace. A Doctrine Schema + * has nothing to do with the "SCHEMA" defined as in PostgreSQL, it is more + * related to the concept of "DATABASE" that exists in MySQL and PostgreSQL. + * + * Every asset in the doctrine schema has a name. A name consists of either a + * namespace.local name pair or just a local unqualified name. + * + * The abstraction layer that covers a PostgreSQL schema is the namespace of an + * database object (asset). A schema can have a name, which will be used as + * default namespace for the unqualified database objects that are created in + * the schema. + * + * In the case of MySQL where cross-database queries are allowed this leads to + * databases being "misinterpreted" as namespaces. This is intentional, however + * the CREATE/DROP SQL visitors will just filter this queries and do not + * execute them. Only the queries for the currently connected database are + * executed. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + */ +class Schema extends AbstractAsset +{ + /** + * @var array + */ + protected $_tables = array(); + + /** + * @var array + */ + protected $_sequences = array(); + + /** + * @var SchemaConfig + */ + protected $_schemaConfig = false; + + /** + * @param array $tables + * @param array $sequences + * @param array $views + * @param array $triggers + * @param SchemaConfig $schemaConfig + */ + public function __construct(array $tables=array(), array $sequences=array(), SchemaConfig $schemaConfig=null) + { + if ($schemaConfig == null) { + $schemaConfig = new SchemaConfig(); + } + $this->_schemaConfig = $schemaConfig; + $this->_setName($schemaConfig->getName() ?: 'public'); + + foreach ($tables as $table) { + $this->_addTable($table); + } + + foreach ($sequences as $sequence) { + $this->_addSequence($sequence); + } + } + + /** + * @return bool + */ + public function hasExplicitForeignKeyIndexes() + { + return $this->_schemaConfig->hasExplicitForeignKeyIndexes(); + } + + /** + * @param Table $table + */ + protected function _addTable(Table $table) + { + $tableName = $table->getFullQualifiedName($this->getName()); + if(isset($this->_tables[$tableName])) { + throw SchemaException::tableAlreadyExists($tableName); + } + + $this->_tables[$tableName] = $table; + $table->setSchemaConfig($this->_schemaConfig); + } + + /** + * @param Sequence $sequence + */ + protected function _addSequence(Sequence $sequence) + { + $seqName = $sequence->getFullQualifiedName($this->getName()); + if (isset($this->_sequences[$seqName])) { + throw SchemaException::sequenceAlreadyExists($seqName); + } + $this->_sequences[$seqName] = $sequence; + } + + /** + * Get all tables of this schema. + * + * @return array + */ + public function getTables() + { + return $this->_tables; + } + + /** + * @param string $tableName + * @return Table + */ + public function getTable($tableName) + { + $tableName = $this->getFullQualifiedAssetName($tableName); + if (!isset($this->_tables[$tableName])) { + throw SchemaException::tableDoesNotExist($tableName); + } + + return $this->_tables[$tableName]; + } + + /** + * @return string + */ + private function getFullQualifiedAssetName($name) + { + if ($this->isIdentifierQuoted($name)) { + $name = $this->trimQuotes($name); + } + if (strpos($name, ".") === false) { + $name = $this->getName() . "." . $name; + } + return strtolower($name); + } + + /** + * Does this schema have a table with the given name? + * + * @param string $tableName + * @return Schema + */ + public function hasTable($tableName) + { + $tableName = $this->getFullQualifiedAssetName($tableName); + return isset($this->_tables[$tableName]); + } + + /** + * Get all table names, prefixed with a schema name, even the default one + * if present. + * + * @return array + */ + public function getTableNames() + { + return array_keys($this->_tables); + } + + public function hasSequence($sequenceName) + { + $sequenceName = $this->getFullQualifiedAssetName($sequenceName); + return isset($this->_sequences[$sequenceName]); + } + + /** + * @throws SchemaException + * @param string $sequenceName + * @return \Doctrine\DBAL\Schema\Sequence + */ + public function getSequence($sequenceName) + { + $sequenceName = $this->getFullQualifiedAssetName($sequenceName); + if(!$this->hasSequence($sequenceName)) { + throw SchemaException::sequenceDoesNotExist($sequenceName); + } + return $this->_sequences[$sequenceName]; + } + + /** + * @return \Doctrine\DBAL\Schema\Sequence[] + */ + public function getSequences() + { + return $this->_sequences; + } + + /** + * Create a new table + * + * @param string $tableName + * @return Table + */ + public function createTable($tableName) + { + $table = new Table($tableName); + $this->_addTable($table); + + foreach ($this->_schemaConfig->getDefaultTableOptions() as $name => $value) { + $table->addOption($name, $value); + } + + return $table; + } + + /** + * Rename a table + * + * @param string $oldTableName + * @param string $newTableName + * @return Schema + */ + public function renameTable($oldTableName, $newTableName) + { + $table = $this->getTable($oldTableName); + $table->_setName($newTableName); + + $this->dropTable($oldTableName); + $this->_addTable($table); + return $this; + } + + /** + * Drop a table from the schema. + * + * @param string $tableName + * @return Schema + */ + public function dropTable($tableName) + { + $tableName = $this->getFullQualifiedAssetName($tableName); + $table = $this->getTable($tableName); + unset($this->_tables[$tableName]); + return $this; + } + + /** + * Create a new sequence + * + * @param string $sequenceName + * @param int $allocationSize + * @param int $initialValue + * @return Sequence + */ + public function createSequence($sequenceName, $allocationSize=1, $initialValue=1) + { + $seq = new Sequence($sequenceName, $allocationSize, $initialValue); + $this->_addSequence($seq); + return $seq; + } + + /** + * @param string $sequenceName + * @return Schema + */ + public function dropSequence($sequenceName) + { + $sequenceName = $this->getFullQualifiedAssetName($sequenceName); + unset($this->_sequences[$sequenceName]); + return $this; + } + + /** + * Return an array of necessary sql queries to create the schema on the given platform. + * + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + * @return array + */ + public function toSql(\Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + $sqlCollector = new CreateSchemaSqlCollector($platform); + $this->visit($sqlCollector); + + return $sqlCollector->getQueries(); + } + + /** + * Return an array of necessary sql queries to drop the schema on the given platform. + * + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + * @return array + */ + public function toDropSql(\Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + $dropSqlCollector = new DropSchemaSqlCollector($platform); + $this->visit($dropSqlCollector); + + return $dropSqlCollector->getQueries(); + } + + /** + * @param Schema $toSchema + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function getMigrateToSql(Schema $toSchema, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + $comparator = new Comparator(); + $schemaDiff = $comparator->compare($this, $toSchema); + return $schemaDiff->toSql($platform); + } + + /** + * @param Schema $fromSchema + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + */ + public function getMigrateFromSql(Schema $fromSchema, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + $comparator = new Comparator(); + $schemaDiff = $comparator->compare($fromSchema, $this); + return $schemaDiff->toSql($platform); + } + + /** + * @param Visitor $visitor + */ + public function visit(Visitor $visitor) + { + $visitor->acceptSchema($this); + + foreach ($this->_tables as $table) { + $table->visit($visitor); + } + foreach ($this->_sequences as $sequence) { + $sequence->visit($visitor); + } + } + + /** + * Cloning a Schema triggers a deep clone of all related assets. + * + * @return void + */ + public function __clone() + { + foreach ($this->_tables as $k => $table) { + $this->_tables[$k] = clone $table; + } + foreach ($this->_sequences as $k => $sequence) { + $this->_sequences[$k] = clone $sequence; + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaConfig.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaConfig.php new file mode 100644 index 0000000..d90da20 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaConfig.php @@ -0,0 +1,119 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * Configuration for a Schema + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + */ +class SchemaConfig +{ + /** + * @var bool + */ + protected $hasExplicitForeignKeyIndexes = false; + + /** + * @var int + */ + protected $maxIdentifierLength = 63; + + /** + * @var string + */ + protected $name; + + /** + * @var array + */ + protected $defaultTableOptions = array(); + + /** + * @return bool + */ + public function hasExplicitForeignKeyIndexes() + { + return $this->hasExplicitForeignKeyIndexes; + } + + /** + * @param bool $flag + */ + public function setExplicitForeignKeyIndexes($flag) + { + $this->hasExplicitForeignKeyIndexes = (bool)$flag; + } + + /** + * @param int $length + */ + public function setMaxIdentifierLength($length) + { + $this->maxIdentifierLength = (int)$length; + } + + /** + * @return int + */ + public function getMaxIdentifierLength() + { + return $this->maxIdentifierLength; + } + + /** + * Get default namespace of schema objects. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * set default namespace name of schema objects. + * + * @param string $name the value to set. + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Get the default options that are passed to Table instances created with + * Schema#createTable(). + * + * @return array + */ + public function getDefaultTableOptions() + { + return $this->defaultTableOptions; + } + + public function setDefaultTableOptions(array $defaultTableOptions) + { + $this->defaultTableOptions = $defaultTableOptions; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaDiff.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaDiff.php new file mode 100644 index 0000000..ba0d9e6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaDiff.php @@ -0,0 +1,176 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use \Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Schema Diff + * + * + * @link www.doctrine-project.org + * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class SchemaDiff +{ + /** + * All added tables + * + * @var array(string=>ezcDbSchemaTable) + */ + public $newTables = array(); + + /** + * All changed tables + * + * @var array(string=>ezcDbSchemaTableDiff) + */ + public $changedTables = array(); + + /** + * All removed tables + * + * @var array(string=>Table) + */ + public $removedTables = array(); + + /** + * @var array + */ + public $newSequences = array(); + + /** + * @var array + */ + public $changedSequences = array(); + + /** + * @var array + */ + public $removedSequences = array(); + + /** + * @var array + */ + public $orphanedForeignKeys = array(); + + /** + * Constructs an SchemaDiff object. + * + * @param array(string=>Table) $newTables + * @param array(string=>TableDiff) $changedTables + * @param array(string=>bool) $removedTables + */ + public function __construct($newTables = array(), $changedTables = array(), $removedTables = array()) + { + $this->newTables = $newTables; + $this->changedTables = $changedTables; + $this->removedTables = $removedTables; + } + + /** + * The to save sql mode ensures that the following things don't happen: + * + * 1. Tables are deleted + * 2. Sequences are deleted + * 3. Foreign Keys which reference tables that would otherwise be deleted. + * + * This way it is ensured that assets are deleted which might not be relevant to the metadata schema at all. + * + * @param AbstractPlatform $platform + * @return array + */ + public function toSaveSql(AbstractPlatform $platform) + { + return $this->_toSql($platform, true); + } + + /** + * @param AbstractPlatform $platform + * @return array + */ + public function toSql(AbstractPlatform $platform) + { + return $this->_toSql($platform, false); + } + + /** + * @param AbstractPlatform $platform + * @param bool $saveMode + * @return array + */ + protected function _toSql(AbstractPlatform $platform, $saveMode = false) + { + $sql = array(); + + if ($platform->supportsForeignKeyConstraints() && $saveMode == false) { + foreach ($this->orphanedForeignKeys as $orphanedForeignKey) { + $sql[] = $platform->getDropForeignKeySQL($orphanedForeignKey, $orphanedForeignKey->getLocalTableName()); + } + } + + if ($platform->supportsSequences() == true) { + foreach ($this->changedSequences as $sequence) { + $sql[] = $platform->getAlterSequenceSQL($sequence); + } + + if ($saveMode === false) { + foreach ($this->removedSequences as $sequence) { + $sql[] = $platform->getDropSequenceSQL($sequence); + } + } + + foreach ($this->newSequences as $sequence) { + $sql[] = $platform->getCreateSequenceSQL($sequence); + } + } + + $foreignKeySql = array(); + foreach ($this->newTables as $table) { + $sql = array_merge( + $sql, + $platform->getCreateTableSQL($table, AbstractPlatform::CREATE_INDEXES) + ); + + if ($platform->supportsForeignKeyConstraints()) { + foreach ($table->getForeignKeys() as $foreignKey) { + $foreignKeySql[] = $platform->getCreateForeignKeySQL($foreignKey, $table); + } + } + } + $sql = array_merge($sql, $foreignKeySql); + + if ($saveMode === false) { + foreach ($this->removedTables as $table) { + $sql[] = $platform->getDropTableSQL($table); + } + } + + foreach ($this->changedTables as $tableDiff) { + $sql = array_merge($sql, $platform->getAlterTableSQL($tableDiff)); + } + + return $sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaException.php new file mode 100644 index 0000000..a8cb93d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SchemaException.php @@ -0,0 +1,126 @@ +getName()." requires a named foreign key, ". + "but the given foreign key from (".implode(", ", $foreignKey->getColumns()).") onto foreign table ". + "'".$foreignKey->getForeignTableName()."' (".implode(", ", $foreignKey->getForeignColumns()).") is currently ". + "unnamed." + ); + } + + static public function alterTableChangeNotSupported($changeName) { + return new self ("Alter table change not supported, given '$changeName'"); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Sequence.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Sequence.php new file mode 100644 index 0000000..87ff0fa --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Sequence.php @@ -0,0 +1,120 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Schema\Visitor\Visitor; + +/** + * Sequence Structure + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class Sequence extends AbstractAsset +{ + /** + * @var int + */ + protected $_allocationSize = 1; + + /** + * @var int + */ + protected $_initialValue = 1; + + /** + * + * @param string $name + * @param int $allocationSize + * @param int $initialValue + */ + public function __construct($name, $allocationSize=1, $initialValue=1) + { + $this->_setName($name); + $this->_allocationSize = (is_numeric($allocationSize))?$allocationSize:1; + $this->_initialValue = (is_numeric($initialValue))?$initialValue:1; + } + + public function getAllocationSize() + { + return $this->_allocationSize; + } + + public function getInitialValue() + { + return $this->_initialValue; + } + + public function setAllocationSize($allocationSize) + { + $this->_allocationSize = (is_numeric($allocationSize))?$allocationSize:1; + } + + public function setInitialValue($initialValue) + { + $this->_initialValue = (is_numeric($initialValue))?$initialValue:1; + } + + /** + * Check if this sequence is an autoincrement sequence for a given table. + * + * This is used inside the comparator to not report sequences as missing, + * when the "from" schema implicitly creates the sequences. + * + * @param Table $table + * + * @return bool + */ + public function isAutoIncrementsFor(Table $table) + { + if ( ! $table->hasPrimaryKey()) { + return false; + } + + $pkColumns = $table->getPrimaryKey()->getColumns(); + + if (count($pkColumns) != 1) { + return false; + } + + $column = $table->getColumn($pkColumns[0]); + + if ( ! $column->getAutoincrement()) { + return false; + } + + $sequenceName = $this->getShortestName($table->getNamespaceName()); + $tableName = $table->getShortestName($table->getNamespaceName()); + $tableSequenceName = sprintf('%s_%s_seq', $tableName, $pkColumns[0]); + + return $tableSequenceName === $sequenceName; + } + + /** + * @param Visitor $visitor + */ + public function visit(Visitor $visitor) + { + $visitor->acceptSequence($this); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php new file mode 100644 index 0000000..41a941d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php @@ -0,0 +1,190 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * SqliteSchemaManager + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @author Konsta Vesterinen + * @author Lukas Smith (PEAR MDB2 library) + * @author Jonathan H. Wage + * @version $Revision$ + * @since 2.0 + */ +class SqliteSchemaManager extends AbstractSchemaManager +{ + /** + * {@inheritdoc} + * + * @override + */ + public function dropDatabase($database) + { + if (file_exists($database)) { + unlink($database); + } + } + + /** + * {@inheritdoc} + * + * @override + */ + public function createDatabase($database) + { + $params = $this->_conn->getParams(); + $driver = $params['driver']; + $options = array( + 'driver' => $driver, + 'path' => $database + ); + $conn = \Doctrine\DBAL\DriverManager::getConnection($options); + $conn->connect(); + $conn->close(); + } + + protected function _getPortableTableDefinition($table) + { + return $table['name']; + } + + /** + * @license New BSD License + * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html + * @param array $tableIndexes + * @param string $tableName + * @return array + */ + protected function _getPortableTableIndexesList($tableIndexes, $tableName=null) + { + $indexBuffer = array(); + + // fetch primary + $stmt = $this->_conn->executeQuery( "PRAGMA TABLE_INFO ('$tableName')" ); + $indexArray = $stmt->fetchAll(\PDO::FETCH_ASSOC); + foreach($indexArray as $indexColumnRow) { + if($indexColumnRow['pk'] == "1") { + $indexBuffer[] = array( + 'key_name' => 'primary', + 'primary' => true, + 'non_unique' => false, + 'column_name' => $indexColumnRow['name'] + ); + } + } + + // fetch regular indexes + foreach($tableIndexes as $tableIndex) { + // Ignore indexes with reserved names, e.g. autoindexes + if (strpos($tableIndex['name'], 'sqlite_') !== 0) { + $keyName = $tableIndex['name']; + $idx = array(); + $idx['key_name'] = $keyName; + $idx['primary'] = false; + $idx['non_unique'] = $tableIndex['unique']?false:true; + + $stmt = $this->_conn->executeQuery( "PRAGMA INDEX_INFO ( '{$keyName}' )" ); + $indexArray = $stmt->fetchAll(\PDO::FETCH_ASSOC); + + foreach ( $indexArray as $indexColumnRow ) { + $idx['column_name'] = $indexColumnRow['name']; + $indexBuffer[] = $idx; + } + } + } + + return parent::_getPortableTableIndexesList($indexBuffer, $tableName); + } + + protected function _getPortableTableIndexDefinition($tableIndex) + { + return array( + 'name' => $tableIndex['name'], + 'unique' => (bool) $tableIndex['unique'] + ); + } + + protected function _getPortableTableColumnDefinition($tableColumn) + { + $e = explode('(', $tableColumn['type']); + $tableColumn['type'] = $e[0]; + if (isset($e[1])) { + $length = trim($e[1], ')'); + $tableColumn['length'] = $length; + } + + $dbType = strtolower($tableColumn['type']); + $length = isset($tableColumn['length']) ? $tableColumn['length'] : null; + $unsigned = (boolean) isset($tableColumn['unsigned']) ? $tableColumn['unsigned'] : false; + $fixed = false; + $type = $this->_platform->getDoctrineTypeMapping($dbType); + $default = $tableColumn['dflt_value']; + if ($default == 'NULL') { + $default = null; + } + if ($default !== null) { + // SQLite returns strings wrapped in single quotes, so we need to strip them + $default = preg_replace("/^'(.*)'$/", '\1', $default); + } + $notnull = (bool) $tableColumn['notnull']; + + if ( ! isset($tableColumn['name'])) { + $tableColumn['name'] = ''; + } + + $precision = null; + $scale = null; + + switch ($dbType) { + case 'char': + $fixed = true; + break; + case 'float': + case 'double': + case 'real': + case 'decimal': + case 'numeric': + if (isset($tableColumn['length'])) { + list($precision, $scale) = array_map('trim', explode(', ', $tableColumn['length'])); + } + $length = null; + break; + } + + $options = array( + 'length' => $length, + 'unsigned' => (bool) $unsigned, + 'fixed' => $fixed, + 'notnull' => $notnull, + 'default' => $default, + 'precision' => $precision, + 'scale' => $scale, + 'autoincrement' => false, + ); + + return new Column($tableColumn['name'], \Doctrine\DBAL\Types\Type::getType($type), $options); + } + + protected function _getPortableViewDefinition($view) + { + return new View($view['name'], $view['sql']); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php new file mode 100644 index 0000000..16fb033 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php @@ -0,0 +1,58 @@ +. + */ + +namespace Doctrine\DBAL\Schema\Synchronizer; + +use Doctrine\DBAL\Connection; + +/** + * Abstract schema synchronizer with methods for executing batches of SQL. + */ +abstract class AbstractSchemaSynchronizer implements SchemaSynchronizer +{ + /** + * @var Connection + */ + protected $conn; + + public function __construct(Connection $conn) + { + $this->conn = $conn; + } + + protected function processSqlSafely(array $sql) + { + foreach ($sql as $s) { + try { + $this->conn->exec($s); + } catch(\Exception $e) { + + } + } + } + + protected function processSql(array $sql) + { + foreach ($sql as $s) { + $this->conn->exec($s); + } + } + +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php new file mode 100644 index 0000000..c249815 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php @@ -0,0 +1,96 @@ +. + */ + +namespace Doctrine\DBAL\Schema\Synchronizer; + +use Doctrine\DBAL\Schema\Schema; + +/** + * The synchronizer knows how to synchronize a schema with the configured + * database. + * + * @author Benjamin Eberlei + */ +interface SchemaSynchronizer +{ + /** + * Get the SQL statements that can be executed to create the schema. + * + * @param Schema $createSchema + * @return array + */ + function getCreateSchema(Schema $createSchema); + + /** + * Get the SQL Statements to update given schema with the underlying db. + * + * @param Schema $toSchema + * @param bool $noDrops + * @return array + */ + function getUpdateSchema(Schema $toSchema, $noDrops = false); + + /** + * Get the SQL Statements to drop the given schema from underlying db. + * + * @param Schema $dropSchema + * @return array + */ + function getDropSchema(Schema $dropSchema); + + /** + * Get the SQL statements to drop all schema assets from underlying db. + * + * @return array + */ + function getDropAllSchema(); + + /** + * Create the Schema + * + * @param Schema $createSchema + * @return void + */ + function createSchema(Schema $createSchema); + + /** + * Update the Schema to new schema version. + * + * @param Schema $toSchema + * @param bool $noDrops + * @return void + */ + function updateSchema(Schema $toSchema, $noDrops = false); + + /** + * Drop the given database schema from the underlying db. + * + * @param Schema $dropSchema + * @return void + */ + function dropSchema(Schema $dropSchema); + + /** + * Drop all assets from the underyling db. + * + * @return void + */ + function dropAllSchema(); +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizer.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizer.php new file mode 100644 index 0000000..38ea53a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizer.php @@ -0,0 +1,197 @@ +. + */ +namespace Doctrine\DBAL\Schema\Synchronizer; + +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Schema\Comparator; +use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector; + +/** + * Schema Synchronizer for Default DBAL Connection + * + * @author Benjamin Eberlei + */ +class SingleDatabaseSynchronizer extends AbstractSchemaSynchronizer +{ + /** + * @var Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $platform; + + public function __construct(Connection $conn) + { + parent::__construct($conn); + $this->platform = $conn->getDatabasePlatform(); + } + + /** + * Get the SQL statements that can be executed to create the schema. + * + * @param Schema $createSchema + * @return array + */ + public function getCreateSchema(Schema $createSchema) + { + return $createSchema->toSql($this->platform); + } + + /** + * Get the SQL Statements to update given schema with the underlying db. + * + * @param Schema $toSchema + * @param bool $noDrops + * @return array + */ + public function getUpdateSchema(Schema $toSchema, $noDrops = false) + { + $comparator = new Comparator(); + $sm = $this->conn->getSchemaManager(); + + $fromSchema = $sm->createSchema(); + $schemaDiff = $comparator->compare($fromSchema, $toSchema); + + if ($noDrops) { + return $schemaDiff->toSaveSql($this->platform); + } + + return $schemaDiff->toSql($this->platform); + } + + /** + * Get the SQL Statements to drop the given schema from underlying db. + * + * @param Schema $dropSchema + * @return array + */ + public function getDropSchema(Schema $dropSchema) + { + $visitor = new DropSchemaSqlCollector($this->platform); + $sm = $this->conn->getSchemaManager(); + + $fullSchema = $sm->createSchema(); + + foreach ($fullSchema->getTables() as $table) { + if ( $dropSchema->hasTable($table->getName())) { + $visitor->acceptTable($table); + } + + foreach ($table->getForeignKeys() as $foreignKey) { + if ( ! $dropSchema->hasTable($table->getName())) { + continue; + } + + if ( ! $dropSchema->hasTable($foreignKey->getForeignTableName())) { + continue; + } + + $visitor->acceptForeignKey($table, $foreignKey); + } + } + + if ( ! $this->platform->supportsSequences()) { + return $visitor->getQueries(); + } + + foreach ($dropSchema->getSequences() as $sequence) { + $visitor->acceptSequence($sequence); + } + + foreach ($dropSchema->getTables() as $table) { + /* @var $sequence Table */ + if ( ! $table->hasPrimaryKey()) { + continue; + } + + $columns = $table->getPrimaryKey()->getColumns(); + if (count($columns) > 1) { + continue; + } + + $checkSequence = $table->getName() . "_" . $columns[0] . "_seq"; + if ($fullSchema->hasSequence($checkSequence)) { + $visitor->acceptSequence($fullSchema->getSequence($checkSequence)); + } + } + + return $visitor->getQueries(); + } + + /** + * Get the SQL statements to drop all schema assets from underlying db. + * + * @return array + */ + public function getDropAllSchema() + { + $sm = $this->conn->getSchemaManager(); + $visitor = new DropSchemaSqlCollector($this->platform); + + /* @var $schema \Doctrine\DBAL\Schema\Schema */ + $schema = $sm->createSchema(); + $schema->visit($visitor); + + return $visitor->getQueries(); + } + + /** + * Create the Schema + * + * @param Schema $createSchema + * @return void + */ + public function createSchema(Schema $createSchema) + { + $this->processSql($this->getCreateSchema($createSchema)); + } + + /** + * Update the Schema to new schema version. + * + * @param Schema $toSchema + * @param bool $noDrops + * @return void + */ + public function updateSchema(Schema $toSchema, $noDrops = false) + { + $this->processSql($this->getUpdateSchema($toSchema, $noDrops)); + } + + /** + * Drop the given database schema from the underlying db. + * + * @param Schema $dropSchema + * @return void + */ + public function dropSchema(Schema $dropSchema) + { + $this->processSqlSafely($this->getDropSchema($dropSchema)); + } + + /** + * Drop all assets from the underyling db. + * + * @return void + */ + public function dropAllSchema() + { + $this->processSql($this->getDropAllSchema()); + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Table.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Table.php new file mode 100644 index 0000000..d0763c5 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Table.php @@ -0,0 +1,678 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Schema\Visitor\Visitor; +use Doctrine\DBAL\DBALException; + +/** + * Object Representation of a table + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class Table extends AbstractAsset +{ + /** + * @var string + */ + protected $_name = null; + + /** + * @var array + */ + protected $_columns = array(); + + /** + * @var array + */ + protected $_indexes = array(); + + /** + * @var string + */ + protected $_primaryKeyName = false; + + /** + * @var array + */ + protected $_fkConstraints = array(); + + /** + * @var array + */ + protected $_options = array(); + + /** + * @var SchemaConfig + */ + protected $_schemaConfig = null; + + /** + * + * @param string $tableName + * @param array $columns + * @param array $indexes + * @param array $fkConstraints + * @param int $idGeneratorType + * @param array $options + */ + public function __construct($tableName, array $columns=array(), array $indexes=array(), array $fkConstraints=array(), $idGeneratorType = 0, array $options=array()) + { + if (strlen($tableName) == 0) { + throw DBALException::invalidTableName($tableName); + } + + $this->_setName($tableName); + $this->_idGeneratorType = $idGeneratorType; + + foreach ($columns as $column) { + $this->_addColumn($column); + } + + foreach ($indexes as $idx) { + $this->_addIndex($idx); + } + + foreach ($fkConstraints as $constraint) { + $this->_addForeignKeyConstraint($constraint); + } + + $this->_options = $options; + } + + /** + * @param SchemaConfig $schemaConfig + */ + public function setSchemaConfig(SchemaConfig $schemaConfig) + { + $this->_schemaConfig = $schemaConfig; + } + + /** + * @return int + */ + protected function _getMaxIdentifierLength() + { + if ($this->_schemaConfig instanceof SchemaConfig) { + return $this->_schemaConfig->getMaxIdentifierLength(); + } else { + return 63; + } + } + + /** + * Set Primary Key + * + * @param array $columns + * @param string $indexName + * @return Table + */ + public function setPrimaryKey(array $columns, $indexName = false) + { + $primaryKey = $this->_createIndex($columns, $indexName ?: "primary", true, true); + + foreach ($columns as $columnName) { + $column = $this->getColumn($columnName); + $column->setNotnull(true); + } + + return $primaryKey; + } + + /** + * @param array $columnNames + * @param string $indexName + * @return Table + */ + public function addIndex(array $columnNames, $indexName = null) + { + if($indexName == null) { + $indexName = $this->_generateIdentifierName( + array_merge(array($this->getName()), $columnNames), "idx", $this->_getMaxIdentifierLength() + ); + } + + return $this->_createIndex($columnNames, $indexName, false, false); + } + + /** + * Drop an index from this table. + * + * @param string $indexName + * @return void + */ + public function dropPrimaryKey() + { + $this->dropIndex($this->_primaryKeyName); + $this->_primaryKeyName = false; + } + + /** + * Drop an index from this table. + * + * @param string $indexName + * @return void + */ + public function dropIndex($indexName) + { + $indexName = strtolower($indexName); + if ( ! $this->hasIndex($indexName)) { + throw SchemaException::indexDoesNotExist($indexName, $this->_name); + } + unset($this->_indexes[$indexName]); + } + + /** + * + * @param array $columnNames + * @param string $indexName + * @return Table + */ + public function addUniqueIndex(array $columnNames, $indexName = null) + { + if ($indexName === null) { + $indexName = $this->_generateIdentifierName( + array_merge(array($this->getName()), $columnNames), "uniq", $this->_getMaxIdentifierLength() + ); + } + + return $this->_createIndex($columnNames, $indexName, true, false); + } + + /** + * Check if an index begins in the order of the given columns. + * + * @param array $columnsNames + * @return bool + */ + public function columnsAreIndexed(array $columnsNames) + { + foreach ($this->getIndexes() as $index) { + /* @var $index Index */ + if ($index->spansColumns($columnsNames)) { + return true; + } + } + return false; + } + + /** + * + * @param array $columnNames + * @param string $indexName + * @param bool $isUnique + * @param bool $isPrimary + * @return Table + */ + private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary) + { + if (preg_match('(([^a-zA-Z0-9_]+))', $indexName)) { + throw SchemaException::indexNameInvalid($indexName); + } + + foreach ($columnNames as $columnName => $indexColOptions) { + if (is_numeric($columnName) && is_string($indexColOptions)) { + $columnName = $indexColOptions; + } + + if ( ! $this->hasColumn($columnName)) { + throw SchemaException::columnDoesNotExist($columnName, $this->_name); + } + } + $this->_addIndex(new Index($indexName, $columnNames, $isUnique, $isPrimary)); + return $this; + } + + /** + * @param string $columnName + * @param string $columnType + * @param array $options + * @return Column + */ + public function addColumn($columnName, $typeName, array $options=array()) + { + $column = new Column($columnName, Type::getType($typeName), $options); + + $this->_addColumn($column); + return $column; + } + + /** + * Rename Column + * + * @param string $oldColumnName + * @param string $newColumnName + * @return Table + */ + public function renameColumn($oldColumnName, $newColumnName) + { + throw new DBALException("Table#renameColumn() was removed, because it drops and recreates " . + "the column instead. There is no fix available, because a schema diff cannot reliably detect if a " . + "column was renamed or one column was created and another one dropped."); + } + + /** + * Change Column Details + * + * @param string $columnName + * @param array $options + * @return Table + */ + public function changeColumn($columnName, array $options) + { + $column = $this->getColumn($columnName); + $column->setOptions($options); + return $this; + } + + /** + * Drop Column from Table + * + * @param string $columnName + * @return Table + */ + public function dropColumn($columnName) + { + $columnName = strtolower($columnName); + $column = $this->getColumn($columnName); + unset($this->_columns[$columnName]); + return $this; + } + + + /** + * Add a foreign key constraint + * + * Name is inferred from the local columns + * + * @param Table $foreignTable + * @param array $localColumns + * @param array $foreignColumns + * @param array $options + * @param string $constraintName + * @return Table + */ + public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array(), $constraintName = null) + { + $constraintName = $constraintName ?: $this->_generateIdentifierName(array_merge((array)$this->getName(), $localColumnNames), "fk", $this->_getMaxIdentifierLength()); + return $this->addNamedForeignKeyConstraint($constraintName, $foreignTable, $localColumnNames, $foreignColumnNames, $options); + } + + /** + * Add a foreign key constraint + * + * Name is to be generated by the database itsself. + * + * @deprecated Use {@link addForeignKeyConstraint} + * @param Table $foreignTable + * @param array $localColumns + * @param array $foreignColumns + * @param array $options + * @return Table + */ + public function addUnnamedForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array()) + { + return $this->addForeignKeyConstraint($foreignTable, $localColumnNames, $foreignColumnNames, $options); + } + + /** + * Add a foreign key constraint with a given name + * + * @deprecated Use {@link addForeignKeyConstraint} + * @param string $name + * @param Table $foreignTable + * @param array $localColumns + * @param array $foreignColumns + * @param array $options + * @return Table + */ + public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array()) + { + if ($foreignTable instanceof Table) { + $foreignTableName = $foreignTable->getName(); + + foreach ($foreignColumnNames as $columnName) { + if ( ! $foreignTable->hasColumn($columnName)) { + throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName()); + } + } + } else { + $foreignTableName = $foreignTable; + } + + foreach ($localColumnNames as $columnName) { + if ( ! $this->hasColumn($columnName)) { + throw SchemaException::columnDoesNotExist($columnName, $this->_name); + } + } + + $constraint = new ForeignKeyConstraint( + $localColumnNames, $foreignTableName, $foreignColumnNames, $name, $options + ); + $this->_addForeignKeyConstraint($constraint); + + return $this; + } + + /** + * @param string $name + * @param string $value + * @return Table + */ + public function addOption($name, $value) + { + $this->_options[$name] = $value; + return $this; + } + + /** + * @param Column $column + */ + protected function _addColumn(Column $column) + { + $columnName = $column->getName(); + $columnName = strtolower($columnName); + + if (isset($this->_columns[$columnName])) { + throw SchemaException::columnAlreadyExists($this->getName(), $columnName); + } + + $this->_columns[$columnName] = $column; + } + + /** + * Add index to table + * + * @param Index $indexCandidate + * @return Table + */ + protected function _addIndex(Index $indexCandidate) + { + // check for duplicates + foreach ($this->_indexes as $existingIndex) { + if ($indexCandidate->isFullfilledBy($existingIndex)) { + return $this; + } + } + + $indexName = $indexCandidate->getName(); + $indexName = strtolower($indexName); + + if (isset($this->_indexes[$indexName]) || ($this->_primaryKeyName != false && $indexCandidate->isPrimary())) { + throw SchemaException::indexAlreadyExists($indexName, $this->_name); + } + + // remove overruled indexes + foreach ($this->_indexes as $idxKey => $existingIndex) { + if ($indexCandidate->overrules($existingIndex)) { + unset($this->_indexes[$idxKey]); + } + } + + if ($indexCandidate->isPrimary()) { + $this->_primaryKeyName = $indexName; + } + + $this->_indexes[$indexName] = $indexCandidate; + return $this; + } + + /** + * @param ForeignKeyConstraint $constraint + */ + protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint) + { + $constraint->setLocalTable($this); + + if(strlen($constraint->getName())) { + $name = $constraint->getName(); + } else { + $name = $this->_generateIdentifierName( + array_merge((array)$this->getName(), $constraint->getLocalColumns()), "fk", $this->_getMaxIdentifierLength() + ); + } + $name = strtolower($name); + + $this->_fkConstraints[$name] = $constraint; + // add an explicit index on the foreign key columns. If there is already an index that fullfils this requirements drop the request. + // In the case of __construct calling this method during hydration from schema-details all the explicitly added indexes + // lead to duplicates. This creates compuation overhead in this case, however no duplicate indexes are ever added (based on columns). + $this->addIndex($constraint->getColumns()); + } + + /** + * Does Table have a foreign key constraint with the given name? + * * + * @param string $constraintName + * @return bool + */ + public function hasForeignKey($constraintName) + { + $constraintName = strtolower($constraintName); + return isset($this->_fkConstraints[$constraintName]); + } + + /** + * @param string $constraintName + * @return ForeignKeyConstraint + */ + public function getForeignKey($constraintName) + { + $constraintName = strtolower($constraintName); + if(!$this->hasForeignKey($constraintName)) { + throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); + } + + return $this->_fkConstraints[$constraintName]; + } + + public function removeForeignKey($constraintName) + { + $constraintName = strtolower($constraintName); + if(!$this->hasForeignKey($constraintName)) { + throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); + } + + unset($this->_fkConstraints[$constraintName]); + } + + /** + * @return Column[] + */ + public function getColumns() + { + $columns = $this->_columns; + + $pkCols = array(); + $fkCols = array(); + + if ($this->hasPrimaryKey()) { + $pkCols = $this->getPrimaryKey()->getColumns(); + } + foreach ($this->getForeignKeys() as $fk) { + /* @var $fk ForeignKeyConstraint */ + $fkCols = array_merge($fkCols, $fk->getColumns()); + } + $colNames = array_unique(array_merge($pkCols, $fkCols, array_keys($columns))); + + uksort($columns, function($a, $b) use($colNames) { + return (array_search($a, $colNames) >= array_search($b, $colNames)); + }); + return $columns; + } + + + /** + * Does this table have a column with the given name? + * + * @param string $columnName + * @return bool + */ + public function hasColumn($columnName) + { + $columnName = $this->trimQuotes(strtolower($columnName)); + return isset($this->_columns[$columnName]); + } + + /** + * Get a column instance + * + * @param string $columnName + * @return Column + */ + public function getColumn($columnName) + { + $columnName = strtolower($this->trimQuotes($columnName)); + if ( ! $this->hasColumn($columnName)) { + throw SchemaException::columnDoesNotExist($columnName, $this->_name); + } + + return $this->_columns[$columnName]; + } + + /** + * @return Index|null + */ + public function getPrimaryKey() + { + if ( ! $this->hasPrimaryKey()) { + return null; + } + return $this->getIndex($this->_primaryKeyName); + } + + public function getPrimaryKeyColumns() + { + if ( ! $this->hasPrimaryKey()) { + throw new DBALException("Table " . $this->getName() . " has no primary key."); + } + return $this->getPrimaryKey()->getColumns(); + } + + /** + * Check if this table has a primary key. + * + * @return bool + */ + public function hasPrimaryKey() + { + return ($this->_primaryKeyName && $this->hasIndex($this->_primaryKeyName)); + } + + /** + * @param string $indexName + * @return bool + */ + public function hasIndex($indexName) + { + $indexName = strtolower($indexName); + return (isset($this->_indexes[$indexName])); + } + + /** + * @param string $indexName + * @return Index + */ + public function getIndex($indexName) + { + $indexName = strtolower($indexName); + if ( ! $this->hasIndex($indexName)) { + throw SchemaException::indexDoesNotExist($indexName, $this->_name); + } + return $this->_indexes[$indexName]; + } + + /** + * @return array + */ + public function getIndexes() + { + return $this->_indexes; + } + + /** + * Get Constraints + * + * @return array + */ + public function getForeignKeys() + { + return $this->_fkConstraints; + } + + public function hasOption($name) + { + return isset($this->_options[$name]); + } + + public function getOption($name) + { + return $this->_options[$name]; + } + + public function getOptions() + { + return $this->_options; + } + + /** + * @param Visitor $visitor + */ + public function visit(Visitor $visitor) + { + $visitor->acceptTable($this); + + foreach ($this->getColumns() as $column) { + $visitor->acceptColumn($this, $column); + } + + foreach ($this->getIndexes() as $index) { + $visitor->acceptIndex($this, $index); + } + + foreach ($this->getForeignKeys() as $constraint) { + $visitor->acceptForeignKey($this, $constraint); + } + } + + /** + * Clone of a Table triggers a deep clone of all affected assets + */ + public function __clone() + { + foreach ($this->_columns as $k => $column) { + $this->_columns[$k] = clone $column; + } + foreach ($this->_indexes as $k => $index) { + $this->_indexes[$k] = clone $index; + } + foreach ($this->_fkConstraints as $k => $fk) { + $this->_fkConstraints[$k] = clone $fk; + $this->_fkConstraints[$k]->setLocalTable($this); + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/TableDiff.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/TableDiff.php new file mode 100644 index 0000000..257a3bd --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/TableDiff.php @@ -0,0 +1,136 @@ +. + */ + +namespace Doctrine\DBAL\Schema; + +/** + * Table Diff + * + * + * @link www.doctrine-project.org + * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + * @since 2.0 + * @author Benjamin Eberlei + */ +class TableDiff +{ + /** + * @var string + */ + public $name = null; + + /** + * @var string + */ + public $newName = false; + + /** + * All added fields + * + * @var array(string=>Column) + */ + public $addedColumns; + + /** + * All changed fields + * + * @var array(string=>Column) + */ + public $changedColumns = array(); + + /** + * All removed fields + * + * @var array(string=>Column) + */ + public $removedColumns = array(); + + /** + * Columns that are only renamed from key to column instance name. + * + * @var array(string=>Column) + */ + public $renamedColumns = array(); + + /** + * All added indexes + * + * @var array(string=>Index) + */ + public $addedIndexes = array(); + + /** + * All changed indexes + * + * @var array(string=>Index) + */ + public $changedIndexes = array(); + + /** + * All removed indexes + * + * @var array(string=>bool) + */ + public $removedIndexes = array(); + + /** + * All added foreign key definitions + * + * @var array + */ + public $addedForeignKeys = array(); + + /** + * All changed foreign keys + * + * @var array + */ + public $changedForeignKeys = array(); + + /** + * All removed foreign keys + * + * @var array + */ + public $removedForeignKeys = array(); + + /** + * Constructs an TableDiff object. + * + * @param array(string=>Column) $addedColumns + * @param array(string=>Column) $changedColumns + * @param array(string=>bool) $removedColumns + * @param array(string=>Index) $addedIndexes + * @param array(string=>Index) $changedIndexes + * @param array(string=>bool) $removedIndexes + */ + public function __construct($tableName, $addedColumns = array(), + $changedColumns = array(), $removedColumns = array(), $addedIndexes = array(), + $changedIndexes = array(), $removedIndexes = array()) + { + $this->name = $tableName; + $this->addedColumns = $addedColumns; + $this->changedColumns = $changedColumns; + $this->removedColumns = $removedColumns; + $this->addedIndexes = $addedIndexes; + $this->changedIndexes = $changedIndexes; + $this->removedIndexes = $removedIndexes; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/View.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/View.php new file mode 100644 index 0000000..8283d07 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/View.php @@ -0,0 +1,53 @@ +. +*/ + +namespace Doctrine\DBAL\Schema; + +/** + * Representation of a Database View + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class View extends AbstractAsset +{ + /** + * @var string + */ + private $_sql; + + public function __construct($name, $sql) + { + $this->_setName($name); + $this->_sql = $sql; + } + + /** + * @return string + */ + public function getSql() + { + return $this->_sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/CreateSchemaSqlCollector.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/CreateSchemaSqlCollector.php new file mode 100644 index 0000000..51228c1 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/CreateSchemaSqlCollector.php @@ -0,0 +1,178 @@ +. + */ + +namespace Doctrine\DBAL\Schema\Visitor; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Schema, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\ForeignKeyConstraint, + Doctrine\DBAL\Schema\Constraint, + Doctrine\DBAL\Schema\Sequence, + Doctrine\DBAL\Schema\Index; + +class CreateSchemaSqlCollector implements Visitor +{ + /** + * @var array + */ + private $_createTableQueries = array(); + + /** + * @var array + */ + private $_createSequenceQueries = array(); + + /** + * @var array + */ + private $_createFkConstraintQueries = array(); + + /** + * + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $_platform = null; + + /** + * @param AbstractPlatform $platform + */ + public function __construct(AbstractPlatform $platform) + { + $this->_platform = $platform; + } + + /** + * @param Schema $schema + */ + public function acceptSchema(Schema $schema) + { + + } + + /** + * Generate DDL Statements to create the accepted table with all its dependencies. + * + * @param Table $table + */ + public function acceptTable(Table $table) + { + $namespace = $this->getNamespace($table); + + $this->_createTableQueries[$namespace] = array_merge( + $this->_createTableQueries[$namespace], + $this->_platform->getCreateTableSQL($table) + ); + } + + public function acceptColumn(Table $table, Column $column) + { + + } + + /** + * @param Table $localTable + * @param ForeignKeyConstraint $fkConstraint + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + $namespace = $this->getNamespace($localTable); + + if ($this->_platform->supportsForeignKeyConstraints()) { + $this->_createFkConstraintQueries[$namespace] = array_merge( + $this->_createFkConstraintQueries[$namespace], + (array) $this->_platform->getCreateForeignKeySQL( + $fkConstraint, $localTable + ) + ); + } + } + + /** + * @param Table $table + * @param Index $index + */ + public function acceptIndex(Table $table, Index $index) + { + + } + + /** + * @param Sequence $sequence + */ + public function acceptSequence(Sequence $sequence) + { + $namespace = $this->getNamespace($sequence); + + $this->_createSequenceQueries[$namespace] = array_merge( + $this->_createSequenceQueries[$namespace], + (array)$this->_platform->getCreateSequenceSQL($sequence) + ); + } + + private function getNamespace($asset) + { + $namespace = $asset->getNamespaceName() ?: 'default'; + if ( !isset($this->_createTableQueries[$namespace])) { + $this->_createTableQueries[$namespace] = array(); + $this->_createSequenceQueries[$namespace] = array(); + $this->_createFkConstraintQueries[$namespace] = array(); + } + + return $namespace; + } + + /** + * @return array + */ + public function resetQueries() + { + $this->_createTableQueries = array(); + $this->_createSequenceQueries = array(); + $this->_createFkConstraintQueries = array(); + } + + /** + * Get all queries collected so far. + * + * @return array + */ + public function getQueries() + { + $sql = array(); + foreach (array_keys($this->_createTableQueries) as $namespace) { + if ($this->_platform->supportsSchemas()) { + // TODO: Create Schema here + } + } + foreach ($this->_createTableQueries as $schemaSql) { + $sql = array_merge($sql, $schemaSql); + } + foreach ($this->_createSequenceQueries as $schemaSql) { + $sql = array_merge($sql, $schemaSql); + } + foreach ($this->_createFkConstraintQueries as $schemaSql) { + $sql = array_merge($sql, $schemaSql); + } + return $sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php new file mode 100644 index 0000000..3d74cb9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php @@ -0,0 +1,160 @@ +. + */ + +namespace Doctrine\DBAL\Schema\Visitor; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Schema, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\ForeignKeyConstraint, + Doctrine\DBAL\Schema\Constraint, + Doctrine\DBAL\Schema\Sequence, + Doctrine\DBAL\Schema\SchemaException, + Doctrine\DBAL\Schema\Index; + +/** + * Gather SQL statements that allow to completly drop the current schema. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + */ +class DropSchemaSqlCollector implements Visitor +{ + /** + * @var \SplObjectStorage + */ + private $constraints; + + /** + * @var \SplObjectStorage + */ + private $sequences; + + /** + * @var \SplObjectStorage + */ + private $tables; + + /** + * + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $platform; + + /** + * @param AbstractPlatform $platform + */ + public function __construct(AbstractPlatform $platform) + { + $this->platform = $platform; + $this->clearQueries(); + } + + /** + * @param Schema $schema + */ + public function acceptSchema(Schema $schema) + { + + } + + /** + * @param Table $table + */ + public function acceptTable(Table $table) + { + $this->tables->attach($table); + } + + /** + * @param Column $column + */ + public function acceptColumn(Table $table, Column $column) + { + + } + + /** + * @param Table $localTable + * @param ForeignKeyConstraint $fkConstraint + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + if (strlen($fkConstraint->getName()) == 0) { + throw SchemaException::namedForeignKeyRequired($localTable, $fkConstraint); + } + + $this->constraints->attach($fkConstraint); + $this->constraints[$fkConstraint] = $localTable; + } + + /** + * @param Table $table + * @param Index $index + */ + public function acceptIndex(Table $table, Index $index) + { + + } + + /** + * @param Sequence $sequence + */ + public function acceptSequence(Sequence $sequence) + { + $this->sequences->attach($sequence); + } + + /** + * @return void + */ + public function clearQueries() + { + $this->constraints = new \SplObjectStorage(); + $this->sequences = new \SplObjectStorage(); + $this->tables = new \SplObjectStorage(); + } + + /** + * @return array + */ + public function getQueries() + { + $sql = array(); + foreach ($this->constraints as $fkConstraint) { + $localTable = $this->constraints[$fkConstraint]; + $sql[] = $this->platform->getDropForeignKeySQL($fkConstraint, $localTable); + } + + foreach ($this->sequences as $sequence) { + $sql[] = $this->platform->getDropSequenceSQL($sequence); + } + + foreach ($this->tables as $table) { + $sql[] = $this->platform->getDropTableSQL($table); + } + + return $sql; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php new file mode 100644 index 0000000..8ae69a2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php @@ -0,0 +1,151 @@ +. + */ + +namespace Doctrine\DBAL\Schema\Visitor; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Schema, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\ForeignKeyConstraint, + Doctrine\DBAL\Schema\Constraint, + Doctrine\DBAL\Schema\Sequence, + Doctrine\DBAL\Schema\Index; + +class Graphviz implements \Doctrine\DBAL\Schema\Visitor\Visitor +{ + private $output = ''; + + public function acceptColumn(Table $table, Column $column) + { + + } + + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + $this->output .= $this->createNodeRelation( + $fkConstraint->getLocalTableName() . ":col" . current($fkConstraint->getLocalColumns()).":se", + $fkConstraint->getForeignTableName() . ":col" . current($fkConstraint->getForeignColumns()).":se", + array( + 'dir' => 'back', + 'arrowtail' => 'dot', + 'arrowhead' => 'normal', + ) + ); + } + + public function acceptIndex(Table $table, Index $index) + { + + } + + public function acceptSchema(Schema $schema) + { + $this->output = 'digraph "' . sha1( mt_rand() ) . '" {' . "\n"; + $this->output .= 'splines = true;' . "\n"; + $this->output .= 'overlap = false;' . "\n"; + $this->output .= 'outputorder=edgesfirst;'."\n"; + $this->output .= 'mindist = 0.6;' . "\n"; + $this->output .= 'sep = .2;' . "\n"; + } + + public function acceptSequence(Sequence $sequence) + { + + } + + public function acceptTable(Table $table) + { + $this->output .= $this->createNode( + $table->getName(), + array( + 'label' => $this->createTableLabel( $table ), + 'shape' => 'plaintext', + ) + ); + } + + private function createTableLabel( Table $table ) + { + // Start the table + $label = '<'; + + // The title + $label .= ''; + + // The attributes block + foreach( $table->getColumns() as $column ) { + $columnLabel = $column->getName(); + + $label .= ''; + $label .= ''; + $label .= ''; + } + + // End the table + $label .= '
' . $table->getName() . '
'; + $label .= '' . $columnLabel . ''; + $label .= '' . strtolower($column->getType()) . ''; + if ($table->hasPrimaryKey() && in_array($column->getName(), $table->getPrimaryKey()->getColumns())) { + $label .= "\xe2\x9c\xb7"; + } + $label .= '
>'; + + return $label; + } + + private function createNode( $name, $options ) + { + $node = $name . " ["; + foreach( $options as $key => $value ) + { + $node .= $key . '=' . $value . ' '; + } + $node .= "]\n"; + return $node; + } + + private function createNodeRelation( $node1, $node2, $options ) + { + $relation = $node1 . ' -> ' . $node2 . ' ['; + foreach( $options as $key => $value ) + { + $relation .= $key . '=' . $value . ' '; + } + $relation .= "]\n"; + return $relation; + } + + /** + * Write dot language output to a file. This should usually be a *.dot file. + * + * You have to convert the output into a viewable format. For example use "neato" on linux systems + * and execute: + * + * neato -Tpng -o er.png er.dot + * + * @param string $filename + * @return void + */ + public function write($filename) + { + file_put_contents($filename, $this->output . "}"); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/RemoveNamespacedAssets.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/RemoveNamespacedAssets.php new file mode 100644 index 0000000..348b2b7 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/RemoveNamespacedAssets.php @@ -0,0 +1,113 @@ +. + */ + +namespace Doctrine\DBAL\Schema\Visitor; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Schema, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\ForeignKeyConstraint, + Doctrine\DBAL\Schema\Constraint, + Doctrine\DBAL\Schema\Sequence, + Doctrine\DBAL\Schema\Index; + +/** + * Remove assets from a schema that are not in the default namespace. + * + * Some databases such as MySQL support cross databases joins, but don't + * allow to call DDLs to a database from another connected database. + * Before a schema is serialized into SQL this visitor can cleanup schemas with + * non default namespaces. + * + * This visitor filters all these non-default namespaced tables and sequences + * and removes them from the SChema instance. + * + * @author Benjamin Eberlei + * @since 2.2 + */ +class RemoveNamespacedAssets implements Visitor +{ + /** + * @var Schema + */ + private $schema; + + /** + * @param Schema $schema + */ + public function acceptSchema(Schema $schema) + { + $this->schema = $schema; + } + + /** + * @param Table $table + */ + public function acceptTable(Table $table) + { + if ( ! $table->isInDefaultNamespace($this->schema->getName()) ) { + $this->schema->dropTable($table->getName()); + } + } + /** + * @param Sequence $sequence + */ + public function acceptSequence(Sequence $sequence) + { + if ( ! $sequence->isInDefaultNamespace($this->schema->getName()) ) { + $this->schema->dropSequence($sequence->getName()); + } + } + + /** + * @param Column $column + */ + public function acceptColumn(Table $table, Column $column) + { + } + + /** + * @param Table $localTable + * @param ForeignKeyConstraint $fkConstraint + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + // The table may already be deleted in a previous + // RemoveNamespacedAssets#acceptTable call. Removing Foreign keys that + // point to nowhere. + if ( ! $this->schema->hasTable($fkConstraint->getForeignTableName())) { + $localTable->removeForeignKey($fkConstraint->getName()); + return; + } + + $foreignTable = $this->schema->getTable($fkConstraint->getForeignTableName()); + if ( ! $foreignTable->isInDefaultNamespace($this->schema->getName()) ) { + $localTable->removeForeignKey($fkConstraint->getName()); + } + } + + /** + * @param Table $table + * @param Index $index + */ + public function acceptIndex(Table $table, Index $index) + { + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Visitor.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Visitor.php new file mode 100644 index 0000000..45eff81 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Schema/Visitor/Visitor.php @@ -0,0 +1,75 @@ +. + */ + +namespace Doctrine\DBAL\Schema\Visitor; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Schema, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\ForeignKeyConstraint, + Doctrine\DBAL\Schema\Constraint, + Doctrine\DBAL\Schema\Sequence, + Doctrine\DBAL\Schema\Index; + +/** + * Schema Visitor used for Validation or Generation purposes. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +interface Visitor +{ + /** + * @param Schema $schema + */ + public function acceptSchema(Schema $schema); + + /** + * @param Table $table + */ + public function acceptTable(Table $table); + + /** + * @param Column $column + */ + public function acceptColumn(Table $table, Column $column); + + /** + * @param Table $localTable + * @param ForeignKeyConstraint $fkConstraint + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint); + + /** + * @param Table $table + * @param Index $index + */ + public function acceptIndex(Table $table, Index $index); + + /** + * @param Sequence $sequence + */ + public function acceptSequence(Sequence $sequence); +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php new file mode 100644 index 0000000..6453e63 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardConnection.php @@ -0,0 +1,201 @@ +. + */ + +namespace Doctrine\DBAL\Sharding; + +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Event\ConnectionEventArgs; +use Doctrine\DBAL\Events; +use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Configuration; + +use Doctrine\Common\EventManager; + +use Doctrine\DBAL\Sharding\ShardChoser\ShardChoser; + +/** + * Sharding implementation that pools many different connections + * internally and serves data from the currently active connection. + * + * The internals of this class are: + * + * - All sharding clients are specified and given a shard-id during + * configuration. + * - By default, the global shard is selected. If no global shard is configured + * an exception is thrown on access. + * - Selecting a shard by distribution value delegates the mapping + * "distributionValue" => "client" to the ShardChooser interface. + * - An exception is thrown if trying to switch shards during an open + * transaction. + * + * Instantiation through the DriverManager looks like: + * + * @example + * + * $conn = DriverManager::getConnection(array( + * 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + * 'driver' => 'pdo_mysql', + * 'global' => array('user' => '', 'password' => '', 'host' => '', 'dbname' => ''), + * 'shards' => array( + * array('id' => 1, 'user' => 'slave1', 'password', 'host' => '', 'dbname' => ''), + * array('id' => 2, 'user' => 'slave2', 'password', 'host' => '', 'dbname' => ''), + * ), + * 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', + * )); + * $shardManager = $conn->getShardManager(); + * $shardManager->selectGlobal(); + * $shardManager->selectShard($value); + * + * @author Benjamin Eberlei + */ +class PoolingShardConnection extends Connection +{ + /** + * @var array + */ + private $activeConnections; + + /** + * @var int + */ + private $activeShardId; + + /** + * @var array + */ + private $connections; + + /** + * @var ShardManager + */ + private $shardManager; + + public function __construct(array $params, Driver $driver, Configuration $config = null, EventManager $eventManager = null) + { + if ( !isset($params['global']) || !isset($params['shards'])) { + throw new \InvalidArgumentException("Connection Parameters require 'global' and 'shards' configurations."); + } + + if ( !isset($params['shardChoser'])) { + throw new \InvalidArgumentException("Missing Shard Choser configuration 'shardChoser'"); + } + + if (is_string($params['shardChoser'])) { + $params['shardChoser'] = new $params['shardChoser']; + } + + if ( ! ($params['shardChoser'] instanceof ShardChoser)) { + throw new \InvalidArgumentException("The 'shardChoser' configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser"); + } + + $this->connections[0] = array_merge($params, $params['global']); + + foreach ($params['shards'] as $shard) { + if ( ! isset($shard['id'])) { + throw new \InvalidArgumentException("Missing 'id' for one configured shard. Please specificy a unique shard-id."); + } + + if ( !is_numeric($shard['id']) || $shard['id'] < 1) { + throw new \InvalidArgumentException("Shard Id has to be a non-negative number."); + } + + if (isset($this->connections[$shard['id']])) { + throw new \InvalidArgumentException("Shard " . $shard['id'] . " is duplicated in the configuration."); + } + + $this->connections[$shard['id']] = array_merge($params, $shard); + } + + parent::__construct($params, $driver, $config, $eventManager); + } + + /** + * Connect to a given shard + * + * @param mixed $shardId + * @return bool + */ + public function connect($shardId = null) + { + if ($shardId === null && $this->_conn) { + return false; + } + + if ($shardId !== null && $shardId === $this->activeShardId) { + return false; + } + + if ($this->getTransactionNestingLevel() > 0) { + throw new ShardingException("Cannot switch shard when transaction is active."); + } + + $this->activeShardId = (int)$shardId; + + if (isset($this->activeConnections[$this->activeShardId])) { + $this->_conn = $this->activeConnections[$this->activeShardId]; + return false; + } + + $this->_conn = $this->activeConnections[$this->activeShardId] = $this->connectTo($this->activeShardId); + + if ($this->_eventManager->hasListeners(Events::postConnect)) { + $eventArgs = new Event\ConnectionEventArgs($this); + $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); + } + + return true; + } + + + /** + * Connect to a specific connection + * + * @param string $shardId + * @return Driver + */ + protected function connectTo($shardId) + { + $params = $this->getParams(); + + $driverOptions = isset($params['driverOptions']) ? $params['driverOptions'] : array(); + + $connectionParams = $this->connections[$shardId]; + + $user = isset($connectionParams['user']) ? $connectionParams['user'] : null; + $password = isset($connectionParams['password']) ? $connectionParams['password'] : null; + + return $this->_driver->connect($connectionParams, $user, $password, $driverOptions); + } + + public function isConnected($shardId = null) + { + if ($shardId === null) { + return $this->_conn !== null; + } + + return isset($this->activeConnections[$shardId]); + } + + public function close() + { + $this->_conn = null; + $this->activeConnections = null; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php new file mode 100644 index 0000000..6f6c5d2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php @@ -0,0 +1,98 @@ +. + */ + +namespace Doctrine\DBAL\Sharding; + +use Doctrine\DBAL\Sharding\ShardChoser\ShardChoser; + +/** + * Shard Manager for the Connection Pooling Shard Strategy + * + * @author Benjamin Eberlei + */ +class PoolingShardManager implements ShardManager +{ + private $conn; + private $choser; + private $currentDistributionValue; + + public function __construct(PoolingShardConnection $conn) + { + $params = $conn->getParams(); + $this->conn = $conn; + $this->choser = $params['shardChoser']; + } + + public function selectGlobal() + { + $this->conn->connect(0); + $this->currentDistributionValue = null; + } + + public function selectShard($distributionValue) + { + $shardId = $this->choser->pickShard($distributionValue, $this->conn); + $this->conn->connect($shardId); + $this->currentDistributionValue = $distributionValue; + } + + public function getCurrentDistributionValue() + { + return $this->currentDistributionValue; + } + + public function getShards() + { + $params = $this->conn->getParams(); + $shards = array(); + + foreach ($params['shards'] as $shard) { + $shards[] = array('id' => $shard['id']); + } + + return $shards; + } + + public function queryAll($sql, array $params, array $types) + { + $shards = $this->getShards(); + if (!$shards) { + throw new \RuntimeException("No shards found."); + } + + $result = array(); + $oldDistribution = $this->getCurrentDistributionValue(); + + foreach ($shards as $shard) { + $this->selectShard($shard['id']); + foreach ($this->conn->fetchAll($sql, $params, $types) as $row) { + $result[] = $row; + } + } + + if ($oldDistribution === null) { + $this->selectGlobal(); + } else { + $this->selectShard($oldDistribution); + } + + return $result; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php new file mode 100644 index 0000000..4001379 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php @@ -0,0 +1,296 @@ +. + */ + +namespace Doctrine\DBAL\Sharding\SQLAzure; + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Types\Type; + +use Doctrine\DBAL\Schema\Synchronizer\AbstractSchemaSynchronizer; +use Doctrine\DBAL\Sharding\SingleDatabaseSynchronizer; + +/** + * SQL Azure Schema Synchronizer + * + * Will iterate over all shards when performing schema operations. This is done + * by partitioning the passed schema into subschemas for the federation and the + * global database and then applying the operations step by step using the + * {@see \Doctrine\DBAL\Sharding\SingleDatabaseSynchronizer}. + * + * @author Benjamin Eberlei + */ +class SQLAzureFederationsSynchronizer extends AbstractSchemaSynchronizer +{ + const FEDERATION_TABLE_FEDERATED = 'azure.federated'; + const FEDERATION_DISTRIBUTION_NAME = 'azure.federatedOnDistributionName'; + + + /** + * @var SQLAzureShardManager + */ + private $shardManager; + + /** + * @var SchemaSynchronizer + */ + private $synchronizer; + + public function __construct(Connection $conn, SQLAzureShardManager $shardManager, SchemaSynchronizer $sync = null) + { + parent::__construct($conn); + $this->shardManager = $shardManager; + $this->synchronizer = $sync ?: new SingleDatabaseSynchronizer($conn); + } + + /** + * Get the SQL statements that can be executed to create the schema. + * + * @param Schema $createSchema + * @return array + */ + public function getCreateSchema(Schema $createSchema) + { + $sql = array(); + + list($global, $federation) = $this->partitionSchema($createSchema); + + $globalSql = $this->synchronizer->getCreateSchema($global); + if ($globalSql) { + $sql[] = "-- Create Root Federation\n" . + "USE FEDERATION ROOT WITH RESET;"; + $sql = array_merge($sql, $globalSql); + } + + $federationSql = $this->synchronizer->getCreateSchema($federation); + + if ($federationSql) { + $defaultValue = $this->getFederationTypeDefaultValue(); + + $sql[] = $this->getCreateFederationStatement(); + $sql[] = "USE FEDERATION " . $this->shardManager->getFederationName() . " (" . $this->shardManager->getDistributionKey() . " = " . $defaultValue . ") WITH RESET, FILTERING = OFF;"; + $sql = array_merge($sql, $federationSql); + } + + return $sql; + } + + /** + * Get the SQL Statements to update given schema with the underlying db. + * + * @param Schema $toSchema + * @param bool $noDrops + * @return array + */ + public function getUpdateSchema(Schema $toSchema, $noDrops = false) + { + return $this->work($toSchema, function($synchronizer, $schema) use ($noDrops) { + return $synchronizer->getUpdateSchema($schema, $noDrops); + }); + } + + /** + * Get the SQL Statements to drop the given schema from underlying db. + * + * @param Schema $dropSchema + * @return array + */ + public function getDropSchema(Schema $dropSchema) + { + return $this->work($dropSchema, function($synchronizer, $schema) { + return $synchronizer->getDropSchema($schema); + }); + } + + /** + * Create the Schema + * + * @param Schema $createSchema + * @return void + */ + public function createSchema(Schema $createSchema) + { + $this->processSql($this->getCreateSchema($createSchema)); + } + + /** + * Update the Schema to new schema version. + * + * @param Schema $toSchema + * @return void + */ + public function updateSchema(Schema $toSchema, $noDrops = false) + { + $this->processSql($this->getUpdateSchema($toSchema, $noDrops)); + } + + /** + * Drop the given database schema from the underlying db. + * + * @param Schema $dropSchema + * @return void + */ + public function dropSchema(Schema $dropSchema) + { + $this->processSqlSafely($this->getDropSchema($dropSchema)); + } + + /** + * Get the SQL statements to drop all schema assets from underlying db. + * + * @return array + */ + public function getDropAllSchema() + { + $this->shardManager->selectGlobal(); + $globalSql = $this->synchronizer->getDropAllSchema(); + + if ($globalSql) { + $sql[] = "-- Work on Root Federation\nUSE FEDERATION ROOT WITH RESET;"; + $sql = array_merge($sql, $globalSql); + } + + $shards = $this->shardManager->getShards(); + foreach ($shards as $shard) { + $this->shardManager->selectShard($shard['rangeLow']); + + $federationSql = $this->synchronizer->getDropAllSchema(); + if ($federationSql) { + $sql[] = "-- Work on Federation ID " . $shard['id'] . "\n" . + "USE FEDERATION " . $this->shardManager->getFederationName() . " (" . $this->shardManager->getDistributionKey() . " = " . $shard['rangeLow'].") WITH RESET, FILTERING = OFF;"; + $sql = array_merge($sql, $federationSql); + } + } + + $sql[] = "USE FEDERATION ROOT WITH RESET;"; + $sql[] = "DROP FEDERATION " . $this->shardManager->getFederationName(); + + return $sql; + } + + /** + * Drop all assets from the underyling db. + * + * @return void + */ + public function dropAllSchema() + { + $this->processSqlSafely($this->getDropAllSchema()); + } + + private function partitionSchema(Schema $schema) + { + return array( + $this->extractSchemaFederation($schema, false), + $this->extractSchemaFederation($schema, true), + ); + } + + private function extractSchemaFederation(Schema $schema, $isFederation) + { + $partionedSchema = clone $schema; + + foreach ($partionedSchema->getTables() as $table) { + if ($isFederation) { + $table->addOption(self::FEDERATION_DISTRIBUTION_NAME, $this->shardManager->getDistributionKey()); + } + + if ( $table->hasOption(self::FEDERATION_TABLE_FEDERATED) !== $isFederation) { + $partionedSchema->dropTable($table->getName()); + } else { + foreach ($table->getForeignKeys() as $fk) { + $foreignTable = $schema->getTable($fk->getForeignTableName()); + if ($foreignTable->hasOption(self::FEDERATION_TABLE_FEDERATED) !== $isFederation) { + throw new \RuntimeException("Cannot have foreign key between global/federation."); + } + } + } + } + + return $partionedSchema; + } + + /** + * Work on the Global/Federation based on currently existing shards and + * perform the given operation on the underyling schema synchronizer given + * the different partioned schema instances. + * + * @param Schema $schema + * @param Closure $operation + * @return array + */ + private function work(Schema $schema, \Closure $operation) + { + list($global, $federation) = $this->partitionSchema($schema); + $sql = array(); + + $this->shardManager->selectGlobal(); + $globalSql = $operation($this->synchronizer, $global); + + if ($globalSql) { + $sql[] = "-- Work on Root Federation\nUSE FEDERATION ROOT WITH RESET;"; + $sql = array_merge($sql, $globalSql); + } + + $shards = $this->shardManager->getShards(); + + foreach ($shards as $shard) { + $this->shardManager->selectShard($shard['rangeLow']); + + $federationSql = $operation($this->synchronizer, $federation); + if ($federationSql) { + $sql[] = "-- Work on Federation ID " . $shard['id'] . "\n" . + "USE FEDERATION " . $this->shardManager->getFederationName() . " (" . $this->shardManager->getDistributionKey() . " = " . $shard['rangeLow'].") WITH RESET, FILTERING = OFF;"; + $sql = array_merge($sql, $federationSql); + } + } + + return $sql; + } + + private function getFederationTypeDefaultValue() + { + $federationType = Type::getType($this->shardManager->getDistributionType()); + + switch ($federationType->getName()) { + case Type::GUID: + $defaultValue = '00000000-0000-0000-0000-000000000000'; + break; + case Type::INTEGER: + case Type::SMALLINT: + case Type::BIGINT: + $defaultValue = '0'; + break; + default: + $defaultValue = ''; + break; + } + return $defaultValue; + } + + private function getCreateFederationStatement() + { + $federationType = Type::getType($this->shardManager->getDistributionType()); + $federationTypeSql = $federationType->getSqlDeclaration(array(), $this->conn->getDatabasePlatform()); + + return "--Create Federation\n" . + "CREATE FEDERATION " . $this->shardManager->getFederationName() . " (" . $this->shardManager->getDistributionKey() . " " . $federationTypeSql ." RANGE)"; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php new file mode 100644 index 0000000..80ca3d9 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php @@ -0,0 +1,238 @@ +. + */ + +namespace Doctrine\DBAL\Sharding\SQLAzure; + +use Doctrine\DBAL\Sharding\ShardManager; +use Doctrine\DBAL\Sharding\ShardingException; +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Types\Type; + +/** + * Sharding using the SQL Azure Federations support. + * + * @author Benjamin Eberlei + */ +class SQLAzureShardManager implements ShardManager +{ + /** + * @var string + */ + private $federationName; + + /** + * @var bool + */ + private $filteringEnabled; + + /** + * @var string + */ + private $distributionKey; + + /** + * @var string + */ + private $distributionType; + + /** + * @var Connection + */ + private $conn; + + /** + * @var string + */ + private $currentDistributionValue; + + /** + * @param Connection $conn + */ + public function __construct(Connection $conn) + { + $this->conn = $conn; + $params = $conn->getParams(); + + if ( ! isset($params['sharding']['federationName'])) { + throw ShardingException::missingDefaultFederationName(); + } + + if ( ! isset($params['sharding']['distributionKey'])) { + throw ShardingException::missingDefaultDistributionKey(); + } + + if ( ! isset($params['sharding']['distributionType'])) { + throw ShardingException::missingDistributionType(); + } + + $this->federationName = $params['sharding']['federationName']; + $this->distributionKey = $params['sharding']['distributionKey']; + $this->distributionType = $params['sharding']['distributionType']; + $this->filteringEnabled = (isset($params['sharding']['filteringEnabled'])) ? (bool)$params['sharding']['filteringEnabled'] : false; + } + + /** + * Get name of the federation + * + * @return string + */ + public function getFederationName() + { + return $this->federationName; + } + + /** + * Get the distribution key + * + * @return string + */ + public function getDistributionKey() + { + return $this->distributionKey; + } + + /** + * Get the Doctrine Type name used for the distribution + * + * @return string + */ + public function getDistributionType() + { + return $this->distributionType; + } + + /** + * Enabled/Disable filtering on the fly. + * + * @param bool $flag + * @return void + */ + public function setFilteringEnabled($flag) + { + $this->filteringEnabled = (bool)$flag; + } + + /** + * {@inheritDoc} + */ + public function selectGlobal() + { + if ($this->conn->isTransactionActive()) { + throw ShardingException::activeTransaction(); + } + + $sql = "USE FEDERATION ROOT WITH RESET"; + $this->conn->exec($sql); + $this->currentDistributionValue = null; + } + + /** + * {@inheritDoc} + */ + public function selectShard($distributionValue) + { + if ($this->conn->isTransactionActive()) { + throw ShardingException::activeTransaction(); + } + + if ($distributionValue === null || is_bool($distributionValue) || !is_scalar($distributionValue)) { + throw ShardingException::noShardDistributionValue(); + } + + $platform = $this->conn->getDatabasePlatform(); + $sql = sprintf( + "USE FEDERATION %s (%s = %s) WITH RESET, FILTERING = %s;", + $platform->quoteIdentifier($this->federationName), + $platform->quoteIdentifier($this->distributionKey), + $this->conn->quote($distributionValue), + ($this->filteringEnabled ? 'ON' : 'OFF') + ); + + $this->conn->exec($sql); + $this->currentDistributionValue = $distributionValue; + } + + /** + * {@inheritDoc} + */ + public function getCurrentDistributionValue() + { + return $this->currentDistributionValue; + } + + /** + * {@inheritDoc} + */ + public function getShards() + { + $sql = "SELECT member_id as id, + distribution_name as distribution_key, + CAST(range_low AS CHAR) AS rangeLow, + CAST(range_high AS CHAR) AS rangeHigh + FROM sys.federation_member_distributions d + INNER JOIN sys.federations f ON f.federation_id = d.federation_id + WHERE f.name = " . $this->conn->quote($this->federationName); + return $this->conn->fetchAll($sql); + } + + /** + * {@inheritDoc} + */ + public function queryAll($sql, array $params = array(), array $types = array()) + { + $shards = $this->getShards(); + if (!$shards) { + throw new \RuntimeException("No shards found for " . $this->federationName); + } + + $result = array(); + $oldDistribution = $this->getCurrentDistributionValue(); + + foreach ($shards as $shard) { + $this->selectShard($shard['rangeLow']); + foreach ($this->conn->fetchAll($sql, $params, $types) as $row) { + $result[] = $row; + } + } + + if ($oldDistribution === null) { + $this->selectGlobal(); + } else { + $this->selectShard($oldDistribution); + } + + return $result; + } + + /** + * Split Federation at a given distribution value. + * + * @param mixed $splitDistributionValue + */ + public function splitFederation($splitDistributionValue) + { + $type = Type::getType($this->distributionType); + + $sql = "ALTER FEDERATION " . $this->getFederationName() . " " . + "SPLIT AT (" . $this->getDistributionKey() . " = " . + $this->conn->quote($splitDistributionValue, $type->getBindingType()) . ")"; + $this->conn->exec($sql); + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php new file mode 100644 index 0000000..2b2b457 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php @@ -0,0 +1,161 @@ +. + */ + +namespace Doctrine\DBAL\Sharding\SQLAzure\Schema; + +use Doctrine\DBAL\Schema\Visitor\Visitor, + Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Schema, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\ForeignKeyConstraint, + Doctrine\DBAL\Schema\Constraint, + Doctrine\DBAL\Schema\Sequence, + Doctrine\DBAL\Schema\Index; + +/** + * Converts a single tenant schema into a multi-tenant schema for SQL Azure + * Federations under the following assumptions: + * + * - Every table is part of the multi-tenant application, only explicitly + * excluded tables are non-federated. The behavior of the tables being in + * global or federated database is undefined. It depends on you selecting a + * federation before DDL statements or not. + * - Every Primary key of a federated table is extended by another column + * 'tenant_id' with a default value of the SQLAzure function + * `federation_filtering_value('tenant_id')`. + * - You always have to work with `filtering=On` when using federations with this + * multi-tenant approach. + * - Primary keys are either using globally unique ids (GUID, Table Generator) + * or you explicitly add the tenent_id in every UPDATE or DELETE statement + * (otherwise they will affect the same-id rows from other tenents as well). + * SQLAzure throws errors when you try to create IDENTIY columns on federated + * tables. + * + * @author Benjamin Eberlei + */ +class MultiTenantVisitor implements Visitor +{ + /** + * @var array + */ + private $excludedTables = array(); + + /** + * @var string + */ + private $tenantColumnName; + + /** + * @var string + */ + private $tenantColumnType = 'integer'; + + /** + * Name of the federation distribution, defaulting to the tenantColumnName + * if not specified. + * + * @var string + */ + private $distributionName; + + public function __construct(array $excludedTables = array(), $tenantColumnName = 'tenant_id', $distributionName = null) + { + $this->excludedTables = $excludedTables; + $this->tenantColumnName = $tenantColumnName; + $this->distributionName = $distributionName ?: $tenantColumnName; + } + + /** + * @param Table $table + */ + public function acceptTable(Table $table) + { + if (in_array($table->getName(), $this->excludedTables)) { + return; + } + + $table->addColumn($this->tenantColumnName, $this->tenantColumnType, array( + 'default' => "federation_filtering_value('". $this->distributionName ."')", + )); + + $clusteredIndex = $this->getClusteredIndex($table); + + $indexColumns = $clusteredIndex->getColumns(); + $indexColumns[] = $this->tenantColumnName; + + if ($clusteredIndex->isPrimary()) { + $table->dropPrimaryKey(); + $table->setPrimaryKey($indexColumns); + } else { + $table->dropIndex($clusteredIndex->getName()); + $table->addIndex($indexColumns, $clusteredIndex->getName()); + $table->getIndex($clusteredIndex->getName())->addFlag('clustered'); + } + } + + private function getClusteredIndex($table) + { + foreach ($table->getIndexes() as $index) { + if ($index->isPrimary() && ! $index->hasFlag('nonclustered')) { + return $index; + } else if ($index->hasFlag('clustered')) { + return $index; + } + } + throw new \RuntimeException("No clustered index found on table " . $table->getName()); + } + + /** + * @param Schema $schema + */ + public function acceptSchema(Schema $schema) + { + } + + /** + * @param Column $column + */ + public function acceptColumn(Table $table, Column $column) + { + } + + /** + * @param Table $localTable + * @param ForeignKeyConstraint $fkConstraint + */ + public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) + { + } + + /** + * @param Table $table + * @param Index $index + */ + public function acceptIndex(Table $table, Index $index) + { + } + + /** + * @param Sequence $sequence + */ + public function acceptSequence(Sequence $sequence) + { + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php new file mode 100644 index 0000000..c6cdabf --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php @@ -0,0 +1,37 @@ +. + */ + +namespace Doctrine\DBAL\Sharding\ShardChoser; + +use Doctrine\DBAL\Sharding\PoolingShardConnection; + +/** + * The MultiTenant Shard choser assumes that the distribution value directly + * maps to the shard id. + * + * @author Benjamin Eberlei + */ +class MultiTenantShardChoser implements ShardChoser +{ + public function pickShard($distributionValue, PoolingShardConnection $conn) + { + return $distributionValue; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/ShardChoser.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/ShardChoser.php new file mode 100644 index 0000000..2aa9f74 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardChoser/ShardChoser.php @@ -0,0 +1,41 @@ +. + */ + +namespace Doctrine\DBAL\Sharding\ShardChoser; + +use Doctrine\DBAL\Sharding\PoolingShardConnection; + +/** + * Given a distribution value this shard-choser strategy will pick the shard to + * connect to for retrieving rows with the distribution value. + * + * @author Benjamin Eberlei + */ +interface ShardChoser +{ + /** + * Pick a shard for the given distribution value + * + * @param string $distributionValue + * @param PoolingShardConnection $conn + * @return int + */ + function pickShard($distributionValue, PoolingShardConnection $conn); +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardManager.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardManager.php new file mode 100644 index 0000000..aa67992 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardManager.php @@ -0,0 +1,95 @@ +. + */ + +namespace Doctrine\DBAL\Sharding; + +use Doctrine\DBAL\Connection; + +/** + * Sharding Manager gives access to APIs to implementing sharding on top of + * Doctrine\DBAL\Connection instances. + * + * For simplicity and developer ease-of-use (and understanding) the sharding + * API only covers single shard queries, no fan-out support. It is primarily + * suited for multi-tenant applications. + * + * The assumption about sharding here + * is that a distribution value can be found that gives access to all the + * necessary data for all use-cases. Switching between shards should be done with + * caution, especially if lazy loading is implemented. Any query is always + * executed against the last shard that was selected. If a query is created for + * a shard Y but then a shard X is selected when its actually excecuted you + * will hit the wrong shard. + * + * @author Benjamin Eberlei + */ +interface ShardManager +{ + /** + * Select global database with global data. + * + * This is the default database that is connected when no shard is + * selected. + * + * @return void + */ + function selectGlobal(); + + /** + * SELECT queries after this statement will be issued against the selected + * shard. + * + * @throws ShardingException If no value is passed as shard identifier. + * @param mixed $distributionValue + * @param array $options + * @return void + */ + function selectShard($distributionValue); + + /** + * Get the distribution value currently used for sharding. + * + * @return string + */ + function getCurrentDistributionValue(); + + /** + * Get information about the amount of shards and other details. + * + * Format is implementation specific, each shard is one element and has a + * 'name' attribute at least. + * + * @return array + */ + function getShards(); + + /** + * Query all shards in undefined order and return the results appended to + * each other. Restore the previous distribution value after execution. + * + * Using {@link Connection::fetchAll} to retrieve rows internally. + * + * @param string $sql + * @param array $params + * @param array $types + * @return array + */ + function queryAll($sql, array $params, array $types); +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardingException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardingException.php new file mode 100644 index 0000000..06dd169 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Sharding/ShardingException.php @@ -0,0 +1,61 @@ +. + */ + +namespace Doctrine\DBAL\Sharding; + +use Doctrine\DBAL\DBALException; + +/** + * Sharding related Exceptions + * + * @since 2.3 + */ +class ShardingException extends DBALException +{ + static public function notImplemented() + { + return new self("This functionality is not implemented with this sharding provider.", 1331557937); + } + + static public function missingDefaultFederationName() + { + return new self("SQLAzure requires a federation name to be set during sharding configuration.", 1332141280); + } + + static public function missingDefaultDistributionKey() + { + return new self("SQLAzure requires a distribution key to be set during sharding configuration.", 1332141329); + } + + static public function activeTransaction() + { + return new self("Cannot switch shard during an active transaction.", 1332141766); + } + + static public function noShardDistributionValue() + { + return new self("You have to specify a string or integer as shard distribution value.", 1332142103); + } + + static public function missingDistributionType() + { + return new self("You have to specify a sharding distribution type such as 'integer', 'string', 'guid'."); + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php new file mode 100644 index 0000000..1bf9d74 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Statement.php @@ -0,0 +1,264 @@ +. + */ + +namespace Doctrine\DBAL; + +use PDO, + Doctrine\DBAL\Types\Type, + Doctrine\DBAL\Driver\Statement as DriverStatement; + +/** + * A thin wrapper around a Doctrine\DBAL\Driver\Statement that adds support + * for logging, DBAL mapping types, etc. + * + * @author Roman Borschel + * @since 2.0 + */ +class Statement implements \IteratorAggregate, DriverStatement +{ + /** + * @var string The SQL statement. + */ + protected $sql; + /** + * @var array The bound parameters. + */ + protected $params = array(); + /** + * @var array The parameter types + */ + protected $types = array(); + /** + * @var \Doctrine\DBAL\Driver\Statement The underlying driver statement. + */ + protected $stmt; + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform The underlying database platform. + */ + protected $platform; + /** + * @var \Doctrine\DBAL\Connection The connection this statement is bound to and executed on. + */ + protected $conn; + + /** + * Creates a new Statement for the given SQL and Connection. + * + * @param string $sql The SQL of the statement. + * @param \Doctrine\DBAL\Connection The connection on which the statement should be executed. + */ + public function __construct($sql, Connection $conn) + { + $this->sql = $sql; + $this->stmt = $conn->getWrappedConnection()->prepare($sql); + $this->conn = $conn; + $this->platform = $conn->getDatabasePlatform(); + } + + /** + * Binds a parameter value to the statement. + * + * The value can optionally be bound with a PDO binding type or a DBAL mapping type. + * If bound with a DBAL mapping type, the binding type is derived from the mapping + * type and the value undergoes the conversion routines of the mapping type before + * being bound. + * + * @param string $name The name or position of the parameter. + * @param mixed $value The value of the parameter. + * @param mixed $type Either a PDO binding type or a DBAL mapping type name or instance. + * @return boolean TRUE on success, FALSE on failure. + */ + public function bindValue($name, $value, $type = null) + { + $this->params[$name] = $value; + $this->types[$name] = $type; + if ($type !== null) { + if (is_string($type)) { + $type = Type::getType($type); + } + if ($type instanceof Type) { + $value = $type->convertToDatabaseValue($value, $this->platform); + $bindingType = $type->getBindingType(); + } else { + $bindingType = $type; // PDO::PARAM_* constants + } + return $this->stmt->bindValue($name, $value, $bindingType); + } else { + return $this->stmt->bindValue($name, $value); + } + } + + /** + * Binds a parameter to a value by reference. + * + * Binding a parameter by reference does not support DBAL mapping types. + * + * @param string $name The name or position of the parameter. + * @param mixed $var The reference to the variable to bind + * @param integer $type The PDO binding type. + * @return boolean TRUE on success, FALSE on failure. + */ + public function bindParam($name, &$var, $type = PDO::PARAM_STR, $length = null) + { + return $this->stmt->bindParam($name, $var, $type, $length ); + } + + /** + * Executes the statement with the currently bound parameters. + * + * @param array $params + * @return boolean TRUE on success, FALSE on failure. + */ + public function execute($params = null) + { + $logger = $this->conn->getConfiguration()->getSQLLogger(); + if ($logger) { + $logger->startQuery($this->sql, $this->params, $this->types); + } + + try { + $stmt = $this->stmt->execute($params); + } catch (\Exception $ex) { + throw DBALException::driverExceptionDuringQuery($ex, $this->sql, $this->conn->resolveParams($this->params, $this->types)); + } + + if ($logger) { + $logger->stopQuery(); + } + $this->params = array(); + $this->types = array(); + return $stmt; + } + + /** + * Closes the cursor, freeing the database resources used by this statement. + * + * @return boolean TRUE on success, FALSE on failure. + */ + public function closeCursor() + { + return $this->stmt->closeCursor(); + } + + /** + * Returns the number of columns in the result set. + * + * @return integer + */ + public function columnCount() + { + return $this->stmt->columnCount(); + } + + /** + * Fetches the SQLSTATE associated with the last operation on the statement. + * + * @return string + */ + public function errorCode() + { + return $this->stmt->errorCode(); + } + + /** + * Fetches extended error information associated with the last operation on the statement. + * + * @return array + */ + public function errorInfo() + { + return $this->stmt->errorInfo(); + } + + public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) + { + if ($arg2 === null) { + return $this->stmt->setFetchMode($fetchMode); + } else if ($arg3 === null) { + return $this->stmt->setFetchMode($fetchMode, $arg2); + } + + return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3); + } + + public function getIterator() + { + return $this->stmt; + } + + /** + * Fetches the next row from a result set. + * + * @param integer $fetchMode + * @return mixed The return value of this function on success depends on the fetch type. + * In all cases, FALSE is returned on failure. + */ + public function fetch($fetchMode = null) + { + return $this->stmt->fetch($fetchMode); + } + + /** + * Returns an array containing all of the result set rows. + * + * @param integer $fetchMode + * @param mixed $fetchArgument + * @return array An array containing all of the remaining rows in the result set. + */ + public function fetchAll($fetchMode = null, $fetchArgument = 0) + { + if ($fetchArgument !== 0) { + return $this->stmt->fetchAll($fetchMode, $fetchArgument); + } + return $this->stmt->fetchAll($fetchMode); + } + + /** + * Returns a single column from the next row of a result set. + * + * @param integer $columnIndex + * @return mixed A single column from the next row of a result set or FALSE if there are no more rows. + */ + public function fetchColumn($columnIndex = 0) + { + return $this->stmt->fetchColumn($columnIndex); + } + + /** + * Returns the number of rows affected by the last execution of this statement. + * + * @return integer The number of affected rows. + */ + public function rowCount() + { + return $this->stmt->rowCount(); + } + + /** + * Gets the wrapped driver statement. + * + * @return \Doctrine\DBAL\Driver\Statement + */ + public function getWrappedStatement() + { + return $this->stmt; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php new file mode 100644 index 0000000..6b2b8c2 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php @@ -0,0 +1,124 @@ +. + */ + +namespace Doctrine\DBAL\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console; + +/** + * Task for executing arbitrary SQL that can come from a file or directly from + * the command line. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ImportCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('dbal:import') + ->setDescription('Import SQL file(s) directly to Database.') + ->setDefinition(array( + new InputArgument( + 'file', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'File path(s) of SQL to be executed.' + ) + )) + ->setHelp(<<getHelper('db')->getConnection(); + + if (($fileNames = $input->getArgument('file')) !== null) { + foreach ((array) $fileNames as $fileName) { + $fileName = realpath($fileName); + + if ( ! file_exists($fileName)) { + throw new \InvalidArgumentException( + sprintf("SQL file '%s' does not exist.", $fileName) + ); + } else if ( ! is_readable($fileName)) { + throw new \InvalidArgumentException( + sprintf("SQL file '%s' does not have read permissions.", $fileName) + ); + } + + $output->write(sprintf("Processing file '%s'... ", $fileName)); + $sql = file_get_contents($fileName); + + if ($conn instanceof \Doctrine\DBAL\Driver\PDOConnection) { + // PDO Drivers + try { + $lines = 0; + + $stmt = $conn->prepare($sql); + $stmt->execute(); + + do { + // Required due to "MySQL has gone away!" issue + $stmt->fetch(); + $stmt->closeCursor(); + + $lines++; + } while ($stmt->nextRowset()); + + $output->write(sprintf('%d statements executed!', $lines) . PHP_EOL); + } catch (\PDOException $e) { + $output->write('error!' . PHP_EOL); + + throw new \RuntimeException($e->getMessage(), $e->getCode(), $e); + } + } else { + // Non-PDO Drivers (ie. OCI8 driver) + $stmt = $conn->prepare($sql); + $rs = $stmt->execute(); + + if ($rs) { + $output->writeln('OK!' . PHP_EOL); + } else { + $error = $stmt->errorInfo(); + + $output->write('error!' . PHP_EOL); + + throw new \RuntimeException($error[2], $error[0]); + } + + $stmt->closeCursor(); + } + } + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php new file mode 100644 index 0000000..7b1bb1c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php @@ -0,0 +1,133 @@ +. + */ + + +namespace Doctrine\DBAL\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console\Command\Command, + Symfony\Component\Console\Input\InputInterface, + Symfony\Component\Console\Output\OutputInterface; +use Doctrine\DBAL\Platforms\Keywords\ReservedKeywordsValidator; + +class ReservedWordsCommand extends Command +{ + private $keywordListClasses = array( + 'mysql' => 'Doctrine\DBAL\Platforms\Keywords\MySQLKeywords', + 'mssql' => 'Doctrine\DBAL\Platforms\Keywords\MsSQLKeywords', + 'sqlite' => 'Doctrine\DBAL\Platforms\Keywords\SQLiteKeywords', + 'pgsql' => 'Doctrine\DBAL\Platforms\Keywords\PostgreSQLKeywords', + 'oracle' => 'Doctrine\DBAL\Platforms\Keywords\OracleKeywords', + 'db2' => 'Doctrine\DBAL\Platforms\Keywords\DB2Keywords', + ); + + /** + * If you want to add or replace a keywords list use this command + * + * @param string $name + * @param string $class + */ + public function setKeywordListClass($name, $class) + { + $this->keywordListClasses[$name] = $class; + } + + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('dbal:reserved-words') + ->setDescription('Checks if the current database contains identifiers that are reserved.') + ->setDefinition(array( + new InputOption( + 'list', 'l', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Keyword-List name.' + ) + )) + ->setHelp(<<%command.full_name% + +If you want to check against specific dialects you can +pass them to the command: + + %command.full_name% mysql pgsql + +The following keyword lists are currently shipped with Doctrine: + + * mysql + * pgsql + * sqlite + * oracle + * mssql + * db2 (Not checked by default) +EOT + ); + } + + /** + * @see Console\Command\Command + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + /* @var $conn \Doctrine\DBAL\Connection */ + $conn = $this->getHelper('db')->getConnection(); + + $keywordLists = (array)$input->getOption('list'); + if ( ! $keywordLists) { + $keywordLists = array('mysql', 'pgsql', 'sqlite', 'oracle', 'mssql'); + } + + $keywords = array(); + foreach ($keywordLists as $keywordList) { + if (!isset($this->keywordListClasses[$keywordList])) { + throw new \InvalidArgumentException( + "There exists no keyword list with name '" . $keywordList . "'. ". + "Known lists: " . implode(", ", array_keys($this->keywordListClasses)) + ); + } + $class = $this->keywordListClasses[$keywordList]; + $keywords[] = new $class; + } + + $output->write('Checking keyword violations for ' . implode(", ", $keywordLists) . "...", true); + + /* @var $schema \Doctrine\DBAL\Schema\Schema */ + $schema = $conn->getSchemaManager()->createSchema(); + $visitor = new ReservedKeywordsValidator($keywords); + $schema->visit($visitor); + + $violations = $visitor->getViolations(); + if (count($violations) == 0) { + $output->write("No reserved keywords violations have been found!", true); + } else { + $output->write('There are ' . count($violations) . ' reserved keyword violations in your database schema:', true); + foreach ($violations as $violation) { + $output->write(' - ' . $violation, true); + } + } + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php new file mode 100644 index 0000000..b1af34b --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php @@ -0,0 +1,87 @@ +. + */ + +namespace Doctrine\DBAL\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console; + +/** + * Task for executing arbitrary SQL that can come from a file or directly from + * the command line. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class RunSqlCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('dbal:run-sql') + ->setDescription('Executes arbitrary SQL directly from the command line.') + ->setDefinition(array( + new InputArgument('sql', InputArgument::REQUIRED, 'The SQL statement to execute.'), + new InputOption('depth', null, InputOption::VALUE_REQUIRED, 'Dumping depth of result set.', 7) + )) + ->setHelp(<<getHelper('db')->getConnection(); + + if (($sql = $input->getArgument('sql')) === null) { + throw new \RuntimeException("Argument 'SQL' is required in order to execute this command correctly."); + } + + $depth = $input->getOption('depth'); + + if ( ! is_numeric($depth)) { + throw new \LogicException("Option 'depth' must contains an integer value"); + } + + if (stripos($sql, 'select') === 0) { + $resultSet = $conn->fetchAll($sql); + } else { + $resultSet = $conn->executeUpdate($sql); + } + + ob_start(); + \Doctrine\Common\Util\Debug::dump($resultSet, (int) $depth); + $message = ob_get_clean(); + + $output->write($message); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php new file mode 100644 index 0000000..877cb64 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Tools/Console/Helper/ConnectionHelper.php @@ -0,0 +1,74 @@ +. + */ + +namespace Doctrine\DBAL\Tools\Console\Helper; + +use Symfony\Component\Console\Helper\Helper, + Doctrine\DBAL\Connection; + +/** + * Doctrine CLI Connection Helper. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConnectionHelper extends Helper +{ + /** + * Doctrine Database Connection + * @var Connection + */ + protected $_connection; + + /** + * Constructor + * + * @param Connection $connection Doctrine Database Connection + */ + public function __construct(Connection $connection) + { + $this->_connection = $connection; + } + + /** + * Retrieves Doctrine Database Connection + * + * @return Connection + */ + public function getConnection() + { + return $this->_connection; + } + + /** + * @see Helper + */ + public function getName() + { + return 'connection'; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ArrayType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ArrayType.php new file mode 100644 index 0000000..447f9ee --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ArrayType.php @@ -0,0 +1,64 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps a PHP array to a clob SQL type. + * + * @since 2.0 + */ +class ArrayType extends Type +{ + public function getSQLDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + return $platform->getClobTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + return serialize($value); + } + + public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + $value = (is_resource($value)) ? stream_get_contents($value) : $value; + $val = unserialize($value); + if ($val === false && $value != 'b:0;') { + throw ConversionException::conversionFailed($value, $this->getName()); + } + return $val; + } + + public function getName() + { + return Type::TARRAY; + } + + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php new file mode 100644 index 0000000..7648bef --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BigIntType.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps a database BIGINT to a PHP string. + * + * @author robo + * @since 2.0 + */ +class BigIntType extends Type +{ + public function getName() + { + return Type::BIGINT; + } + + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getBigIntTypeDeclarationSQL($fieldDeclaration); + } + + public function getBindingType() + { + return \PDO::PARAM_STR; + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return (null === $value) ? null : (string) $value; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BlobType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BlobType.php new file mode 100644 index 0000000..32c93a1 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BlobType.php @@ -0,0 +1,67 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps an SQL BLOB to a PHP resource stream + * + * @since 2.2 + */ +class BlobType extends Type +{ + /** @override */ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getBlobTypeDeclarationSQL($fieldDeclaration); + } + + /** + * Converts a value from its database representation to its PHP representation + * of this type. + * + * @param mixed $value The value to convert. + * @param AbstractPlatform $platform The currently used database platform. + * @return mixed The PHP representation of the value. + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if (null === $value) { + return null; + } + if (is_string($value)) { + $value = fopen('data://text/plain;base64,' . base64_encode($value), 'r'); + } else if ( ! is_resource($value)) { + throw ConversionException::conversionFailed($value, self::BLOB); + } + return $value; + } + + public function getName() + { + return Type::BLOB; + } + + public function getBindingType() + { + return \PDO::PARAM_LOB; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BooleanType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BooleanType.php new file mode 100644 index 0000000..f1a968d --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/BooleanType.php @@ -0,0 +1,57 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps an SQL boolean to a PHP boolean. + * + * @since 2.0 + */ +class BooleanType extends Type +{ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getBooleanTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return $platform->convertBooleans($value); + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return (null === $value) ? null : (bool) $value; + } + + public function getName() + { + return Type::BOOLEAN; + } + + public function getBindingType() + { + return \PDO::PARAM_BOOL; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php new file mode 100644 index 0000000..3a19d1a --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php @@ -0,0 +1,65 @@ +. + */ + + +/** + * Conversion Exception is thrown when the database to PHP conversion fails + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +namespace Doctrine\DBAL\Types; + +class ConversionException extends \Doctrine\DBAL\DBALException +{ + /** + * Thrown when a Database to Doctrine Type Conversion fails. + * + * @param string $value + * @param string $toType + * @return ConversionException + */ + static public function conversionFailed($value, $toType) + { + $value = (strlen($value) > 32) ? substr($value, 0, 20) . "..." : $value; + return new self('Could not convert database value "' . $value . '" to Doctrine Type ' . $toType); + } + + /** + * Thrown when a Database to Doctrine Type Conversion fails and we can make a statement + * about the expected format. + * + * @param string $value + * @param string $toType + * @return ConversionException + */ + static public function conversionFailedFormat($value, $toType, $expectedFormat) + { + $value = (strlen($value) > 32) ? substr($value, 0, 20) . "..." : $value; + return new self( + 'Could not convert database value "' . $value . '" to Doctrine Type ' . + $toType . '. Expected format: ' . $expectedFormat + ); + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php new file mode 100644 index 0000000..06de729 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php @@ -0,0 +1,59 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps an SQL DATETIME/TIMESTAMP to a PHP DateTime object. + * + * @since 2.0 + */ +class DateTimeType extends Type +{ + public function getName() + { + return Type::DATETIME; + } + + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getDateTimeTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return ($value !== null) + ? $value->format($platform->getDateTimeFormatString()) : null; + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof \DateTime) { + return $value; + } + + $val = \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value); + if ( ! $val) { + throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateTimeFormatString()); + } + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzType.php new file mode 100644 index 0000000..e0a786c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeTzType.php @@ -0,0 +1,79 @@ +. + */ + + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * DateTime type saving additional timezone information. + * + * Caution: Databases are not necessarily experts at storing timezone related + * data of dates. First, of all the supported vendors only PostgreSQL and Oracle + * support storing Timezone data. But those two don't save the actual timezone + * attached to a DateTime instance (for example "Europe/Berlin" or "America/Montreal") + * but the current offset of them related to UTC. That means depending on daylight saving times + * or not you may get different offsets. + * + * This datatype makes only sense to use, if your application works with an offset, not + * with an actual timezone that uses transitions. Otherwise your DateTime instance + * attached with a timezone such as Europe/Berlin gets saved into the database with + * the offset and re-created from persistence with only the offset, not the original timezone + * attached. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class DateTimeTzType extends Type +{ + public function getName() + { + return Type::DATETIMETZ; + } + + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getDateTimeTzTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return ($value !== null) + ? $value->format($platform->getDateTimeTzFormatString()) : null; + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof \DateTime) { + return $value; + } + + $val = \DateTime::createFromFormat($platform->getDateTimeTzFormatString(), $value); + if ( ! $val) { + throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateTimeTzFormatString()); + } + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateType.php new file mode 100644 index 0000000..a3f7018 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateType.php @@ -0,0 +1,59 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps an SQL DATE to a PHP Date object. + * + * @since 2.0 + */ +class DateType extends Type +{ + public function getName() + { + return Type::DATE; + } + + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getDateTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return ($value !== null) + ? $value->format($platform->getDateFormatString()) : null; + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof \DateTime) { + return $value; + } + + $val = \DateTime::createFromFormat('!'.$platform->getDateFormatString(), $value); + if ( ! $val) { + throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateFormatString()); + } + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DecimalType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DecimalType.php new file mode 100644 index 0000000..fd61b53 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DecimalType.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps an SQL DECIMAL to a PHP double. + * + * @since 2.0 + */ +class DecimalType extends Type +{ + public function getName() + { + return Type::DECIMAL; + } + + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getDecimalTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return (null === $value) ? null : $value; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/FloatType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/FloatType.php new file mode 100644 index 0000000..d02ca0c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/FloatType.php @@ -0,0 +1,54 @@ +. + */ + + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +class FloatType extends Type +{ + public function getName() + { + return Type::FLOAT; + } + + /** + * @param array $fieldDeclaration + * @param AbstractPlatform $platform + * @return string + */ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getFloatDeclarationSQL($fieldDeclaration); + } + + /** + * Converts a value from its database representation to its PHP representation + * of this type. + * + * @param mixed $value The value to convert. + * @param AbstractPlatform $platform The currently used database platform. + * @return mixed The PHP representation of the value. + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return (null === $value) ? null : (double) $value; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/GuidType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/GuidType.php new file mode 100644 index 0000000..a8251dd --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/GuidType.php @@ -0,0 +1,42 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Represents a GUID/UUID datatype (both are actually synomys) in the database. + * + * @author Benjamin Eberlei + * @since 2.3 + */ +class GuidType extends StringType +{ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getGuidTypeDeclarationSQL($fieldDeclaration); + } + + public function getName() + { + return Type::GUID; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/IntegerType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/IntegerType.php new file mode 100644 index 0000000..bac9b3f --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/IntegerType.php @@ -0,0 +1,53 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps an SQL INT to a PHP integer. + * + * @author Roman Borschel + * @since 2.0 + */ +class IntegerType extends Type +{ + public function getName() + { + return Type::INTEGER; + } + + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getIntegerTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return (null === $value) ? null : (int) $value; + } + + public function getBindingType() + { + return \PDO::PARAM_INT; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/JsonArrayType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/JsonArrayType.php new file mode 100644 index 0000000..ca00557 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/JsonArrayType.php @@ -0,0 +1,66 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Array Type which can be used to generate json arrays. + * + * @since 2.3 + * @author Johannes M. Schmitt + */ +class JsonArrayType extends Type +{ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getClobTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if (null === $value) { + return null; + } + + return json_encode($value); + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return array(); + } + + $value = (is_resource($value)) ? stream_get_contents($value) : $value; + + return json_decode($value, true); + } + + public function getName() + { + return Type::JSON_ARRAY; + } + + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php new file mode 100644 index 0000000..9510d29 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php @@ -0,0 +1,64 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps a PHP object to a clob SQL type. + * + * @since 2.0 + */ +class ObjectType extends Type +{ + public function getSQLDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + return $platform->getClobTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + return serialize($value); + } + + public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + if ($value === null) { + return null; + } + + $value = (is_resource($value)) ? stream_get_contents($value) : $value; + $val = unserialize($value); + if ($val === false && $value !== 'b:0;') { + throw ConversionException::conversionFailed($value, $this->getName()); + } + return $val; + } + + public function getName() + { + return Type::OBJECT; + } + + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SimpleArrayType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SimpleArrayType.php new file mode 100644 index 0000000..719d7f1 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SimpleArrayType.php @@ -0,0 +1,69 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Array Type which can be used for simple values. + * + * Only use this type if you are sure that your values cannot contain a ",". + * + * @since 2.3 + * @author Johannes M. Schmitt + */ +class SimpleArrayType extends Type +{ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getClobTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if (!$value) { + return null; + } + + return implode(',', $value); + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null) { + return array(); + } + + $value = (is_resource($value)) ? stream_get_contents($value) : $value; + + return explode(',', $value); + } + + public function getName() + { + return Type::SIMPLE_ARRAY; + } + + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return true; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SmallIntType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SmallIntType.php new file mode 100644 index 0000000..97e9aaf --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/SmallIntType.php @@ -0,0 +1,52 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps a database SMALLINT to a PHP integer. + * + * @author robo + */ +class SmallIntType extends Type +{ + public function getName() + { + return Type::SMALLINT; + } + + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getSmallIntTypeDeclarationSQL($fieldDeclaration); + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return (null === $value) ? null : (int) $value; + } + + public function getBindingType() + { + return \PDO::PARAM_INT; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/StringType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/StringType.php new file mode 100644 index 0000000..48c76d6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/StringType.php @@ -0,0 +1,50 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps an SQL VARCHAR to a PHP string. + * + * @since 2.0 + */ +class StringType extends Type +{ + /** @override */ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration); + } + + /** @override */ + public function getDefaultLength(AbstractPlatform $platform) + { + return $platform->getVarcharDefaultLength(); + } + + /** @override */ + public function getName() + { + return Type::STRING; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TextType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TextType.php new file mode 100644 index 0000000..98ecbe6 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TextType.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps an SQL CLOB to a PHP string. + * + * @since 2.0 + */ +class TextType extends Type +{ + /** @override */ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getClobTypeDeclarationSQL($fieldDeclaration); + } + + /** + * Converts a value from its database representation to its PHP representation + * of this type. + * + * @param mixed $value The value to convert. + * @param AbstractPlatform $platform The currently used database platform. + * @return mixed The PHP representation of the value. + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return (is_resource($value)) ? stream_get_contents($value) : $value; + } + + public function getName() + { + return Type::TEXT; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeType.php new file mode 100644 index 0000000..8653750 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/TimeType.php @@ -0,0 +1,68 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Type that maps an SQL TIME to a PHP DateTime object. + * + * @since 2.0 + */ +class TimeType extends Type +{ + public function getName() + { + return Type::TIME; + } + + /** + * {@inheritdoc} + */ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getTimeTypeDeclarationSQL($fieldDeclaration); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return ($value !== null) + ? $value->format($platform->getTimeFormatString()) : null; + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof \DateTime) { + return $value; + } + + $val = \DateTime::createFromFormat($platform->getTimeFormatString(), $value); + if ( ! $val) { + throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getTimeFormatString()); + } + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Type.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Type.php new file mode 100644 index 0000000..29947be --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Type.php @@ -0,0 +1,306 @@ +. + */ + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform, + Doctrine\DBAL\DBALException; + +/** + * The base class for so-called Doctrine mapping types. + * + * A Type object is obtained by calling the static {@link getType()} method. + * + * @author Roman Borschel + * @author Benjamin Eberlei + * @since 2.0 + */ +abstract class Type +{ + const TARRAY = 'array'; + const SIMPLE_ARRAY = 'simple_array'; + const JSON_ARRAY = 'json_array'; + const BIGINT = 'bigint'; + const BOOLEAN = 'boolean'; + const DATETIME = 'datetime'; + const DATETIMETZ = 'datetimetz'; + const DATE = 'date'; + const TIME = 'time'; + const DECIMAL = 'decimal'; + const INTEGER = 'integer'; + const OBJECT = 'object'; + const SMALLINT = 'smallint'; + const STRING = 'string'; + const TEXT = 'text'; + const BLOB = 'blob'; + const FLOAT = 'float'; + const GUID = 'guid'; + + /** Map of already instantiated type objects. One instance per type (flyweight). */ + private static $_typeObjects = array(); + + /** The map of supported doctrine mapping types. */ + private static $_typesMap = array( + self::TARRAY => 'Doctrine\DBAL\Types\ArrayType', + self::SIMPLE_ARRAY => 'Doctrine\DBAL\Types\SimpleArrayType', + self::JSON_ARRAY => 'Doctrine\DBAL\Types\JsonArrayType', + self::OBJECT => 'Doctrine\DBAL\Types\ObjectType', + self::BOOLEAN => 'Doctrine\DBAL\Types\BooleanType', + self::INTEGER => 'Doctrine\DBAL\Types\IntegerType', + self::SMALLINT => 'Doctrine\DBAL\Types\SmallIntType', + self::BIGINT => 'Doctrine\DBAL\Types\BigIntType', + self::STRING => 'Doctrine\DBAL\Types\StringType', + self::TEXT => 'Doctrine\DBAL\Types\TextType', + self::DATETIME => 'Doctrine\DBAL\Types\DateTimeType', + self::DATETIMETZ => 'Doctrine\DBAL\Types\DateTimeTzType', + self::DATE => 'Doctrine\DBAL\Types\DateType', + self::TIME => 'Doctrine\DBAL\Types\TimeType', + self::DECIMAL => 'Doctrine\DBAL\Types\DecimalType', + self::FLOAT => 'Doctrine\DBAL\Types\FloatType', + self::BLOB => 'Doctrine\DBAL\Types\BlobType', + self::GUID => 'Doctrine\DBAL\Types\GuidType', + ); + + /* Prevent instantiation and force use of the factory method. */ + final private function __construct() {} + + /** + * Converts a value from its PHP representation to its database representation + * of this type. + * + * @param mixed $value The value to convert. + * @param AbstractPlatform $platform The currently used database platform. + * @return mixed The database representation of the value. + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return $value; + } + + /** + * Converts a value from its database representation to its PHP representation + * of this type. + * + * @param mixed $value The value to convert. + * @param AbstractPlatform $platform The currently used database platform. + * @return mixed The PHP representation of the value. + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return $value; + } + + /** + * Gets the default length of this type. + * + * @todo Needed? + */ + public function getDefaultLength(AbstractPlatform $platform) + { + return null; + } + + /** + * Gets the SQL declaration snippet for a field of this type. + * + * @param array $fieldDeclaration The field declaration. + * @param AbstractPlatform $platform The currently used database platform. + */ + abstract public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform); + + /** + * Gets the name of this type. + * + * @return string + * @todo Needed? + */ + abstract public function getName(); + + /** + * Factory method to create type instances. + * Type instances are implemented as flyweights. + * + * @static + * @throws DBALException + * @param string $name The name of the type (as returned by getName()). + * @return \Doctrine\DBAL\Types\Type + */ + public static function getType($name) + { + if ( ! isset(self::$_typeObjects[$name])) { + if ( ! isset(self::$_typesMap[$name])) { + throw DBALException::unknownColumnType($name); + } + self::$_typeObjects[$name] = new self::$_typesMap[$name](); + } + + return self::$_typeObjects[$name]; + } + + /** + * Adds a custom type to the type map. + * + * @static + * @param string $name Name of the type. This should correspond to what getName() returns. + * @param string $className The class name of the custom type. + * @throws DBALException + */ + public static function addType($name, $className) + { + if (isset(self::$_typesMap[$name])) { + throw DBALException::typeExists($name); + } + + self::$_typesMap[$name] = $className; + } + + /** + * Checks if exists support for a type. + * + * @static + * @param string $name Name of the type + * @return boolean TRUE if type is supported; FALSE otherwise + */ + public static function hasType($name) + { + return isset(self::$_typesMap[$name]); + } + + /** + * Overrides an already defined type to use a different implementation. + * + * @static + * @param string $name + * @param string $className + * @throws DBALException + */ + public static function overrideType($name, $className) + { + if ( ! isset(self::$_typesMap[$name])) { + throw DBALException::typeNotFound($name); + } + + if (isset(self::$_typeObjects[$name])) { + unset(self::$_typeObjects[$name]); + } + + self::$_typesMap[$name] = $className; + } + + /** + * Gets the (preferred) binding type for values of this type that + * can be used when binding parameters to prepared statements. + * + * This method should return one of the PDO::PARAM_* constants, that is, one of: + * + * PDO::PARAM_BOOL + * PDO::PARAM_NULL + * PDO::PARAM_INT + * PDO::PARAM_STR + * PDO::PARAM_LOB + * + * @return integer + */ + public function getBindingType() + { + return \PDO::PARAM_STR; + } + + /** + * Get the types array map which holds all registered types and the corresponding + * type class + * + * @return array $typesMap + */ + public static function getTypesMap() + { + return self::$_typesMap; + } + + public function __toString() + { + $e = explode('\\', get_class($this)); + return str_replace('Type', '', end($e)); + } + + /** + * Does working with this column require SQL conversion functions? + * + * This is a metadata function that is required for example in the ORM. + * Usage of {@link convertToDatabaseValueSQL} and + * {@link convertToPHPValueSQL} works for any type and mostly + * does nothing. This method can additionally be used for optimization purposes. + * + * @return bool + */ + public function canRequireSQLConversion() + { + return false; + } + + /** + * Modifies the SQL expression (identifier, parameter) to convert to a database value. + * + * @param string $sqlExpr + * @param AbstractPlatform $platform + * @return string + */ + public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) + { + return $sqlExpr; + } + + /** + * Modifies the SQL expression (identifier, parameter) to convert to a PHP value. + * + * @param string $sqlExpr + * @param AbstractPlatform $platform + * @return string + */ + public function convertToPHPValueSQL($sqlExpr, $platform) + { + return $sqlExpr; + } + + /** + * Get an array of database types that map to this Doctrine type. + * + * @param AbstractPlatform $platform + * @return array + */ + public function getMappedDatabaseTypes(AbstractPlatform $platform) + { + return array(); + } + + /** + * If this Doctrine Type maps to an already mapped database type, + * reverse schema engineering can't take them apart. You need to mark + * one of those types as commented, which will have Doctrine use an SQL + * comment to typehint the actual Doctrine Type. + * + * @param AbstractPlatform $platform + * @return bool + */ + public function requiresSQLCommentHint(AbstractPlatform $platform) + { + return false; + } +} + diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php new file mode 100644 index 0000000..7085822 --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php @@ -0,0 +1,60 @@ +. + */ + + +namespace Doctrine\DBAL\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * Variable DateTime Type using date_create() instead of DateTime::createFromFormat() + * + * This type has performance implications as it runs twice as long as the regular + * {@see DateTimeType}, however in certain PostgreSQL configurations with + * TIMESTAMP(n) columns where n > 0 it is necessary to use this type. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class VarDateTimeType extends DateTimeType +{ + /** + * @throws ConversionException + * @param string $value + * @param AbstractPlatform $platform + * @return \DateTime + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if ($value === null || $value instanceof \DateTime) { + return $value; + } + + $val = date_create($value); + if ( ! $val) { + throw ConversionException::conversionFailed($value, $this->getName()); + } + return $val; + } +} diff --git a/vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php new file mode 100644 index 0000000..4dc3f1c --- /dev/null +++ b/vendor/doctrine/dbal/lib/Doctrine/DBAL/Version.php @@ -0,0 +1,55 @@ +. + */ + +namespace Doctrine\DBAL; + +/** + * Class to store and retrieve the version of Doctrine + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Version +{ + /** + * Current Doctrine Version + */ + const VERSION = '2.3.0'; + + /** + * Compares a Doctrine version with the current one. + * + * @param string $version Doctrine version to compare. + * @return int Returns -1 if older, 0 if it is the same, 1 if version + * passed as argument is newer. + */ + public static function compare($version) + { + $currentVersion = str_replace(' ', '', strtolower(self::VERSION)); + $version = str_replace(' ', '', $version); + + return version_compare($version, $currentVersion); + } +} diff --git a/vendor/doctrine/dbal/phpunit.xml.dist b/vendor/doctrine/dbal/phpunit.xml.dist new file mode 100644 index 0000000..fe1d515 --- /dev/null +++ b/vendor/doctrine/dbal/phpunit.xml.dist @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + ./tests/Doctrine/Tests/DBAL + + + \ No newline at end of file diff --git a/vendor/doctrine/dbal/run-all.sh b/vendor/doctrine/dbal/run-all.sh new file mode 100644 index 0000000..80712ee --- /dev/null +++ b/vendor/doctrine/dbal/run-all.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# This script is a small convenience wrapper for running the doctrine testsuite against a large bunch of databases. +# Just create the phpunit.xmls as described in the array below and configure the specific files section +# to connect to that database. Just omit a file if you dont have that database and the tests will be skipped. + +configs[1]="mysql.phpunit.xml" +configs[2]='postgres.phpunit.xml' +configs[3]='sqlite.phpunit.xml' +configs[4]='oracle.phpunit.xml' +configs[5]='db2.phpunit.xml' +configs[6]='pdo-ibm.phpunit.xml' +configs[7]='sqlsrv.phpunit.xml' + +for i in "${configs[@]}"; do + if [ -f "$i" ]; + then + echo "RUNNING TESTS WITH CONFIG $i" + phpunit -c "$i" "$@" + fi; +done diff --git a/vendor/doctrine/dbal/tests/.gitignore b/vendor/doctrine/dbal/tests/.gitignore new file mode 100644 index 0000000..7210405 --- /dev/null +++ b/vendor/doctrine/dbal/tests/.gitignore @@ -0,0 +1,3 @@ +Doctrine/Tests/Proxies/ +Doctrine/Tests/ORM/Proxy/generated/ +Doctrine/Tests/ORM/Tools/Export/export diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/ConnectionTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/ConnectionTest.php new file mode 100644 index 0000000..48fbb69 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/ConnectionTest.php @@ -0,0 +1,177 @@ + 'pdo_mysql', + 'host' => 'localhost', + 'user' => 'root', + 'password' => 'password', + 'port' => '1234' + ); + $this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params); + } + + public function testIsConnected() + { + $this->assertFalse($this->_conn->isConnected()); + } + + public function testNoTransactionActiveByDefault() + { + $this->assertFalse($this->_conn->isTransactionActive()); + } + + public function testCommitWithNoActiveTransaction_ThrowsException() + { + $this->setExpectedException('Doctrine\DBAL\ConnectionException'); + $this->_conn->commit(); + } + + public function testRollbackWithNoActiveTransaction_ThrowsException() + { + $this->setExpectedException('Doctrine\DBAL\ConnectionException'); + $this->_conn->rollback(); + } + + public function testSetRollbackOnlyNoActiveTransaction_ThrowsException() + { + $this->setExpectedException('Doctrine\DBAL\ConnectionException'); + $this->_conn->setRollbackOnly(); + } + + public function testIsRollbackOnlyNoActiveTransaction_ThrowsException() + { + $this->setExpectedException('Doctrine\DBAL\ConnectionException'); + $this->_conn->isRollbackOnly(); + } + + public function testGetConfiguration() + { + $config = $this->_conn->getConfiguration(); + + $this->assertInstanceOf('Doctrine\DBAL\Configuration', $config); + } + + public function testGetHost() + { + $this->assertEquals('localhost', $this->_conn->getHost()); + } + + public function testGetPort() + { + $this->assertEquals('1234', $this->_conn->getPort()); + } + + public function testGetUsername() + { + $this->assertEquals('root', $this->_conn->getUsername()); + } + + public function testGetPassword() + { + $this->assertEquals('password', $this->_conn->getPassword()); + } + + public function testGetDriver() + { + $this->assertInstanceOf('Doctrine\DBAL\Driver\PDOMySql\Driver', $this->_conn->getDriver()); + } + + public function testGetEventManager() + { + $this->assertInstanceOf('Doctrine\Common\EventManager', $this->_conn->getEventManager()); + } + + public function testConnectDispatchEvent() + { + $listenerMock = $this->getMock('ConnectDispatchEventListener', array('postConnect')); + $listenerMock->expects($this->once())->method('postConnect'); + + $eventManager = new EventManager(); + $eventManager->addEventListener(array(Events::postConnect), $listenerMock); + + $driverMock = $this->getMock('Doctrine\DBAL\Driver'); + $driverMock->expects(($this->at(0))) + ->method('connect'); + $platform = new Mocks\MockPlatform(); + + $conn = new Connection(array('platform' => $platform), $driverMock, new Configuration(), $eventManager); + $conn->connect(); + } + + public function testEventManagerPassedToPlatform() + { + $this->assertInstanceOf('Doctrine\Common\EventManager', $this->_conn->getDatabasePlatform()->getEventManager()); + $this->assertSame($this->_conn->getEventManager(), $this->_conn->getDatabasePlatform()->getEventManager()); + } + + /** + * @expectedException Doctrine\DBAL\DBALException + * @dataProvider getQueryMethods + */ + public function testDriverExceptionIsWrapped($method) + { + $this->setExpectedException('Doctrine\DBAL\DBALException', "An exception occurred while executing 'MUUHAAAAHAAAA': + +SQLSTATE[HY000]: General error: 1 near \"MUUHAAAAHAAAA\""); + + $con = \Doctrine\DBAL\DriverManager::getConnection(array( + 'driver' => 'pdo_sqlite', + 'memory' => true, + )); + + $con->$method('MUUHAAAAHAAAA'); + } + + public function getQueryMethods() + { + return array( + array('exec'), + array('query'), + array('executeQuery'), + array('executeUpdate'), + array('prepare'), + ); + } + + /** + * Pretty dumb test, however we want to check that the EchoSQLLogger correctly implements the interface. + * + * @group DBAL-11 + */ + public function testEchoSQLLogger() + { + $logger = new \Doctrine\DBAL\Logging\EchoSQLLogger(); + $this->_conn->getConfiguration()->setSQLLogger($logger); + $this->assertSame($logger, $this->_conn->getConfiguration()->getSQLLogger()); + } + + /** + * Pretty dumb test, however we want to check that the DebugStack correctly implements the interface. + * + * @group DBAL-11 + */ + public function testDebugSQLStack() + { + $logger = new \Doctrine\DBAL\Logging\DebugStack(); + $this->_conn->getConfiguration()->setSQLLogger($logger); + $this->assertSame($logger, $this->_conn->getConfiguration()->getSQLLogger()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php new file mode 100644 index 0000000..a3dfe2a --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php @@ -0,0 +1,82 @@ +markTestSkipped('oci8 is not installed.'); + } + + parent::setUp(); + } + + /** + * This scenario shows that when the first parameter is not null + * it properly sets $hasZeroIndex to 1 and calls bindValue starting at 1. + * + * This also verifies that the statement will check with the connection to + * see what the current execution mode is. + * + * The expected exception is due to oci_execute failing due to no valid connection. + * + * @dataProvider executeDataProvider + * @expectedException \Doctrine\DBAL\Driver\OCI8\OCI8Exception + */ + public function testExecute(array $params) + { + $statement = $this->getMock('\Doctrine\DBAL\Driver\OCI8\OCI8Statement', + array('bindValue', 'errorInfo'), + array(), '', false); + + $statement->expects($this->at(0)) + ->method('bindValue') + ->with( + $this->equalTo(1), + $this->equalTo($params[0]) + ); + $statement->expects($this->at(1)) + ->method('bindValue') + ->with( + $this->equalTo(2), + $this->equalTo($params[1]) + ); + $statement->expects($this->at(2)) + ->method('bindValue') + ->with( + $this->equalTo(3), + $this->equalTo($params[2]) + ); + + // can't pass to constructor since we don't have a real database handle, + // but execute must check the connection for the executeMode + $conn = $this->getMock('\Doctrine\DBAL\Driver\OCI8\OCI8Connection', array('getExecuteMode'), array(), '', false); + $conn->expects($this->once()) + ->method('getExecuteMode'); + + $reflProperty = new \ReflectionProperty($statement, '_conn'); + $reflProperty->setAccessible(true); + $reflProperty->setValue($statement, $conn); + + $statement->execute($params); + } + + public static function executeDataProvider() + { + return array( + // $hasZeroIndex = isset($params[0]); == true + array( + array(0 => 'test', 1 => null, 2 => 'value') + ), + // $hasZeroIndex = isset($params[0]); == false + array( + array(0 => null, 1 => 'test', 2 => 'value') + ) + ); + } + +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/DriverManagerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/DriverManagerTest.php new file mode 100644 index 0000000..055b2ae --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/DriverManagerTest.php @@ -0,0 +1,117 @@ + 'test' + ); + $test = \Doctrine\DBAL\DriverManager::getConnection($options); + } + + public function testValidPdoInstance() + { + $options = array( + 'pdo' => new \PDO('sqlite::memory:') + ); + $conn = \Doctrine\DBAL\DriverManager::getConnection($options); + $this->assertEquals('sqlite', $conn->getDatabasePlatform()->getName()); + } + + /** + * @group DBAL-32 + */ + public function testPdoInstanceSetErrorMode() + { + $pdo = new \PDO('sqlite::memory:'); + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT); + $options = array( + 'pdo' => $pdo + ); + + $conn = \Doctrine\DBAL\DriverManager::getConnection($options); + $this->assertEquals(\PDO::ERRMODE_EXCEPTION, $pdo->getAttribute(\PDO::ATTR_ERRMODE)); + } + + /** + * @expectedException \Doctrine\DBAL\DBALException + */ + public function testCheckParams() + { + $conn = \Doctrine\DBAL\DriverManager::getConnection(array()); + } + + /** + * @expectedException \Doctrine\DBAL\DBALException + */ + public function testInvalidDriver() + { + $conn = \Doctrine\DBAL\DriverManager::getConnection(array('driver' => 'invalid_driver')); + } + + public function testCustomPlatform() + { + $mockPlatform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $options = array( + 'pdo' => new \PDO('sqlite::memory:'), + 'platform' => $mockPlatform + ); + + $conn = \Doctrine\DBAL\DriverManager::getConnection($options); + $this->assertSame($mockPlatform, $conn->getDatabasePlatform()); + } + + public function testCustomWrapper() + { + $wrapperClass = 'Doctrine\Tests\Mocks\ConnectionMock'; + + $options = array( + 'pdo' => new \PDO('sqlite::memory:'), + 'wrapperClass' => $wrapperClass, + ); + + $conn = \Doctrine\DBAL\DriverManager::getConnection($options); + $this->assertInstanceOf($wrapperClass, $conn); + } + + public function testInvalidWrapperClass() + { + $this->setExpectedException('\Doctrine\DBAL\DBALException'); + + $options = array( + 'pdo' => new \PDO('sqlite::memory:'), + 'wrapperClass' => 'stdClass', + ); + + $conn = \Doctrine\DBAL\DriverManager::getConnection($options); + } + + public function testInvalidDriverClass() + { + $this->setExpectedException('\Doctrine\DBAL\DBALException'); + + $options = array( + 'driverClass' => 'stdClass' + ); + + $conn = \Doctrine\DBAL\DriverManager::getConnection($options); + } + + public function testValidDriverClass() + { + $options = array( + 'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver', + ); + + $conn = \Doctrine\DBAL\DriverManager::getConnection($options); + $this->assertInstanceOf('Doctrine\DBAL\Driver\PDOMySql\Driver', $conn->getDriver()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/MysqlSessionInitTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/MysqlSessionInitTest.php new file mode 100644 index 0000000..1ef47dd --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/MysqlSessionInitTest.php @@ -0,0 +1,33 @@ +getMock('Doctrine\DBAL\Connection', array(), array(), '', false); + $connectionMock->expects($this->once()) + ->method('executeUpdate') + ->with($this->equalTo("SET NAMES foo COLLATE bar")); + + $eventArgs = new ConnectionEventArgs($connectionMock); + + + $listener = new MysqlSessionInit('foo', 'bar'); + $listener->postConnect($eventArgs); + } + + public function testGetSubscribedEvents() + { + $listener = new MysqlSessionInit(); + $this->assertEquals(array(Events::postConnect), $listener->getSubscribedEvents()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/OracleSessionInitTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/OracleSessionInitTest.php new file mode 100644 index 0000000..847ed6b --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/OracleSessionInitTest.php @@ -0,0 +1,33 @@ +getMock('Doctrine\DBAL\Connection', array(), array(), '', false); + $connectionMock->expects($this->once()) + ->method('executeUpdate') + ->with($this->isType('string')); + + $eventArgs = new ConnectionEventArgs($connectionMock); + + + $listener = new OracleSessionInit(); + $listener->postConnect($eventArgs); + } + + public function testGetSubscribedEvents() + { + $listener = new OracleSessionInit(); + $this->assertEquals(array(Events::postConnect), $listener->getSubscribedEvents()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/SQLSessionInitTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/SQLSessionInitTest.php new file mode 100644 index 0000000..ed2dd43 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Events/SQLSessionInitTest.php @@ -0,0 +1,35 @@ +getMock('Doctrine\DBAL\Connection', array(), array(), '', false); + $connectionMock->expects($this->once()) + ->method('exec') + ->with($this->equalTo("SET SEARCH_PATH TO foo, public, TIMEZONE TO 'Europe/Berlin'")); + + $eventArgs = new ConnectionEventArgs($connectionMock); + + $listener = new SQLSessionInit("SET SEARCH_PATH TO foo, public, TIMEZONE TO 'Europe/Berlin'"); + $listener->postConnect($eventArgs); + } + + public function testGetSubscribedEvents() + { + $listener = new SQLSessionInit("SET SEARCH_PATH TO foo, public, TIMEZONE TO 'Europe/Berlin'"); + $this->assertEquals(array(Events::postConnect), $listener->getSubscribedEvents()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/BlobTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/BlobTest.php new file mode 100644 index 0000000..7c56542 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/BlobTest.php @@ -0,0 +1,83 @@ +addColumn('id', 'integer'); + $table->addColumn('clobfield', 'text'); + $table->addColumn('blobfield', 'blob'); + $table->setPrimaryKey(array('id')); + + $sm = $this->_conn->getSchemaManager(); + $sm->createTable($table); + } catch(\Exception $e) { + + } + $this->_conn->exec($this->_conn->getDatabasePlatform()->getTruncateTableSQL('blob_table')); + } + + public function testInsert() + { + $ret = $this->_conn->insert('blob_table', + array('id' => 1, 'clobfield' => 'test', 'blobfield' => 'test'), + array(\PDO::PARAM_INT, \PDO::PARAM_STR, \PDO::PARAM_LOB) + ); + $this->assertEquals(1, $ret); + } + + public function testSelect() + { + $ret = $this->_conn->insert('blob_table', + array('id' => 1, 'clobfield' => 'test', 'blobfield' => 'test'), + array(\PDO::PARAM_INT, \PDO::PARAM_STR, \PDO::PARAM_LOB) + ); + + $this->assertBlobContains('test'); + } + + public function testUpdate() + { + $ret = $this->_conn->insert('blob_table', + array('id' => 1, 'clobfield' => 'test', 'blobfield' => 'test'), + array(\PDO::PARAM_INT, \PDO::PARAM_STR, \PDO::PARAM_LOB) + ); + + $this->_conn->update('blob_table', + array('blobfield' => 'test2'), + array('id' => 1), + array(\PDO::PARAM_LOB, \PDO::PARAM_INT) + ); + + $this->assertBlobContains('test2'); + } + + private function assertBlobContains($text) + { + $rows = $this->_conn->fetchAll('SELECT * FROM blob_table'); + + $this->assertEquals(1, count($rows)); + $row = array_change_key_case($rows[0], CASE_LOWER); + + $blobValue = Type::getType('blob')->convertToPHPValue($row['blobfield'], $this->_conn->getDatabasePlatform()); + + $this->assertInternalType('resource', $blobValue); + $this->assertEquals($text, stream_get_contents($blobValue)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php new file mode 100644 index 0000000..31da42f --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php @@ -0,0 +1,219 @@ +resetSharedConn(); + parent::setUp(); + } + + public function tearDown() + { + parent::tearDown(); + $this->resetSharedConn(); + } + + public function testGetWrappedConnection() + { + $this->assertInstanceOf('Doctrine\DBAL\Driver\Connection', $this->_conn->getWrappedConnection()); + } + + public function testCommitWithRollbackOnlyThrowsException() + { + $this->_conn->beginTransaction(); + $this->_conn->setRollbackOnly(); + $this->setExpectedException('Doctrine\DBAL\ConnectionException'); + $this->_conn->commit(); + } + + public function testTransactionNestingBehavior() + { + try { + $this->_conn->beginTransaction(); + $this->assertEquals(1, $this->_conn->getTransactionNestingLevel()); + + try { + $this->_conn->beginTransaction(); + $this->assertEquals(2, $this->_conn->getTransactionNestingLevel()); + throw new \Exception; + $this->_conn->commit(); // never reached + } catch (\Exception $e) { + $this->_conn->rollback(); + $this->assertEquals(1, $this->_conn->getTransactionNestingLevel()); + //no rethrow + } + $this->assertTrue($this->_conn->isRollbackOnly()); + + $this->_conn->commit(); // should throw exception + $this->fail('Transaction commit after failed nested transaction should fail.'); + } catch (ConnectionException $e) { + $this->assertEquals(1, $this->_conn->getTransactionNestingLevel()); + $this->_conn->rollback(); + $this->assertEquals(0, $this->_conn->getTransactionNestingLevel()); + } + } + + public function testTransactionNestingBehaviorWithSavepoints() + { + if (!$this->_conn->getDatabasePlatform()->supportsSavepoints()) { + $this->markTestSkipped('This test requires the platform to support savepoints.'); + } + + $this->_conn->setNestTransactionsWithSavepoints(true); + try { + $this->_conn->beginTransaction(); + $this->assertEquals(1, $this->_conn->getTransactionNestingLevel()); + + try { + $this->_conn->beginTransaction(); + $this->assertEquals(2, $this->_conn->getTransactionNestingLevel()); + $this->_conn->beginTransaction(); + $this->assertEquals(3, $this->_conn->getTransactionNestingLevel()); + $this->_conn->commit(); + $this->assertEquals(2, $this->_conn->getTransactionNestingLevel()); + throw new \Exception; + $this->_conn->commit(); // never reached + } catch (\Exception $e) { + $this->_conn->rollback(); + $this->assertEquals(1, $this->_conn->getTransactionNestingLevel()); + //no rethrow + } + $this->assertFalse($this->_conn->isRollbackOnly()); + try { + $this->_conn->setNestTransactionsWithSavepoints(false); + $this->fail('Should not be able to disable savepoints in usage for nested transactions inside an open transaction.'); + } catch (ConnectionException $e) { + $this->assertTrue($this->_conn->getNestTransactionsWithSavepoints()); + } + $this->_conn->commit(); // should not throw exception + } catch (ConnectionException $e) { + $this->fail('Transaction commit after failed nested transaction should not fail when using savepoints.'); + $this->_conn->rollback(); + } + } + + public function testTransactionNestingBehaviorCantBeChangedInActiveTransaction() + { + if (!$this->_conn->getDatabasePlatform()->supportsSavepoints()) { + $this->markTestSkipped('This test requires the platform to support savepoints.'); + } + + $this->_conn->beginTransaction(); + try { + $this->_conn->setNestTransactionsWithSavepoints(true); + $this->fail('An exception should have been thrown by chaning the nesting transaction behavior within an transaction.'); + } catch(ConnectionException $e) { + $this->_conn->rollBack(); + } + } + + public function testSetNestedTransactionsThroughSavepointsNotSupportedThrowsException() + { + if ($this->_conn->getDatabasePlatform()->supportsSavepoints()) { + $this->markTestSkipped('This test requires the platform not to support savepoints.'); + } + + $this->setExpectedException('Doctrine\DBAL\ConnectionException', "Savepoints are not supported by this driver."); + + $this->_conn->setNestTransactionsWithSavepoints(true); + } + + public function testCreateSavepointsNotSupportedThrowsException() + { + if ($this->_conn->getDatabasePlatform()->supportsSavepoints()) { + $this->markTestSkipped('This test requires the platform not to support savepoints.'); + } + + $this->setExpectedException('Doctrine\DBAL\ConnectionException', "Savepoints are not supported by this driver."); + + $this->_conn->createSavepoint('foo'); + } + + public function testReleaseSavepointsNotSupportedThrowsException() + { + if ($this->_conn->getDatabasePlatform()->supportsSavepoints()) { + $this->markTestSkipped('This test requires the platform not to support savepoints.'); + } + + $this->setExpectedException('Doctrine\DBAL\ConnectionException', "Savepoints are not supported by this driver."); + + $this->_conn->releaseSavepoint('foo'); + } + + public function testRollbackSavepointsNotSupportedThrowsException() + { + if ($this->_conn->getDatabasePlatform()->supportsSavepoints()) { + $this->markTestSkipped('This test requires the platform not to support savepoints.'); + } + + $this->setExpectedException('Doctrine\DBAL\ConnectionException', "Savepoints are not supported by this driver."); + + $this->_conn->rollbackSavepoint('foo'); + } + + public function testTransactionBehaviorWithRollback() + { + try { + $this->_conn->beginTransaction(); + $this->assertEquals(1, $this->_conn->getTransactionNestingLevel()); + + throw new \Exception; + + $this->_conn->commit(); // never reached + } catch (\Exception $e) { + $this->assertEquals(1, $this->_conn->getTransactionNestingLevel()); + $this->_conn->rollback(); + $this->assertEquals(0, $this->_conn->getTransactionNestingLevel()); + } + } + + public function testTransactionBehaviour() + { + try { + $this->_conn->beginTransaction(); + $this->assertEquals(1, $this->_conn->getTransactionNestingLevel()); + $this->_conn->commit(); + } catch (\Exception $e) { + $this->_conn->rollback(); + $this->assertEquals(0, $this->_conn->getTransactionNestingLevel()); + } + + $this->assertEquals(0, $this->_conn->getTransactionNestingLevel()); + } + + public function testTransactionalWithException() + { + try { + $this->_conn->transactional(function($conn) { + $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL()); + throw new \RuntimeException("Ooops!"); + }); + } catch (\RuntimeException $expected) { + $this->assertEquals(0, $this->_conn->getTransactionNestingLevel()); + } + } + + public function testTransactional() + { + $this->_conn->transactional(function($conn) { + /* @var $conn Connection */ + $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL()); + }); + } + + /** + * Tests that the quote function accepts DBAL and PDO types. + */ + public function testQuote() + { + $this->assertEquals($this->_conn->quote("foo", Type::STRING), $this->_conn->quote("foo", \PDO::PARAM_STR)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php new file mode 100644 index 0000000..4b57a44 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php @@ -0,0 +1,543 @@ +addColumn('test_int', 'integer'); + $table->addColumn('test_string', 'string'); + $table->addColumn('test_datetime', 'datetime', array('notnull' => false)); + $table->setPrimaryKey(array('test_int')); + + $sm = $this->_conn->getSchemaManager(); + $sm->createTable($table); + + $this->_conn->insert('fetch_table', array('test_int' => 1, 'test_string' => 'foo', 'test_datetime' => '2010-01-01 10:10:10')); + self::$generated = true; + } + } + + public function testPrepareWithBindValue() + { + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $stmt = $this->_conn->prepare($sql); + $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); + + $stmt->bindValue(1, 1); + $stmt->bindValue(2, 'foo'); + $stmt->execute(); + + $row = $stmt->fetch(\PDO::FETCH_ASSOC); + $row = array_change_key_case($row, \CASE_LOWER); + $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); + } + + public function testPrepareWithBindParam() + { + $paramInt = 1; + $paramStr = 'foo'; + + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $stmt = $this->_conn->prepare($sql); + $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); + + $stmt->bindParam(1, $paramInt); + $stmt->bindParam(2, $paramStr); + $stmt->execute(); + + $row = $stmt->fetch(\PDO::FETCH_ASSOC); + $row = array_change_key_case($row, \CASE_LOWER); + $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); + } + + public function testPrepareWithFetchAll() + { + $paramInt = 1; + $paramStr = 'foo'; + + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $stmt = $this->_conn->prepare($sql); + $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); + + $stmt->bindParam(1, $paramInt); + $stmt->bindParam(2, $paramStr); + $stmt->execute(); + + $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC); + $rows[0] = array_change_key_case($rows[0], \CASE_LOWER); + $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $rows[0]); + } + + /** + * @group DBAL-228 + */ + public function testPrepareWithFetchAllBoth() + { + $paramInt = 1; + $paramStr = 'foo'; + + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $stmt = $this->_conn->prepare($sql); + $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); + + $stmt->bindParam(1, $paramInt); + $stmt->bindParam(2, $paramStr); + $stmt->execute(); + + $rows = $stmt->fetchAll(\PDO::FETCH_BOTH); + $rows[0] = array_change_key_case($rows[0], \CASE_LOWER); + $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo', 0 => 1, 1 => 'foo'), $rows[0]); + } + + public function testPrepareWithFetchColumn() + { + $paramInt = 1; + $paramStr = 'foo'; + + $sql = "SELECT test_int FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $stmt = $this->_conn->prepare($sql); + $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); + + $stmt->bindParam(1, $paramInt); + $stmt->bindParam(2, $paramStr); + $stmt->execute(); + + $column = $stmt->fetchColumn(); + $this->assertEquals(1, $column); + } + + public function testPrepareWithIterator() + { + $paramInt = 1; + $paramStr = 'foo'; + + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $stmt = $this->_conn->prepare($sql); + $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); + + $stmt->bindParam(1, $paramInt); + $stmt->bindParam(2, $paramStr); + $stmt->execute(); + + $rows = array(); + $stmt->setFetchMode(\PDO::FETCH_ASSOC); + foreach ($stmt as $row) { + $rows[] = array_change_key_case($row, \CASE_LOWER); + } + + $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $rows[0]); + } + + public function testPrepareWithQuoted() + { + $table = 'fetch_table'; + $paramInt = 1; + $paramStr = 'foo'; + + $sql = "SELECT test_int, test_string FROM " . $this->_conn->quoteIdentifier($table) . " ". + "WHERE test_int = " . $this->_conn->quote($paramInt) . " AND test_string = " . $this->_conn->quote($paramStr); + $stmt = $this->_conn->prepare($sql); + $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); + } + + public function testPrepareWithExecuteParams() + { + $paramInt = 1; + $paramStr = 'foo'; + + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $stmt = $this->_conn->prepare($sql); + $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt); + $stmt->execute(array($paramInt, $paramStr)); + + $row = $stmt->fetch(\PDO::FETCH_ASSOC); + $this->assertTrue($row !== false); + $row = array_change_key_case($row, \CASE_LOWER); + $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row); + } + + public function testFetchAll() + { + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $data = $this->_conn->fetchAll($sql, array(1, 'foo')); + + $this->assertEquals(1, count($data)); + + $row = $data[0]; + $this->assertEquals(2, count($row)); + + $row = array_change_key_case($row, \CASE_LOWER); + $this->assertEquals(1, $row['test_int']); + $this->assertEquals('foo', $row['test_string']); + } + + public function testFetchBoth() + { + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $row = $this->_conn->executeQuery($sql, array(1, 'foo'))->fetch(\PDO::FETCH_BOTH); + + $this->assertTrue($row !== false); + + $row = array_change_key_case($row, \CASE_LOWER); + + $this->assertEquals(1, $row['test_int']); + $this->assertEquals('foo', $row['test_string']); + $this->assertEquals(1, $row[0]); + $this->assertEquals('foo', $row[1]); + } + + public function testFetchRow() + { + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $row = $this->_conn->fetchAssoc($sql, array(1, 'foo')); + + $this->assertTrue($row !== false); + + $row = array_change_key_case($row, \CASE_LOWER); + + $this->assertEquals(1, $row['test_int']); + $this->assertEquals('foo', $row['test_string']); + } + + public function testFetchArray() + { + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $row = $this->_conn->fetchArray($sql, array(1, 'foo')); + + $this->assertEquals(1, $row[0]); + $this->assertEquals('foo', $row[1]); + } + + public function testFetchColumn() + { + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $testInt = $this->_conn->fetchColumn($sql, array(1, 'foo'), 0); + + $this->assertEquals(1, $testInt); + + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $testString = $this->_conn->fetchColumn($sql, array(1, 'foo'), 1); + + $this->assertEquals('foo', $testString); + } + + /** + * @group DDC-697 + */ + public function testExecuteQueryBindDateTimeType() + { + $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?'; + $stmt = $this->_conn->executeQuery($sql, + array(1 => new \DateTime('2010-01-01 10:10:10')), + array(1 => Type::DATETIME) + ); + + $this->assertEquals(1, $stmt->fetchColumn()); + } + + /** + * @group DDC-697 + */ + public function testExecuteUpdateBindDateTimeType() + { + $datetime = new \DateTime('2010-02-02 20:20:20'); + + $sql = 'INSERT INTO fetch_table (test_int, test_string, test_datetime) VALUES (?, ?, ?)'; + $affectedRows = $this->_conn->executeUpdate($sql, + array(1 => 50, 2 => 'foo', 3 => $datetime), + array(1 => PDO::PARAM_INT, 2 => PDO::PARAM_STR, 3 => Type::DATETIME) + ); + + $this->assertEquals(1, $affectedRows); + $this->assertEquals(1, $this->_conn->executeQuery( + 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?', + array(1 => $datetime), + array(1 => Type::DATETIME) + )->fetchColumn()); + } + + /** + * @group DDC-697 + */ + public function testPrepareQueryBindValueDateTimeType() + { + $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?'; + $stmt = $this->_conn->prepare($sql); + $stmt->bindValue(1, new \DateTime('2010-01-01 10:10:10'), Type::DATETIME); + $stmt->execute(); + + $this->assertEquals(1, $stmt->fetchColumn()); + } + + /** + * @group DBAL-78 + */ + public function testNativeArrayListSupport() + { + for ($i = 100; $i < 110; $i++) { + $this->_conn->insert('fetch_table', array('test_int' => $i, 'test_string' => 'foo' . $i, 'test_datetime' => '2010-01-01 10:10:10')); + } + + $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_int IN (?)', + array(array(100, 101, 102, 103, 104)), array(Connection::PARAM_INT_ARRAY)); + + $data = $stmt->fetchAll(PDO::FETCH_NUM); + $this->assertEquals(5, count($data)); + $this->assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data); + + $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_string IN (?)', + array(array('foo100', 'foo101', 'foo102', 'foo103', 'foo104')), array(Connection::PARAM_STR_ARRAY)); + + $data = $stmt->fetchAll(PDO::FETCH_NUM); + $this->assertEquals(5, count($data)); + $this->assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data); + } + + /** + * @group DDC-1014 + */ + public function testDateArithmetics() + { + $p = $this->_conn->getDatabasePlatform(); + $sql = 'SELECT '; + $sql .= $p->getDateDiffExpression('test_datetime', $p->getCurrentTimestampSQL()) .' AS diff, '; + $sql .= $p->getDateAddDaysExpression('test_datetime', 10) .' AS add_days, '; + $sql .= $p->getDateSubDaysExpression('test_datetime', 10) .' AS sub_days, '; + $sql .= $p->getDateAddMonthExpression('test_datetime', 2) .' AS add_month, '; + $sql .= $p->getDateSubMonthExpression('test_datetime', 2) .' AS sub_month '; + $sql .= 'FROM fetch_table'; + + $row = $this->_conn->fetchAssoc($sql); + $row = array_change_key_case($row, CASE_LOWER); + + $diff = floor( (strtotime('2010-01-01')-time()) / 3600 / 24); + $this->assertEquals($diff, (int)$row['diff'], "Date difference should be approx. ".$diff." days.", 1); + $this->assertEquals('2010-01-11', date('Y-m-d', strtotime($row['add_days'])), "Adding date should end up on 2010-01-11"); + $this->assertEquals('2009-12-22', date('Y-m-d', strtotime($row['sub_days'])), "Subtracting date should end up on 2009-12-22"); + $this->assertEquals('2010-03-01', date('Y-m-d', strtotime($row['add_month'])), "Adding month should end up on 2010-03-01"); + $this->assertEquals('2009-11-01', date('Y-m-d', strtotime($row['sub_month'])), "Adding month should end up on 2009-11-01"); + } + + public function testQuoteSQLInjection() + { + $sql = "SELECT * FROM fetch_table WHERE test_string = " . $this->_conn->quote("bar' OR '1'='1"); + $rows = $this->_conn->fetchAll($sql); + + $this->assertEquals(0, count($rows), "no result should be returned, otherwise SQL injection is possible"); + } + + /** + * @group DDC-1213 + */ + public function testBitComparisonExpressionSupport() + { + $this->_conn->executeQuery('DELETE FROM fetch_table')->execute(); + $platform = $this->_conn->getDatabasePlatform(); + $bitmap = array(); + + for ($i = 2; $i < 9; $i = $i + 2) { + $bitmap[$i] = array( + 'bit_or' => ($i | 2), + 'bit_and' => ($i & 2) + ); + $this->_conn->insert('fetch_table', array( + 'test_int' => $i, + 'test_string' => json_encode($bitmap[$i]), + 'test_datetime' => '2010-01-01 10:10:10' + )); + } + + $sql[] = 'SELECT '; + $sql[] = 'test_int, '; + $sql[] = 'test_string, '; + $sql[] = $platform->getBitOrComparisonExpression('test_int', 2) . ' AS bit_or, '; + $sql[] = $platform->getBitAndComparisonExpression('test_int', 2) . ' AS bit_and '; + $sql[] = 'FROM fetch_table'; + + $stmt = $this->_conn->executeQuery(implode(PHP_EOL, $sql)); + $data = $stmt->fetchAll(PDO::FETCH_ASSOC); + + + $this->assertEquals(4, count($data)); + $this->assertEquals(count($bitmap), count($data)); + foreach ($data as $row) { + $row = array_change_key_case($row, CASE_LOWER); + + $this->assertArrayHasKey('test_int', $row); + + $id = $row['test_int']; + + $this->assertArrayHasKey($id, $bitmap); + $this->assertArrayHasKey($id, $bitmap); + + $this->assertArrayHasKey('bit_or', $row); + $this->assertArrayHasKey('bit_and', $row); + + $this->assertEquals($row['bit_or'], $bitmap[$id]['bit_or']); + $this->assertEquals($row['bit_and'], $bitmap[$id]['bit_and']); + } + } + + public function testSetDefaultFetchMode() + { + $stmt = $this->_conn->query("SELECT * FROM fetch_table"); + $stmt->setFetchMode(\PDO::FETCH_NUM); + + $row = array_keys($stmt->fetch()); + $this->assertEquals(0, count( array_filter($row, function($v) { return ! is_numeric($v); })), "should be no non-numerical elements in the result."); + } + + /** + * @group DBAL-196 + */ + public function testFetchAllSupportFetchClass() + { + $this->skipOci8AndMysqli(); + $this->setupFixture(); + + $sql = "SELECT test_int, test_string, test_datetime FROM fetch_table"; + $stmt = $this->_conn->prepare($sql); + $stmt->execute(); + + $results = $stmt->fetchAll( + \PDO::FETCH_CLASS, + __NAMESPACE__.'\\MyFetchClass' + ); + + $this->assertEquals(1, count($results)); + $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]); + + $this->assertEquals(1, $results[0]->test_int); + $this->assertEquals('foo', $results[0]->test_string); + $this->assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime); + } + + /** + * @group DBAL-241 + */ + public function testFetchAllStyleColumn() + { + $sql = "DELETE FROM fetch_table"; + $this->_conn->executeUpdate($sql); + + $this->_conn->insert('fetch_table', array('test_int' => 1, 'test_string' => 'foo')); + $this->_conn->insert('fetch_table', array('test_int' => 10, 'test_string' => 'foo')); + + $sql = "SELECT test_int FROM fetch_table"; + $rows = $this->_conn->query($sql)->fetchAll(\PDO::FETCH_COLUMN); + + $this->assertEquals(array(1, 10), $rows); + } + + /** + * @group DBAL-214 + */ + public function testSetFetchModeClassFetchAll() + { + $this->skipOci8AndMysqli(); + $this->setupFixture(); + + $sql = "SELECT * FROM fetch_table"; + $stmt = $this->_conn->query($sql); + $stmt->setFetchMode(\PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array()); + + $results = $stmt->fetchAll(); + + $this->assertEquals(1, count($results)); + $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]); + + $this->assertEquals(1, $results[0]->test_int); + $this->assertEquals('foo', $results[0]->test_string); + $this->assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime); + } + + /** + * @group DBAL-214 + */ + public function testSetFetchModeClassFetch() + { + $this->skipOci8AndMysqli(); + $this->setupFixture(); + + $sql = "SELECT * FROM fetch_table"; + $stmt = $this->_conn->query($sql); + $stmt->setFetchMode(\PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array()); + + $results = array(); + while ($row = $stmt->fetch()) { + $results[] = $row; + } + + $this->assertEquals(1, count($results)); + $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]); + + $this->assertEquals(1, $results[0]->test_int); + $this->assertEquals('foo', $results[0]->test_string); + $this->assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime); + } + + /** + * @group DBAL-257 + */ + public function testEmptyFetchColumnReturnsFalse() + { + $this->_conn->executeQuery('DELETE FROM fetch_table')->execute(); + $this->assertFalse($this->_conn->fetchColumn('SELECT test_int FROM fetch_table')); + $this->assertFalse($this->_conn->query('SELECT test_int FROM fetch_table')->fetchColumn()); + } + + /** + * @group DBAL-339 + */ + public function testSetFetchModeOnDbalStatement() + { + $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?"; + $stmt = $this->_conn->executeQuery($sql, array(1, "foo")); + $stmt->setFetchMode(\PDO::FETCH_NUM); + + while ($row = $stmt->fetch()) { + $this->assertTrue(isset($row[0])); + $this->assertTrue(isset($row[1])); + } + } + + private function setupFixture() + { + $this->_conn->executeQuery('DELETE FROM fetch_table')->execute(); + $this->_conn->insert('fetch_table', array( + 'test_int' => 1, + 'test_string' => 'foo', + 'test_datetime' => '2010-01-01 10:10:10' + )); + } + + private function skipOci8AndMysqli() + { + if (isset($GLOBALS['db_type']) && $GLOBALS['db_type'] == "oci8") { + $this->markTestSkipped("Not supported by OCI8"); + } + if ('mysqli' == $this->_conn->getDriver()->getName()) { + $this->markTestSkipped('Mysqli driver dont support this feature.'); + } + } +} + +class MyFetchClass +{ + public $test_int, $test_string, $test_datetime; +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/LoggingTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/LoggingTest.php new file mode 100644 index 0000000..7c96813 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/LoggingTest.php @@ -0,0 +1,52 @@ +_conn->getDatabasePlatform()->getDummySelectSQL(); + + $logMock = $this->getMock('Doctrine\DBAL\Logging\SQLLogger'); + $logMock->expects($this->at(0)) + ->method('startQuery') + ->with($this->equalTo($sql), $this->equalTo(array()), $this->equalTo(array())); + $logMock->expects($this->at(1)) + ->method('stopQuery'); + $this->_conn->getConfiguration()->setSQLLogger($logMock); + $this->_conn->executeQuery($sql, array()); + } + + public function testLogExecuteUpdate() + { + $this->markTestSkipped('Test breaks MySQL but works on all other platforms (Unbuffered Queries stuff).'); + + $sql = $this->_conn->getDatabasePlatform()->getDummySelectSQL(); + + $logMock = $this->getMock('Doctrine\DBAL\Logging\SQLLogger'); + $logMock->expects($this->at(0)) + ->method('startQuery') + ->with($this->equalTo($sql), $this->equalTo(array()), $this->equalTo(array())); + $logMock->expects($this->at(1)) + ->method('stopQuery'); + $this->_conn->getConfiguration()->setSQLLogger($logMock); + $this->_conn->executeUpdate($sql, array()); + } + + public function testLogPrepareExecute() + { + $sql = $this->_conn->getDatabasePlatform()->getDummySelectSQL(); + + $logMock = $this->getMock('Doctrine\DBAL\Logging\SQLLogger'); + $logMock->expects($this->once()) + ->method('startQuery') + ->with($this->equalTo($sql), $this->equalTo(array())); + $logMock->expects($this->at(1)) + ->method('stopQuery'); + $this->_conn->getConfiguration()->setSQLLogger($logMock); + + $stmt = $this->_conn->prepare($sql); + $stmt->execute(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/MasterSlaveConnectionTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/MasterSlaveConnectionTest.php new file mode 100644 index 0000000..3317c6b --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/MasterSlaveConnectionTest.php @@ -0,0 +1,102 @@ +_conn->getDatabasePlatform()->getName() == "sqlite") { + $this->markTestSkipped('Test does not work on sqlite.'); + } + + try { + /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ + $table = new \Doctrine\DBAL\Schema\Table("master_slave_table"); + $table->addColumn('test_int', 'integer'); + $table->setPrimaryKey(array('test_int')); + + $sm = $this->_conn->getSchemaManager(); + $sm->createTable($table); + + $this->_conn->insert('master_slave_table', array('test_int' => 1)); + } catch(\Exception $e) { + } + } + + public function createMasterSlaveConnection($keepSlave = false) + { + $params = $this->_conn->getParams(); + $params['master'] = $params; + $params['slaves'] = array($params, $params); + $params['keepSlave'] = $keepSlave; + $params['wrapperClass'] = 'Doctrine\DBAL\Connections\MasterSlaveConnection'; + + return DriverManager::getConnection($params); + } + + public function testMasterOnConnect() + { + $conn = $this->createMasterSlaveConnection(); + + $this->assertFalse($conn->isConnectedToMaster()); + $conn->connect('slave'); + $this->assertFalse($conn->isConnectedToMaster()); + $conn->connect('master'); + $this->assertTrue($conn->isConnectedToMaster()); + } + + public function testNoMasterOnExecuteQuery() + { + $conn = $this->createMasterSlaveConnection(); + + $sql = "SELECT count(*) as num FROM master_slave_table"; + $data = $conn->fetchAll($sql); + $data[0] = array_change_key_case($data[0], CASE_LOWER); + + $this->assertEquals(1, $data[0]['num']); + $this->assertFalse($conn->isConnectedToMaster()); + } + + public function testMasterOnWriteOperation() + { + $conn = $this->createMasterSlaveConnection(); + $conn->insert('master_slave_table', array('test_int' => 30)); + + $this->assertTrue($conn->isConnectedToMaster()); + + $sql = "SELECT count(*) as num FROM master_slave_table"; + $data = $conn->fetchAll($sql); + $data[0] = array_change_key_case($data[0], CASE_LOWER); + + $this->assertEquals(2, $data[0]['num']); + $this->assertTrue($conn->isConnectedToMaster()); + } + + /** + * @group DBAL-335 + */ + public function testKeepSlaveBeginTransactionStaysOnMaster() + { + $conn = $this->createMasterSlaveConnection($keepSlave = true); + $conn->connect('slave'); + + $conn->insert('master_slave_table', array('test_int' => 40)); + + $this->assertTrue($conn->isConnectedToMaster()); + + $conn->connect(); + $this->assertTrue($conn->isConnectedToMaster()); + + $conn->connect('slave'); + $this->assertFalse($conn->isConnectedToMaster()); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php new file mode 100644 index 0000000..69ba6ac --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php @@ -0,0 +1,114 @@ +addColumn('test_int', 'integer'); + $table->setPrimaryKey(array('test_int')); + + $table2 = new \Doctrine\DBAL\Schema\Table("modify_limit_table2"); + $table2->addColumn('id', 'integer', array('autoincrement' => true)); + $table2->addColumn('test_int', 'integer'); + $table2->setPrimaryKey(array('id')); + + $sm = $this->_conn->getSchemaManager(); + $sm->createTable($table); + $sm->createTable($table2); + self::$tableCreated = true; + } + $this->_conn->exec($this->_conn->getDatabasePlatform()->getTruncateTableSQL('modify_limit_table')); + $this->_conn->exec($this->_conn->getDatabasePlatform()->getTruncateTableSQL('modify_limit_table2')); + } + + public function testModifyLimitQuerySimpleQuery() + { + $this->_conn->insert('modify_limit_table', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table', array('test_int' => 2)); + $this->_conn->insert('modify_limit_table', array('test_int' => 3)); + $this->_conn->insert('modify_limit_table', array('test_int' => 4)); + + $sql = "SELECT * FROM modify_limit_table"; + + $this->assertLimitResult(array(1, 2, 3, 4), $sql, 10, 0); + $this->assertLimitResult(array(1, 2), $sql, 2, 0); + $this->assertLimitResult(array(3, 4), $sql, 2, 2); + } + + public function testModifyLimitQueryJoinQuery() + { + $this->_conn->insert('modify_limit_table', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table', array('test_int' => 2)); + + $this->_conn->insert('modify_limit_table2', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table2', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table2', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table2', array('test_int' => 2)); + $this->_conn->insert('modify_limit_table2', array('test_int' => 2)); + + $sql = "SELECT modify_limit_table.test_int FROM modify_limit_table INNER JOIN modify_limit_table2 ON modify_limit_table.test_int = modify_limit_table2.test_int"; + + $this->assertLimitResult(array(1, 1, 1, 2, 2), $sql, 10, 0); + $this->assertLimitResult(array(1, 1, 1), $sql, 3, 0); + $this->assertLimitResult(array(2, 2), $sql, 2, 3); + } + + public function testModifyLimitQueryOrderBy() + { + $this->_conn->insert('modify_limit_table', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table', array('test_int' => 2)); + $this->_conn->insert('modify_limit_table', array('test_int' => 3)); + $this->_conn->insert('modify_limit_table', array('test_int' => 4)); + + $sql = "SELECT * FROM modify_limit_table ORDER BY test_int DESC"; + + $this->assertLimitResult(array(4, 3, 2, 1), $sql, 10, 0); + $this->assertLimitResult(array(4, 3), $sql, 2, 0); + $this->assertLimitResult(array(2, 1), $sql, 2, 2); + } + + public function testModifyLimitQueryGroupBy() + { + $this->_conn->insert('modify_limit_table', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table', array('test_int' => 2)); + + $this->_conn->insert('modify_limit_table2', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table2', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table2', array('test_int' => 1)); + $this->_conn->insert('modify_limit_table2', array('test_int' => 2)); + $this->_conn->insert('modify_limit_table2', array('test_int' => 2)); + + $sql = "SELECT modify_limit_table.test_int FROM modify_limit_table " . + "INNER JOIN modify_limit_table2 ON modify_limit_table.test_int = modify_limit_table2.test_int ". + "GROUP BY modify_limit_table.test_int"; + $this->assertLimitResult(array(1, 2), $sql, 10, 0); + $this->assertLimitResult(array(1), $sql, 1, 0); + $this->assertLimitResult(array(2), $sql, 1, 1); + } + + public function assertLimitResult($expectedResults, $sql, $limit, $offset) + { + $p = $this->_conn->getDatabasePlatform(); + $data = array(); + foreach ($this->_conn->fetchAll($p->modifyLimitQuery($sql, $limit, $offset)) AS $row) { + $row = array_change_key_case($row, CASE_LOWER); + $data[] = $row['test_int']; + } + $this->assertEquals($expectedResults, $data); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/NamedParametersTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/NamedParametersTest.php new file mode 100644 index 0000000..6f9e513 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/NamedParametersTest.php @@ -0,0 +1,166 @@ +1,'bar'=> array(1, 2, 3)), + array('foo'=>PDO::PARAM_INT,'bar'=> Connection::PARAM_INT_ARRAY,), + array( + array('id'=>1,'foo'=>1,'bar'=>1), + array('id'=>2,'foo'=>1,'bar'=>2), + array('id'=>3,'foo'=>1,'bar'=>3), + ) + ), + + array( + 'SELECT * FROM ddc1372_foobar f WHERE f.foo = :foo AND f.bar IN (:bar)', + array('foo'=>1,'bar'=> array(1, 2, 3)), + array('bar'=> Connection::PARAM_INT_ARRAY,'foo'=>PDO::PARAM_INT), + array( + array('id'=>1,'foo'=>1,'bar'=>1), + array('id'=>2,'foo'=>1,'bar'=>2), + array('id'=>3,'foo'=>1,'bar'=>3), + ) + ), + + array( + 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo = :foo', + array('foo'=>1,'bar'=> array(1, 2, 3)), + array('bar'=> Connection::PARAM_INT_ARRAY,'foo'=>PDO::PARAM_INT), + array( + array('id'=>1,'foo'=>1,'bar'=>1), + array('id'=>2,'foo'=>1,'bar'=>2), + array('id'=>3,'foo'=>1,'bar'=>3), + ) + ), + + array( + 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo = :foo', + array('foo'=>1,'bar'=> array('1', '2', '3')), + array('bar'=> Connection::PARAM_STR_ARRAY,'foo'=>PDO::PARAM_INT), + array( + array('id'=>1,'foo'=>1,'bar'=>1), + array('id'=>2,'foo'=>1,'bar'=>2), + array('id'=>3,'foo'=>1,'bar'=>3), + ) + ), + + array( + 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo IN (:foo)', + array('foo'=>array('1'),'bar'=> array(1, 2, 3,4)), + array('bar'=> Connection::PARAM_STR_ARRAY,'foo'=>Connection::PARAM_INT_ARRAY), + array( + array('id'=>1,'foo'=>1,'bar'=>1), + array('id'=>2,'foo'=>1,'bar'=>2), + array('id'=>3,'foo'=>1,'bar'=>3), + array('id'=>4,'foo'=>1,'bar'=>4), + ) + ), + + array( + 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo IN (:foo)', + array('foo'=>1,'bar'=> 2), + array('bar'=>PDO::PARAM_INT,'foo'=>PDO::PARAM_INT), + array( + array('id'=>2,'foo'=>1,'bar'=>2), + ) + ), + + array( + 'SELECT * FROM ddc1372_foobar f WHERE f.bar = :arg AND f.foo <> :arg', + array('arg'=>'1'), + array('arg'=>PDO::PARAM_STR), + array( + array('id'=>5,'foo'=>2,'bar'=>1), + ) + ), + + array( + 'SELECT * FROM ddc1372_foobar f WHERE f.bar NOT IN (:arg) AND f.foo IN (:arg)', + array('arg'=>array(1, 2)), + array('arg'=>Connection::PARAM_INT_ARRAY), + array( + array('id'=>3,'foo'=>1,'bar'=>3), + array('id'=>4,'foo'=>1,'bar'=>4), + ) + ), + + ); + } + + public function setUp() + { + parent::setUp(); + + if (!$this->_conn->getSchemaManager()->tablesExist("ddc1372_foobar")) { + try { + $table = new \Doctrine\DBAL\Schema\Table("ddc1372_foobar"); + $table->addColumn('id', 'integer'); + $table->addColumn('foo','string'); + $table->addColumn('bar','string'); + $table->setPrimaryKey(array('id')); + + + $sm = $this->_conn->getSchemaManager(); + $sm->createTable($table); + + $this->_conn->insert('ddc1372_foobar', array( + 'id' => 1, 'foo' => 1, 'bar' => 1 + )); + $this->_conn->insert('ddc1372_foobar', array( + 'id' => 2, 'foo' => 1, 'bar' => 2 + )); + $this->_conn->insert('ddc1372_foobar', array( + 'id' => 3, 'foo' => 1, 'bar' => 3 + )); + $this->_conn->insert('ddc1372_foobar', array( + 'id' => 4, 'foo' => 1, 'bar' => 4 + )); + $this->_conn->insert('ddc1372_foobar', array( + 'id' => 5, 'foo' => 2, 'bar' => 1 + )); + $this->_conn->insert('ddc1372_foobar', array( + 'id' => 6, 'foo' => 2, 'bar' => 2 + )); + } catch(\Exception $e) { + $this->fail($e->getMessage()); + } + } + } + + /** + * @dataProvider ticketProvider + * @param string $query + * @param array $params + * @param array $types + * @param array $expected + */ + public function testTicket($query,$params,$types,$expected) + { + $stmt = $this->_conn->executeQuery($query, $params, $types); + $result = $stmt->fetchAll(\PDO::FETCH_ASSOC); + + foreach ($result as $k => $v) { + $result[$k] = array_change_key_case($v, CASE_LOWER); + } + + $this->assertEquals($result, $expected); + } + +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/PortabilityTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/PortabilityTest.php new file mode 100644 index 0000000..acf995b --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/PortabilityTest.php @@ -0,0 +1,97 @@ +portableConnection) { + $this->portableConnection->close(); + } + } + + private function getPortableConnection($portabilityMode = \Doctrine\DBAL\Portability\Connection::PORTABILITY_ALL, $case = \PDO::CASE_LOWER) + { + if (!$this->portableConnection) { + $params = $this->_conn->getParams(); + $params['wrapperClass'] = 'Doctrine\DBAL\Portability\Connection'; + $params['portability'] = $portabilityMode; + $params['fetch_case'] = $case; + $this->portableConnection = DriverManager::getConnection($params, $this->_conn->getConfiguration(), $this->_conn->getEventManager()); + + try { + /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ + $table = new \Doctrine\DBAL\Schema\Table("portability_table"); + $table->addColumn('Test_Int', 'integer'); + $table->addColumn('Test_String', 'string', array('fixed' => true, 'length' => 32)); + $table->addColumn('Test_Null', 'string', array('notnull' => false)); + $table->setPrimaryKey(array('Test_Int')); + + $sm = $this->portableConnection->getSchemaManager(); + $sm->createTable($table); + + $this->portableConnection->insert('portability_table', array('Test_Int' => 1, 'Test_String' => 'foo', 'Test_Null' => '')); + $this->portableConnection->insert('portability_table', array('Test_Int' => 2, 'Test_String' => 'foo ', 'Test_Null' => null)); + } catch(\Exception $e) { + + } + } + + return $this->portableConnection; + } + + public function testFullFetchMode() + { + $rows = $this->getPortableConnection()->fetchAll('SELECT * FROM portability_table'); + $this->assertFetchResultRows($rows); + + $stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table'); + $stmt->setFetchMode(\PDO::FETCH_ASSOC); + foreach ($stmt as $row) { + $this->assertFetchResultRow($row); + } + + $stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table'); + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + $this->assertFetchResultRow($row); + } + + $stmt = $this->getPortableConnection()->prepare('SELECT * FROM portability_table'); + $stmt->execute(); + + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + $this->assertFetchResultRow($row); + } + } + + public function assertFetchResultRows($rows) + { + $this->assertEquals(2, count($rows)); + foreach ($rows AS $row) { + $this->assertFetchResultRow($row); + } + } + + public function assertFetchResultRow($row) + { + $this->assertTrue(in_array($row['test_int'], array(1, 2)), "Primary key test_int should either be 1 or 2."); + $this->assertArrayHasKey('test_string', $row, "Case should be lowered."); + $this->assertEquals(3, strlen($row['test_string']), "test_string should be rtrimed to length of three for CHAR(32) column."); + $this->assertNull($row['test_null']); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ResultCacheTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ResultCacheTest.php new file mode 100644 index 0000000..dc82911 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/ResultCacheTest.php @@ -0,0 +1,208 @@ + 100, 'test_string' => 'foo'), array('test_int' => 200, 'test_string' => 'bar'), array('test_int' => 300, 'test_string' => 'baz')); + private $sqlLogger; + + public function setUp() + { + parent::setUp(); + + try { + /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ + $table = new \Doctrine\DBAL\Schema\Table("caching"); + $table->addColumn('test_int', 'integer'); + $table->addColumn('test_string', 'string', array('notnull' => false)); + $table->setPrimaryKey(array('test_int')); + + $sm = $this->_conn->getSchemaManager(); + $sm->createTable($table); + } catch(\Exception $e) { + + } + $this->_conn->executeUpdate('DELETE FROM caching'); + foreach ($this->expectedResult AS $row) { + $this->_conn->insert('caching', $row); + } + + $config = $this->_conn->getConfiguration(); + $config->setSQLLogger($this->sqlLogger = new \Doctrine\DBAL\Logging\DebugStack); + + $cache = new \Doctrine\Common\Cache\ArrayCache; + $config->setResultCacheImpl($cache); + } + + public function testCacheFetchAssoc() + { + $this->assertCacheNonCacheSelectSameFetchModeAreEqual($this->expectedResult, \PDO::FETCH_ASSOC); + } + + public function testFetchNum() + { + $expectedResult = array(); + foreach ($this->expectedResult AS $v) { + $expectedResult[] = array_values($v); + } + $this->assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, \PDO::FETCH_NUM); + } + + public function testFetchBoth() + { + $expectedResult = array(); + foreach ($this->expectedResult AS $v) { + $expectedResult[] = array_merge($v, array_values($v)); + } + $this->assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, \PDO::FETCH_BOTH); + } + + public function testFetchColumn() + { + $expectedResult = array(); + foreach ($this->expectedResult AS $v) { + $expectedResult[] = array_shift($v); + } + $this->assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, \PDO::FETCH_COLUMN); + } + + public function testMixingFetch() + { + $numExpectedResult = array(); + foreach ($this->expectedResult AS $v) { + $numExpectedResult[] = array_values($v); + } + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + + $data = $this->hydrateStmt($stmt, \PDO::FETCH_ASSOC); + + $this->assertEquals($this->expectedResult, $data); + + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + + $data = $this->hydrateStmt($stmt, \PDO::FETCH_NUM); + + $this->assertEquals($numExpectedResult, $data); + } + + public function testIteratorFetch() + { + $this->assertStandardAndIteratorFetchAreEqual(\PDO::FETCH_BOTH); + $this->assertStandardAndIteratorFetchAreEqual(\PDO::FETCH_ASSOC); + $this->assertStandardAndIteratorFetchAreEqual(\PDO::FETCH_NUM); + } + + public function assertStandardAndIteratorFetchAreEqual($fetchMode) + { + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + $data = $this->hydrateStmt($stmt, $fetchMode); + + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + $data_iterator = $this->hydrateStmtIterator($stmt, $fetchMode); + + $this->assertEquals($data, $data_iterator); + } + + public function testDontCloseNoCache() + { + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + + $data = array(); + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + $data[] = $row; + } + + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + + $data = array(); + while ($row = $stmt->fetch(\PDO::FETCH_NUM)) { + $data[] = $row; + } + + $this->assertEquals(2, count($this->sqlLogger->queries)); + } + + public function testDontFinishNoCache() + { + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + + $row = $stmt->fetch(\PDO::FETCH_ASSOC); + $stmt->closeCursor(); + + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + + $data = $this->hydrateStmt($stmt, \PDO::FETCH_NUM); + + $this->assertEquals(2, count($this->sqlLogger->queries)); + } + + public function assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, $fetchMode) + { + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + + $this->assertEquals(2, $stmt->columnCount()); + $data = $this->hydrateStmt($stmt, $fetchMode); + $this->assertEquals($expectedResult, $data); + + $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey")); + + $this->assertEquals(2, $stmt->columnCount()); + $data = $this->hydrateStmt($stmt, $fetchMode); + $this->assertEquals($expectedResult, $data); + $this->assertEquals(1, count($this->sqlLogger->queries), "just one dbal hit"); + } + + public function testEmptyResultCache() + { + $stmt = $this->_conn->executeQuery("SELECT * FROM caching WHERE test_int > 500", array(), array(), new QueryCacheProfile(10, "emptycachekey")); + $data = $this->hydrateStmt($stmt); + + $stmt = $this->_conn->executeQuery("SELECT * FROM caching WHERE test_int > 500", array(), array(), new QueryCacheProfile(10, "emptycachekey")); + $data = $this->hydrateStmt($stmt); + + $this->assertEquals(1, count($this->sqlLogger->queries), "just one dbal hit"); + } + + public function testChangeCacheImpl() + { + $stmt = $this->_conn->executeQuery("SELECT * FROM caching WHERE test_int > 500", array(), array(), new QueryCacheProfile(10, "emptycachekey")); + $data = $this->hydrateStmt($stmt); + + $secondCache = new \Doctrine\Common\Cache\ArrayCache; + $stmt = $this->_conn->executeQuery("SELECT * FROM caching WHERE test_int > 500", array(), array(), new QueryCacheProfile(10, "emptycachekey", $secondCache)); + $data = $this->hydrateStmt($stmt); + + $this->assertEquals(2, count($this->sqlLogger->queries), "two hits"); + $this->assertEquals(1, count($secondCache->fetch("emptycachekey"))); + } + + private function hydrateStmt($stmt, $fetchMode = \PDO::FETCH_ASSOC) + { + $data = array(); + while ($row = $stmt->fetch($fetchMode)) { + $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row; + } + $stmt->closeCursor(); + return $data; + } + + private function hydrateStmtIterator($stmt, $fetchMode = \PDO::FETCH_ASSOC) + { + $data = array(); + $stmt->setFetchMode($fetchMode); + foreach ($stmt as $row) { + $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row; + } + $stmt->closeCursor(); + return $data; + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/Db2SchemaManagerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/Db2SchemaManagerTest.php new file mode 100644 index 0000000..a567900 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/Db2SchemaManagerTest.php @@ -0,0 +1,12 @@ +addColumn('foo_id', 'integer'); + $tableOld->addColumn('bar_id', 'integer'); + $tableNew = clone $tableOld; + + $this->_sm->createTable($tableOld); + $tableFetched = $this->_sm->listTableDetails("switch_primary_key_columns"); + $tableNew = clone $tableFetched; + $tableNew->setPrimaryKey(array('bar_id', 'foo_id')); + + $comparator = new \Doctrine\DBAL\Schema\Comparator; + $this->_sm->alterTable($comparator->diffTable($tableFetched, $tableNew)); + } + + public function testDiffTableBug() + { + $schema = new Schema(); + $table = $schema->createTable('diffbug_routing_translations'); + $table->addColumn('id', 'integer'); + $table->addColumn('route', 'string'); + $table->addColumn('locale', 'string'); + $table->addColumn('attribute', 'string'); + $table->addColumn('localized_value', 'string'); + $table->addColumn('original_value', 'string'); + $table->setPrimaryKey(array('id')); + $table->addUniqueIndex(array('route', 'locale', 'attribute')); + $table->addIndex(array('localized_value')); // this is much more selective than the unique index + + $this->_sm->createTable($table); + $tableFetched = $this->_sm->listTableDetails("diffbug_routing_translations"); + + $comparator = new \Doctrine\DBAL\Schema\Comparator; + $diff = $comparator->diffTable($tableFetched, $table); + + $this->assertFalse($diff, "no changes expected."); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php new file mode 100644 index 0000000..231b542 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php @@ -0,0 +1,39 @@ +markTestSkipped('Foo'); + } + + $username = $GLOBALS['db_username']; + + $query = "GRANT ALL PRIVILEGES TO ".$username; + + $conn = \Doctrine\Tests\TestUtil::getTempConnection(); + $conn->executeUpdate($query); + } + + public function testRenameTable() + { + $this->_sm->tryMethod('DropTable', 'list_tables_test'); + $this->_sm->tryMethod('DropTable', 'list_tables_test_new_name'); + + $this->createTestTable('list_tables_test'); + $this->_sm->renameTable('list_tables_test', 'list_tables_test_new_name'); + + $tables = $this->_sm->listTables(); + + $this->assertHasTable($tables, 'list_tables_test_new_name'); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php new file mode 100644 index 0000000..2cb9bd7 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php @@ -0,0 +1,262 @@ +_conn) { + return; + } + + $this->_conn->getConfiguration()->setFilterSchemaAssetsExpression(null); + } + + /** + * @group DBAL-177 + */ + public function testGetSearchPath() + { + $params = $this->_conn->getParams(); + + $paths = $this->_sm->getSchemaSearchPaths(); + $this->assertEquals(array($params['user'], 'public'), $paths); + } + + /** + * @group DBAL-244 + */ + public function testGetSchemaNames() + { + $names = $this->_sm->getSchemaNames(); + + $this->assertInternalType('array', $names); + $this->assertTrue(count($names) > 0); + $this->assertTrue(in_array('public', $names), "The public schema should be found."); + } + + /** + * @group DBAL-21 + */ + public function testSupportDomainTypeFallback() + { + $createDomainTypeSQL = "CREATE DOMAIN MyMoney AS DECIMAL(18,2)"; + $this->_conn->exec($createDomainTypeSQL); + + $createTableSQL = "CREATE TABLE domain_type_test (id INT PRIMARY KEY, value MyMoney)"; + $this->_conn->exec($createTableSQL); + + $table = $this->_conn->getSchemaManager()->listTableDetails('domain_type_test'); + $this->assertInstanceOf('Doctrine\DBAL\Types\DecimalType', $table->getColumn('value')->getType()); + + Type::addType('MyMoney', 'Doctrine\Tests\DBAL\Functional\Schema\MoneyType'); + $this->_conn->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'MyMoney'); + + $table = $this->_conn->getSchemaManager()->listTableDetails('domain_type_test'); + $this->assertInstanceOf('Doctrine\Tests\DBAL\Functional\Schema\MoneyType', $table->getColumn('value')->getType()); + } + + /** + * @group DBAL-37 + */ + public function testDetectsAutoIncrement() + { + $autoincTable = new \Doctrine\DBAL\Schema\Table('autoinc_table'); + $column = $autoincTable->addColumn('id', 'integer'); + $column->setAutoincrement(true); + $this->_sm->createTable($autoincTable); + $autoincTable = $this->_sm->listTableDetails('autoinc_table'); + + $this->assertTrue($autoincTable->getColumn('id')->getAutoincrement()); + } + + /** + * @group DBAL-37 + */ + public function testAlterTableAutoIncrementAdd() + { + $tableFrom = new \Doctrine\DBAL\Schema\Table('autoinc_table_add'); + $column = $tableFrom->addColumn('id', 'integer'); + $this->_sm->createTable($tableFrom); + $tableFrom = $this->_sm->listTableDetails('autoinc_table_add'); + $this->assertFalse($tableFrom->getColumn('id')->getAutoincrement()); + + $tableTo = new \Doctrine\DBAL\Schema\Table('autoinc_table_add'); + $column = $tableTo->addColumn('id', 'integer'); + $column->setAutoincrement(true); + + $c = new \Doctrine\DBAL\Schema\Comparator(); + $diff = $c->diffTable($tableFrom, $tableTo); + $sql = $this->_conn->getDatabasePlatform()->getAlterTableSQL($diff); + $this->assertEquals(array( + "CREATE SEQUENCE autoinc_table_add_id_seq", + "SELECT setval('autoinc_table_add_id_seq', (SELECT MAX(id) FROM autoinc_table_add))", + "ALTER TABLE autoinc_table_add ALTER id SET DEFAULT nextval('autoinc_table_add_id_seq')", + ), $sql); + + $this->_sm->alterTable($diff); + $tableFinal = $this->_sm->listTableDetails('autoinc_table_add'); + $this->assertTrue($tableFinal->getColumn('id')->getAutoincrement()); + } + + /** + * @group DBAL-37 + */ + public function testAlterTableAutoIncrementDrop() + { + $tableFrom = new \Doctrine\DBAL\Schema\Table('autoinc_table_drop'); + $column = $tableFrom->addColumn('id', 'integer'); + $column->setAutoincrement(true); + $this->_sm->createTable($tableFrom); + $tableFrom = $this->_sm->listTableDetails('autoinc_table_drop'); + $this->assertTrue($tableFrom->getColumn('id')->getAutoincrement()); + + $tableTo = new \Doctrine\DBAL\Schema\Table('autoinc_table_drop'); + $column = $tableTo->addColumn('id', 'integer'); + + $c = new \Doctrine\DBAL\Schema\Comparator(); + $diff = $c->diffTable($tableFrom, $tableTo); + $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $diff, "There should be a difference and not false being returned from the table comparison"); + $this->assertEquals(array("ALTER TABLE autoinc_table_drop ALTER id DROP DEFAULT"), $this->_conn->getDatabasePlatform()->getAlterTableSQL($diff)); + + $this->_sm->alterTable($diff); + $tableFinal = $this->_sm->listTableDetails('autoinc_table_drop'); + $this->assertFalse($tableFinal->getColumn('id')->getAutoincrement()); + } + + /** + * @group DBAL-75 + */ + public function testTableWithSchema() + { + $this->_conn->exec('CREATE SCHEMA nested'); + + $nestedRelatedTable = new \Doctrine\DBAL\Schema\Table('nested.schemarelated'); + $column = $nestedRelatedTable->addColumn('id', 'integer'); + $column->setAutoincrement(true); + $nestedRelatedTable->setPrimaryKey(array('id')); + + $nestedSchemaTable = new \Doctrine\DBAL\Schema\Table('nested.schematable'); + $column = $nestedSchemaTable->addColumn('id', 'integer'); + $column->setAutoincrement(true); + $nestedSchemaTable->setPrimaryKey(array('id')); + $nestedSchemaTable->addUnnamedForeignKeyConstraint($nestedRelatedTable, array('id'), array('id')); + + $this->_sm->createTable($nestedRelatedTable); + $this->_sm->createTable($nestedSchemaTable); + + $tables = $this->_sm->listTableNames(); + $this->assertContains('nested.schematable', $tables, "The table should be detected with its non-public schema."); + + $nestedSchemaTable = $this->_sm->listTableDetails('nested.schematable'); + $this->assertTrue($nestedSchemaTable->hasColumn('id')); + $this->assertEquals(array('id'), $nestedSchemaTable->getPrimaryKey()->getColumns()); + + $relatedFks = $nestedSchemaTable->getForeignKeys(); + $this->assertEquals(1, count($relatedFks)); + $relatedFk = array_pop($relatedFks); + $this->assertEquals("nested.schemarelated", $relatedFk->getForeignTableName()); + } + + /** + * @group DBAL-91 + * @group DBAL-88 + */ + public function testReturnQuotedAssets() + { + $sql = 'create table dbal91_something ( id integer CONSTRAINT id_something PRIMARY KEY NOT NULL ,"table" integer );'; + $this->_conn->exec($sql); + + $sql = 'ALTER TABLE dbal91_something ADD CONSTRAINT something_input FOREIGN KEY( "table" ) REFERENCES dbal91_something ON UPDATE CASCADE;'; + $this->_conn->exec($sql); + + $table = $this->_sm->listTableDetails('dbal91_something'); + + $this->assertEquals( + array( + "CREATE TABLE dbal91_something (id INT NOT NULL, \"table\" INT DEFAULT NULL, PRIMARY KEY(id))", + "CREATE INDEX IDX_A9401304ECA7352B ON dbal91_something (\"table\")", + ), + $this->_conn->getDatabasePlatform()->getCreateTableSQL($table) + ); + } + + /** + * @group DBAL-204 + */ + public function testFilterSchemaExpression() + { + $testTable = new \Doctrine\DBAL\Schema\Table('dbal204_test_prefix'); + $column = $testTable->addColumn('id', 'integer'); + $this->_sm->createTable($testTable); + $testTable = new \Doctrine\DBAL\Schema\Table('dbal204_without_prefix'); + $column = $testTable->addColumn('id', 'integer'); + $this->_sm->createTable($testTable); + + $this->_conn->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_#'); + $names = $this->_sm->listTableNames(); + $this->assertEquals(2, count($names)); + + $this->_conn->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_test#'); + $names = $this->_sm->listTableNames(); + $this->assertEquals(1, count($names)); + } + + public function testListForeignKeys() + { + if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped('Does not support foreign key constraints.'); + } + + $fkOptions = array('SET NULL', 'SET DEFAULT', 'NO ACTION','CASCADE', 'RESTRICT'); + $foreignKeys = array(); + $fkTable = $this->getTestTable('test_create_fk1'); + for($i = 0; $i < count($fkOptions); $i++) { + $fkTable->addColumn("foreign_key_test$i", 'integer'); + $foreignKeys[] = new \Doctrine\DBAL\Schema\ForeignKeyConstraint( + array("foreign_key_test$i"), 'test_create_fk2', array('id'), "foreign_key_test_$i"."_fk", array('onDelete' => $fkOptions[$i])); + } + $this->_sm->dropAndCreateTable($fkTable); + $this->createTestTable('test_create_fk2'); + + foreach($foreignKeys as $foreignKey) { + $this->_sm->createForeignKey($foreignKey, 'test_create_fk1'); + } + $fkeys = $this->_sm->listTableForeignKeys('test_create_fk1'); + $this->assertEquals(count($foreignKeys), count($fkeys), "Table 'test_create_fk1' has to have " . count($foreignKeys) . " foreign keys."); + for ($i = 0; $i < count($fkeys); $i++) { + $this->assertEquals(array("foreign_key_test$i"), array_map('strtolower', $fkeys[$i]->getLocalColumns())); + $this->assertEquals(array('id'), array_map('strtolower', $fkeys[$i]->getForeignColumns())); + $this->assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName())); + if ($foreignKeys[$i]->getOption('onDelete') == 'NO ACTION') { + $this->assertFalse($fkeys[$i]->hasOption('onDelete'), 'Unexpected option: '. $fkeys[$i]->getOption('onDelete')); + } else { + $this->assertEquals($foreignKeys[$i]->getOption('onDelete'), $fkeys[$i]->getOption('onDelete')); + } + } + } +} + +class MoneyType extends Type +{ + + public function getName() + { + return "MyMoney"; + } + + public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return 'MyMoney'; + } + +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLServerSchemaManagerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLServerSchemaManagerTest.php new file mode 100644 index 0000000..b6372b4 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLServerSchemaManagerTest.php @@ -0,0 +1,37 @@ +addColumn('id', 'integer'); + $table->addColumn('todrop', 'decimal', array('default' => 10.2)); + + $this->_sm->createTable($table); + + $diff = new TableDiff('sqlsrv_drop_column', array(), array(), array( + new Column('todrop', Type::getType('decimal')) + )); + $this->_sm->alterTable($diff); + + $columns = $this->_sm->listTableColumns('sqlsrv_drop_column'); + $this->assertEquals(1, count($columns)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php new file mode 100644 index 0000000..2f30c3c --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php @@ -0,0 +1,647 @@ +getPlatformName(); + + if ($this->_conn->getDatabasePlatform()->getName() !== $dbms) { + $this->markTestSkipped(get_class($this) . ' requires the use of ' . $dbms); + } + + $this->_sm = $this->_conn->getSchemaManager(); + } + + /** + * @group DBAL-195 + */ + public function testDropAndCreateSequence() + { + if(!$this->_conn->getDatabasePlatform()->supportsSequences()) { + $this->markTestSkipped($this->_conn->getDriver()->getName().' does not support sequences.'); + } + + $sequence = new \Doctrine\DBAL\Schema\Sequence('dropcreate_sequences_test_seq', 20, 10); + $this->_sm->dropAndCreateSequence($sequence); + } + + public function testListSequences() + { + if(!$this->_conn->getDatabasePlatform()->supportsSequences()) { + $this->markTestSkipped($this->_conn->getDriver()->getName().' does not support sequences.'); + } + + $sequence = new \Doctrine\DBAL\Schema\Sequence('list_sequences_test_seq', 20, 10); + $this->_sm->createSequence($sequence); + + $sequences = $this->_sm->listSequences(); + + $this->assertInternalType('array', $sequences, 'listSequences() should return an array.'); + + $foundSequence = null; + foreach($sequences AS $sequence) { + $this->assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $sequence, 'Array elements of listSequences() should be Sequence instances.'); + if(strtolower($sequence->getName()) == 'list_sequences_test_seq') { + $foundSequence = $sequence; + } + } + + $this->assertNotNull($foundSequence, "Sequence with name 'list_sequences_test_seq' was not found."); + $this->assertEquals(20, $foundSequence->getAllocationSize(), "Allocation Size is expected to be 20."); + $this->assertEquals(10, $foundSequence->getInitialValue(), "Initial Value is expected to be 10."); + } + + public function testListDatabases() + { + if (!$this->_sm->getDatabasePlatform()->supportsCreateDropDatabase()) { + $this->markTestSkipped('Cannot drop Database client side with this Driver.'); + } + + $this->_sm->dropAndCreateDatabase('test_create_database'); + $databases = $this->_sm->listDatabases(); + + $databases = \array_map('strtolower', $databases); + + $this->assertEquals(true, \in_array('test_create_database', $databases)); + } + + public function testListTables() + { + $this->createTestTable('list_tables_test'); + $tables = $this->_sm->listTables(); + + $this->assertInternalType('array', $tables); + $this->assertTrue(count($tables) > 0, "List Tables has to find at least one table named 'list_tables_test'."); + + $foundTable = false; + foreach ($tables AS $table) { + $this->assertInstanceOf('Doctrine\DBAL\Schema\Table', $table); + if (strtolower($table->getName()) == 'list_tables_test') { + $foundTable = true; + + $this->assertTrue($table->hasColumn('id')); + $this->assertTrue($table->hasColumn('test')); + $this->assertTrue($table->hasColumn('foreign_key_test')); + } + } + + $this->assertTrue( $foundTable , "The 'list_tables_test' table has to be found."); + } + + public function createListTableColumns() + { + $table = new \Doctrine\DBAL\Schema\Table('list_table_columns'); + $table->addColumn('id', 'integer', array('notnull' => true)); + $table->addColumn('test', 'string', array('length' => 255, 'notnull' => false, 'default' => 'expected default')); + $table->addColumn('foo', 'text', array('notnull' => true)); + $table->addColumn('bar', 'decimal', array('precision' => 10, 'scale' => 4, 'notnull' => false)); + $table->addColumn('baz1', 'datetime'); + $table->addColumn('baz2', 'time'); + $table->addColumn('baz3', 'date'); + $table->setPrimaryKey(array('id')); + + return $table; + } + + public function testListTableColumns() + { + $table = $this->createListTableColumns(); + + $this->_sm->dropAndCreateTable($table); + + $columns = $this->_sm->listTableColumns('list_table_columns'); + + $this->assertArrayHasKey('id', $columns); + $this->assertEquals('id', strtolower($columns['id']->getname())); + $this->assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns['id']->gettype()); + $this->assertEquals(false, $columns['id']->getunsigned()); + $this->assertEquals(true, $columns['id']->getnotnull()); + $this->assertEquals(null, $columns['id']->getdefault()); + $this->assertInternalType('array', $columns['id']->getPlatformOptions()); + + $this->assertArrayHasKey('test', $columns); + $this->assertEquals('test', strtolower($columns['test']->getname())); + $this->assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['test']->gettype()); + $this->assertEquals(255, $columns['test']->getlength()); + $this->assertEquals(false, $columns['test']->getfixed()); + $this->assertEquals(false, $columns['test']->getnotnull()); + $this->assertEquals('expected default', $columns['test']->getdefault()); + $this->assertInternalType('array', $columns['test']->getPlatformOptions()); + + $this->assertEquals('foo', strtolower($columns['foo']->getname())); + $this->assertInstanceOf('Doctrine\DBAL\Types\TextType', $columns['foo']->gettype()); + $this->assertEquals(false, $columns['foo']->getunsigned()); + $this->assertEquals(false, $columns['foo']->getfixed()); + $this->assertEquals(true, $columns['foo']->getnotnull()); + $this->assertEquals(null, $columns['foo']->getdefault()); + $this->assertInternalType('array', $columns['foo']->getPlatformOptions()); + + $this->assertEquals('bar', strtolower($columns['bar']->getname())); + $this->assertInstanceOf('Doctrine\DBAL\Types\DecimalType', $columns['bar']->gettype()); + $this->assertEquals(null, $columns['bar']->getlength()); + $this->assertEquals(10, $columns['bar']->getprecision()); + $this->assertEquals(4, $columns['bar']->getscale()); + $this->assertEquals(false, $columns['bar']->getunsigned()); + $this->assertEquals(false, $columns['bar']->getfixed()); + $this->assertEquals(false, $columns['bar']->getnotnull()); + $this->assertEquals(null, $columns['bar']->getdefault()); + $this->assertInternalType('array', $columns['bar']->getPlatformOptions()); + + $this->assertEquals('baz1', strtolower($columns['baz1']->getname())); + $this->assertInstanceOf('Doctrine\DBAL\Types\DateTimeType', $columns['baz1']->gettype()); + $this->assertEquals(true, $columns['baz1']->getnotnull()); + $this->assertEquals(null, $columns['baz1']->getdefault()); + $this->assertInternalType('array', $columns['baz1']->getPlatformOptions()); + + $this->assertEquals('baz2', strtolower($columns['baz2']->getname())); + $this->assertContains($columns['baz2']->gettype()->getName(), array('time', 'date', 'datetime')); + $this->assertEquals(true, $columns['baz2']->getnotnull()); + $this->assertEquals(null, $columns['baz2']->getdefault()); + $this->assertInternalType('array', $columns['baz2']->getPlatformOptions()); + + $this->assertEquals('baz3', strtolower($columns['baz3']->getname())); + $this->assertContains($columns['baz2']->gettype()->getName(), array('time', 'date', 'datetime')); + $this->assertEquals(true, $columns['baz3']->getnotnull()); + $this->assertEquals(null, $columns['baz3']->getdefault()); + $this->assertInternalType('array', $columns['baz3']->getPlatformOptions()); + } + + public function testListTableColumnsDispatchEvent() + { + $table = $this->createListTableColumns(); + + $this->_sm->dropAndCreateTable($table); + + $listenerMock = $this->getMock('ListTableColumnsDispatchEventListener', array('onSchemaColumnDefinition')); + $listenerMock + ->expects($this->exactly(7)) + ->method('onSchemaColumnDefinition'); + + $oldEventManager = $this->_sm->getDatabasePlatform()->getEventManager(); + + $eventManager = new EventManager(); + $eventManager->addEventListener(array(Events::onSchemaColumnDefinition), $listenerMock); + + $this->_sm->getDatabasePlatform()->setEventManager($eventManager); + + $this->_sm->listTableColumns('list_table_columns'); + + $this->_sm->getDatabasePlatform()->setEventManager($oldEventManager); + } + + public function testListTableIndexesDispatchEvent() + { + $table = $this->getTestTable('list_table_indexes_test'); + $table->addUniqueIndex(array('test'), 'test_index_name'); + $table->addIndex(array('id', 'test'), 'test_composite_idx'); + + $this->_sm->dropAndCreateTable($table); + + $listenerMock = $this->getMock('ListTableIndexesDispatchEventListener', array('onSchemaIndexDefinition')); + $listenerMock + ->expects($this->exactly(3)) + ->method('onSchemaIndexDefinition'); + + $oldEventManager = $this->_sm->getDatabasePlatform()->getEventManager(); + + $eventManager = new EventManager(); + $eventManager->addEventListener(array(Events::onSchemaIndexDefinition), $listenerMock); + + $this->_sm->getDatabasePlatform()->setEventManager($eventManager); + + $this->_sm->listTableIndexes('list_table_indexes_test'); + + $this->_sm->getDatabasePlatform()->setEventManager($oldEventManager); + } + + public function testDiffListTableColumns() + { + if ($this->_sm->getDatabasePlatform()->getName() == 'oracle') { + $this->markTestSkipped('Does not work with Oracle, since it cannot detect DateTime, Date and Time differenecs (at the moment).'); + } + + $offlineTable = $this->createListTableColumns(); + $onlineTable = $this->_sm->listTableDetails('list_table_columns'); + + $comparator = new \Doctrine\DBAL\Schema\Comparator(); + $diff = $comparator->diffTable($offlineTable, $onlineTable); + + $this->assertFalse($diff, "No differences should be detected with the offline vs online schema."); + } + + public function testListTableIndexes() + { + $table = $this->getTestCompositeTable('list_table_indexes_test'); + $table->addUniqueIndex(array('test'), 'test_index_name'); + $table->addIndex(array('id', 'test'), 'test_composite_idx'); + + $this->_sm->dropAndCreateTable($table); + + $tableIndexes = $this->_sm->listTableIndexes('list_table_indexes_test'); + + $this->assertEquals(3, count($tableIndexes)); + + $this->assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.'); + $this->assertEquals(array('id', 'other_id'), array_map('strtolower', $tableIndexes['primary']->getColumns())); + $this->assertTrue($tableIndexes['primary']->isUnique()); + $this->assertTrue($tableIndexes['primary']->isPrimary()); + + $this->assertEquals('test_index_name', $tableIndexes['test_index_name']->getName()); + $this->assertEquals(array('test'), array_map('strtolower', $tableIndexes['test_index_name']->getColumns())); + $this->assertTrue($tableIndexes['test_index_name']->isUnique()); + $this->assertFalse($tableIndexes['test_index_name']->isPrimary()); + + $this->assertEquals('test_composite_idx', $tableIndexes['test_composite_idx']->getName()); + $this->assertEquals(array('id', 'test'), array_map('strtolower', $tableIndexes['test_composite_idx']->getColumns())); + $this->assertFalse($tableIndexes['test_composite_idx']->isUnique()); + $this->assertFalse($tableIndexes['test_composite_idx']->isPrimary()); + } + + public function testDropAndCreateIndex() + { + $table = $this->getTestTable('test_create_index'); + $table->addUniqueIndex(array('test'), 'test'); + $this->_sm->dropAndCreateTable($table); + + $this->_sm->dropAndCreateIndex($table->getIndex('test'), $table); + $tableIndexes = $this->_sm->listTableIndexes('test_create_index'); + $this->assertInternalType('array', $tableIndexes); + + $this->assertEquals('test', strtolower($tableIndexes['test']->getName())); + $this->assertEquals(array('test'), array_map('strtolower', $tableIndexes['test']->getColumns())); + $this->assertTrue($tableIndexes['test']->isUnique()); + $this->assertFalse($tableIndexes['test']->isPrimary()); + } + + public function testCreateTableWithForeignKeys() + { + if(!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped('Platform does not support foreign keys.'); + } + + $tableB = $this->getTestTable('test_foreign'); + + $this->_sm->dropAndCreateTable($tableB); + + $tableA = $this->getTestTable('test_create_fk'); + $tableA->addForeignKeyConstraint('test_foreign', array('foreign_key_test'), array('id')); + + $this->_sm->dropAndCreateTable($tableA); + + $fkTable = $this->_sm->listTableDetails('test_create_fk'); + $fkConstraints = $fkTable->getForeignKeys(); + $this->assertEquals(1, count($fkConstraints), "Table 'test_create_fk1' has to have one foreign key."); + + $fkConstraint = current($fkConstraints); + $this->assertInstanceOf('\Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkConstraint); + $this->assertEquals('test_foreign', strtolower($fkConstraint->getForeignTableName())); + $this->assertEquals(array('foreign_key_test'), array_map('strtolower', $fkConstraint->getColumns())); + $this->assertEquals(array('id'), array_map('strtolower', $fkConstraint->getForeignColumns())); + + $this->assertTrue($fkTable->columnsAreIndexed($fkConstraint->getColumns()), "The columns of a foreign key constraint should always be indexed."); + } + + public function testListForeignKeys() + { + if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped('Does not support foreign key constraints.'); + } + + $this->createTestTable('test_create_fk1'); + $this->createTestTable('test_create_fk2'); + + $foreignKey = new \Doctrine\DBAL\Schema\ForeignKeyConstraint( + array('foreign_key_test'), 'test_create_fk2', array('id'), 'foreign_key_test_fk', array('onDelete' => 'CASCADE') + ); + + $this->_sm->createForeignKey($foreignKey, 'test_create_fk1'); + + $fkeys = $this->_sm->listTableForeignKeys('test_create_fk1'); + + $this->assertEquals(1, count($fkeys), "Table 'test_create_fk1' has to have one foreign key."); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]); + $this->assertEquals(array('foreign_key_test'), array_map('strtolower', $fkeys[0]->getLocalColumns())); + $this->assertEquals(array('id'), array_map('strtolower', $fkeys[0]->getForeignColumns())); + $this->assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName())); + + if($fkeys[0]->hasOption('onDelete')) { + $this->assertEquals('CASCADE', $fkeys[0]->getOption('onDelete')); + } + } + + protected function getCreateExampleViewSql() + { + $this->markTestSkipped('No Create Example View SQL was defined for this SchemaManager'); + } + + public function testCreateSchema() + { + $this->createTestTable('test_table'); + + $schema = $this->_sm->createSchema(); + $this->assertTrue($schema->hasTable('test_table')); + } + + public function testAlterTableScenario() + { + if(!$this->_sm->getDatabasePlatform()->supportsAlterTable()) { + $this->markTestSkipped('Alter Table is not supported by this platform.'); + } + + $this->createTestTable('alter_table'); + $this->createTestTable('alter_table_foreign'); + + $table = $this->_sm->listTableDetails('alter_table'); + $this->assertTrue($table->hasColumn('id')); + $this->assertTrue($table->hasColumn('test')); + $this->assertTrue($table->hasColumn('foreign_key_test')); + $this->assertEquals(0, count($table->getForeignKeys())); + $this->assertEquals(1, count($table->getIndexes())); + + $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); + $tableDiff->addedColumns['foo'] = new \Doctrine\DBAL\Schema\Column('foo', Type::getType('integer')); + $tableDiff->removedColumns['test'] = $table->getColumn('test'); + + $this->_sm->alterTable($tableDiff); + + $table = $this->_sm->listTableDetails('alter_table'); + $this->assertFalse($table->hasColumn('test')); + $this->assertTrue($table->hasColumn('foo')); + + $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); + $tableDiff->addedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo')); + + $this->_sm->alterTable($tableDiff); + + $table = $this->_sm->listTableDetails('alter_table'); + $this->assertEquals(2, count($table->getIndexes())); + $this->assertTrue($table->hasIndex('foo_idx')); + $this->assertEquals(array('foo'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns())); + $this->assertFalse($table->getIndex('foo_idx')->isPrimary()); + $this->assertFalse($table->getIndex('foo_idx')->isUnique()); + + $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); + $tableDiff->changedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test')); + + $this->_sm->alterTable($tableDiff); + + $table = $this->_sm->listTableDetails('alter_table'); + $this->assertEquals(2, count($table->getIndexes())); + $this->assertTrue($table->hasIndex('foo_idx')); + $this->assertEquals(array('foo', 'foreign_key_test'), array_map('strtolower', $table->getIndex('foo_idx')->getColumns())); + + $tableDiff = new \Doctrine\DBAL\Schema\TableDiff("alter_table"); + $tableDiff->removedIndexes[] = new \Doctrine\DBAL\Schema\Index('foo_idx', array('foo', 'foreign_key_test')); + $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('foreign_key_test'), 'alter_table_foreign', array('id')); + $tableDiff->addedForeignKeys[] = $fk; + + $this->_sm->alterTable($tableDiff); + $table = $this->_sm->listTableDetails('alter_table'); + + // dont check for index size here, some platforms automatically add indexes for foreign keys. + $this->assertFalse($table->hasIndex('foo_idx')); + + $this->assertEquals(1, count($table->getForeignKeys())); + $fks = $table->getForeignKeys(); + $foreignKey = current($fks); + $this->assertEquals('alter_table_foreign', strtolower($foreignKey->getForeignTableName())); + $this->assertEquals(array('foreign_key_test'), array_map('strtolower', $foreignKey->getColumns())); + $this->assertEquals(array('id'), array_map('strtolower', $foreignKey->getForeignColumns())); + } + + public function testCreateAndListViews() + { + if (!$this->_sm->getDatabasePlatform()->supportsViews()) { + $this->markTestSkipped('Views is not supported by this platform.'); + } + + $this->createTestTable('view_test_table'); + + $name = "doctrine_test_view"; + $sql = "SELECT * FROM view_test_table"; + + $view = new \Doctrine\DBAL\Schema\View($name, $sql); + + $this->_sm->dropAndCreateView($view); + + $views = $this->_sm->listViews(); + } + + public function testAutoincrementDetection() + { + if (!$this->_sm->getDatabasePlatform()->supportsIdentityColumns()) { + $this->markTestSkipped('This test is only supported on platforms that have autoincrement'); + } + + $table = new \Doctrine\DBAL\Schema\Table('test_autoincrement'); + $table->setSchemaConfig($this->_sm->createSchemaConfig()); + $table->addColumn('id', 'integer', array('autoincrement' => true)); + $table->setPrimaryKey(array('id')); + + $this->_sm->createTable($table); + + $inferredTable = $this->_sm->listTableDetails('test_autoincrement'); + $this->assertTrue($inferredTable->hasColumn('id')); + $this->assertTrue($inferredTable->getColumn('id')->getAutoincrement()); + } + + /** + * @group DDC-887 + */ + public function testUpdateSchemaWithForeignKeyRenaming() + { + if (!$this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped('This test is only supported on platforms that have foreign keys.'); + } + + $table = new \Doctrine\DBAL\Schema\Table('test_fk_base'); + $table->addColumn('id', 'integer'); + $table->setPrimaryKey(array('id')); + + $tableFK = new \Doctrine\DBAL\Schema\Table('test_fk_rename'); + $tableFK->setSchemaConfig($this->_sm->createSchemaConfig()); + $tableFK->addColumn('id', 'integer'); + $tableFK->addColumn('fk_id', 'integer'); + $tableFK->setPrimaryKey(array('id')); + $tableFK->addIndex(array('fk_id'), 'fk_idx'); + $tableFK->addForeignKeyConstraint('test_fk_base', array('fk_id'), array('id')); + + $this->_sm->createTable($table); + $this->_sm->createTable($tableFK); + + $tableFKNew = new \Doctrine\DBAL\Schema\Table('test_fk_rename'); + $tableFKNew->setSchemaConfig($this->_sm->createSchemaConfig()); + $tableFKNew->addColumn('id', 'integer'); + $tableFKNew->addColumn('rename_fk_id', 'integer'); + $tableFKNew->setPrimaryKey(array('id')); + $tableFKNew->addIndex(array('rename_fk_id'), 'fk_idx'); + $tableFKNew->addForeignKeyConstraint('test_fk_base', array('rename_fk_id'), array('id')); + + $c = new \Doctrine\DBAL\Schema\Comparator(); + $tableDiff = $c->diffTable($tableFK, $tableFKNew); + + $this->_sm->alterTable($tableDiff); + } + + /** + * @group DBAL-42 + */ + public function testGetColumnComment() + { + if (!$this->_conn->getDatabasePlatform()->supportsInlineColumnComments() && !$this->_conn->getDatabasePlatform()->supportsCommentOnStatement()) { + $this->markTestSkipped('Database does not support column comments.'); + } + + $table = new \Doctrine\DBAL\Schema\Table('column_comment_test'); + $table->addColumn('id', 'integer', array('comment' => 'This is a comment')); + $table->setPrimaryKey(array('id')); + + $this->_sm->createTable($table); + + $columns = $this->_sm->listTableColumns("column_comment_test"); + $this->assertEquals(1, count($columns)); + $this->assertEquals('This is a comment', $columns['id']->getComment()); + } + + /** + * @group DBAL-42 + */ + public function testAutomaticallyAppendCommentOnMarkedColumns() + { + if (!$this->_conn->getDatabasePlatform()->supportsInlineColumnComments() && !$this->_conn->getDatabasePlatform()->supportsCommentOnStatement()) { + $this->markTestSkipped('Database does not support column comments.'); + } + + $table = new \Doctrine\DBAL\Schema\Table('column_comment_test2'); + $table->addColumn('id', 'integer', array('comment' => 'This is a comment')); + $table->addColumn('obj', 'object', array('comment' => 'This is a comment')); + $table->addColumn('arr', 'array', array('comment' => 'This is a comment')); + $table->setPrimaryKey(array('id')); + + $this->_sm->createTable($table); + + $columns = $this->_sm->listTableColumns("column_comment_test2"); + $this->assertEquals(3, count($columns)); + $this->assertEquals('This is a comment', $columns['id']->getComment()); + $this->assertEquals('This is a comment', $columns['obj']->getComment(), "The Doctrine2 Typehint should be stripped from comment."); + $this->assertInstanceOf('Doctrine\DBAL\Types\ObjectType', $columns['obj']->getType(), "The Doctrine2 should be detected from comment hint."); + $this->assertEquals('This is a comment', $columns['arr']->getComment(), "The Doctrine2 Typehint should be stripped from comment."); + $this->assertInstanceOf('Doctrine\DBAL\Types\ArrayType', $columns['arr']->getType(), "The Doctrine2 should be detected from comment hint."); + } + + /** + * @group DBAL-197 + */ + public function testListTableWithBlob() + { + $table = new \Doctrine\DBAL\Schema\Table('test_blob_table'); + $table->addColumn('id', 'integer', array('comment' => 'This is a comment')); + $table->addColumn('binarydata', 'blob', array()); + $table->setPrimaryKey(array('id')); + + $this->_sm->createTable($table); + $blobTable = $this->_sm->listTableDetails('test_blob_table'); + } + + /** + * @param string $name + * @param array $data + */ + protected function createTestTable($name = 'test_table', $data = array()) + { + $options = array(); + if (isset($data['options'])) { + $options = $data['options']; + } + + $table = $this->getTestTable($name, $options); + + $this->_sm->dropAndCreateTable($table); + } + + protected function getTestTable($name, $options=array()) + { + $table = new \Doctrine\DBAL\Schema\Table($name, array(), array(), array(), false, $options); + $table->setSchemaConfig($this->_sm->createSchemaConfig()); + $table->addColumn('id', 'integer', array('notnull' => true)); + $table->setPrimaryKey(array('id')); + $table->addColumn('test', 'string', array('length' => 255)); + $table->addColumn('foreign_key_test', 'integer'); + return $table; + } + + protected function getTestCompositeTable($name) + { + $table = new \Doctrine\DBAL\Schema\Table($name, array(), array(), array(), false, array()); + $table->setSchemaConfig($this->_sm->createSchemaConfig()); + $table->addColumn('id', 'integer', array('notnull' => true)); + $table->addColumn('other_id', 'integer', array('notnull' => true)); + $table->setPrimaryKey(array('id', 'other_id')); + $table->addColumn('test', 'string', array('length' => 255)); + return $table; + } + + protected function assertHasTable($tables, $tableName) + { + $foundTable = false; + foreach ($tables AS $table) { + $this->assertInstanceOf('Doctrine\DBAL\Schema\Table', $table, 'No Table instance was found in tables array.'); + if (strtolower($table->getName()) == 'list_tables_test_new_name') { + $foundTable = true; + } + } + $this->assertTrue($foundTable, "Could not find new table"); + } + + public function testListForeignKeysComposite() + { + if(!$this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped('Does not support foreign key constraints.'); + } + + $this->_sm->createTable($this->getTestTable('test_create_fk3')); + $this->_sm->createTable($this->getTestCompositeTable('test_create_fk4')); + + $foreignKey = new \Doctrine\DBAL\Schema\ForeignKeyConstraint( + array('id', 'foreign_key_test'), 'test_create_fk4', array('id', 'other_id'), 'foreign_key_test_fk' + ); + + $this->_sm->createForeignKey($foreignKey, 'test_create_fk3'); + + $fkeys = $this->_sm->listTableForeignKeys('test_create_fk3'); + + $this->assertEquals(1, count($fkeys), "Table 'test_create_fk3' has to have one foreign key."); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]); + $this->assertEquals(array('id', 'foreign_key_test'), array_map('strtolower', $fkeys[0]->getLocalColumns())); + $this->assertEquals(array('id', 'other_id'), array_map('strtolower', $fkeys[0]->getForeignColumns())); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php new file mode 100644 index 0000000..2dccb51 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php @@ -0,0 +1,46 @@ +_sm->listDatabases(); + } + + public function testCreateAndDropDatabase() + { + $path = dirname(__FILE__).'/test_create_and_drop_sqlite_database.sqlite'; + + $this->_sm->createDatabase($path); + $this->assertEquals(true, file_exists($path)); + $this->_sm->dropDatabase($path); + $this->assertEquals(false, file_exists($path)); + } + + /** + * @expectedException \Doctrine\DBAL\DBALException + */ + public function testRenameTable() + { + $this->_sm->renameTable('oldname', 'newname'); + } + + public function testAutoincrementDetection() + { + $this->markTestSkipped( + 'There is currently no reliable way to determine whether an SQLite column is marked as ' + . 'auto-increment. So, while it does support a single identity column, we cannot with ' + . 'certainty determine which it is.'); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php new file mode 100644 index 0000000..ea9ac53 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php @@ -0,0 +1,59 @@ +_conn->getDatabasePlatform(); + if ($platform->getName() == "sqlite") { + $this->markTestSkipped('TableGenerator does not work with SQLite'); + } + + try { + $schema = new \Doctrine\DBAL\Schema\Schema(); + $visitor = new \Doctrine\DBAL\Id\TableGeneratorSchemaVisitor(); + $schema->visit($visitor); + + foreach ($schema->toSql($platform) as $sql) { + $this->_conn->exec($sql); + } + + } catch(\Exception $e) { + } + $this->generator = new TableGenerator($this->_conn); + } + + public function testNextVal() + { + $id1 = $this->generator->nextValue("tbl1"); + $id2 = $this->generator->nextValue("tbl1"); + $id3 = $this->generator->nextValue("tbl2"); + + $this->assertTrue($id1 > 0, "First id has to be larger than 0"); + $this->assertEquals($id1 + 1, $id2, "Second id is one larger than first one."); + $this->assertEquals($id1, $id3, "First ids from different tables are equal."); + } + + public function testNextValNotAffectedByOuterTransactions() + { + $this->_conn->beginTransaction(); + $id1 = $this->generator->nextValue("tbl1"); + $this->_conn->rollBack(); + $id2 = $this->generator->nextValue("tbl1"); + + $this->assertTrue($id1 > 0, "First id has to be larger than 0"); + $this->assertEquals($id1 + 1, $id2, "Second id is one larger than first one."); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TemporaryTableTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TemporaryTableTest.php new file mode 100644 index 0000000..9fa92c7 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TemporaryTableTest.php @@ -0,0 +1,102 @@ +_conn->exec($this->_conn->getDatabasePlatform()->getDropTableSQL("nontemporary")); + } catch(\Exception $e) { + + } + } + + public function tearDown() + { + if ($this->_conn) { + try { + $tempTable = $this->_conn->getDatabasePlatform()->getTemporaryTableName("temporary"); + $this->_conn->exec($this->_conn->getDatabasePlatform()->getDropTemporaryTableSQL($tempTable)); + } catch(\Exception $e) { } + } + } + + /** + * @group DDC-1337 + * @return void + */ + public function testDropTemporaryTableNotAutoCommitTransaction() + { + $platform = $this->_conn->getDatabasePlatform(); + $columnDefinitions = array("id" => array("type" => Type::getType("integer"), "notnull" => true)); + $tempTable = $platform->getTemporaryTableName("temporary"); + + $createTempTableSQL = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' + . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; + $this->_conn->executeUpdate($createTempTableSQL); + + $table = new Table("nontemporary"); + $table->addColumn("id", "integer"); + $table->setPrimaryKey(array('id')); + + foreach ($platform->getCreateTableSQL($table) AS $sql) { + $this->_conn->executeQuery($sql); + } + + $this->_conn->beginTransaction(); + $this->_conn->insert("nontemporary", array("id" => 1)); + $this->_conn->exec($platform->getDropTemporaryTableSQL($tempTable)); + $this->_conn->insert("nontemporary", array("id" => 2)); + + $this->_conn->rollback(); + + $rows = $this->_conn->fetchAll('SELECT * FROM nontemporary'); + $this->assertEquals(array(), $rows, "In an event of an error this result has one row, because of an implicit commit."); + } + + /** + * @group DDC-1337 + * @return void + */ + public function testCreateTemporaryTableNotAutoCommitTransaction() + { + $platform = $this->_conn->getDatabasePlatform(); + $columnDefinitions = array("id" => array("type" => Type::getType("integer"), "notnull" => true)); + $tempTable = $platform->getTemporaryTableName("temporary"); + + $createTempTableSQL = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' + . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; + + $table = new Table("nontemporary"); + $table->addColumn("id", "integer"); + $table->setPrimaryKey(array('id')); + + foreach ($platform->getCreateTableSQL($table) AS $sql) { + $this->_conn->executeQuery($sql); + } + + $this->_conn->beginTransaction(); + $this->_conn->insert("nontemporary", array("id" => 1)); + + $this->_conn->exec($createTempTableSQL); + $this->_conn->insert("nontemporary", array("id" => 2)); + + $this->_conn->rollback(); + + try { + $this->_conn->exec($platform->getDropTemporaryTableSQL($tempTable)); + } catch(\Exception $e) { + + } + + $rows = $this->_conn->fetchAll('SELECT * FROM nontemporary'); + $this->assertEquals(array(), $rows, "In an event of an error this result has one row, because of an implicit commit."); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL168Test.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL168Test.php new file mode 100644 index 0000000..1393404 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL168Test.php @@ -0,0 +1,27 @@ +_conn->getDatabasePlatform()->getName() != "postgresql") { + $this->markTestSkipped('PostgreSQL only test'); + } + + $table = new \Doctrine\DBAL\Schema\Table("domains"); + $table->addColumn('id', 'integer'); + $table->addColumn('parent_id', 'integer'); + $table->setPrimaryKey(array('id')); + $table->addForeignKeyConstraint('domains', array('parent_id'), array('id')); + + $this->_conn->getSchemaManager()->createTable($table); + $table = $this->_conn->getSchemaManager()->listTableDetails('domains'); + + $this->assertEquals('domains', $table->getName()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL202Test.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL202Test.php new file mode 100644 index 0000000..4448ed7 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL202Test.php @@ -0,0 +1,48 @@ +_conn->getDatabasePlatform()->getName() != 'oracle') { + $this->markTestSkipped('OCI8 only test'); + } + + if ($this->_conn->getSchemaManager()->tablesExist('DBAL202')) { + $this->_conn->executeQuery('DELETE FROM DBAL202'); + } else { + $table = new \Doctrine\DBAL\Schema\Table('DBAL202'); + $table->addColumn('id', 'integer'); + $table->setPrimaryKey(array('id')); + + $this->_conn->getSchemaManager()->createTable($table); + } + } + + public function testStatementRollback() + { + $stmt = $this->_conn->prepare('INSERT INTO DBAL202 VALUES (8)'); + $this->_conn->beginTransaction(); + $stmt->execute(); + $this->_conn->rollback(); + + $this->assertEquals(0, $this->_conn->query('SELECT COUNT(1) FROM DBAL202')->fetchColumn()); + } + + public function testStatementCommit() + { + $stmt = $this->_conn->prepare('INSERT INTO DBAL202 VALUES (8)'); + $this->_conn->beginTransaction(); + $stmt->execute(); + $this->_conn->commit(); + + $this->assertEquals(1, $this->_conn->query('SELECT COUNT(1) FROM DBAL202')->fetchColumn()); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TypeConversionTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TypeConversionTest.php new file mode 100644 index 0000000..67e6dda --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/TypeConversionTest.php @@ -0,0 +1,101 @@ +_conn->getSchemaManager(); + + $table = new \Doctrine\DBAL\Schema\Table("type_conversion"); + $table->addColumn('id', 'integer', array('notnull' => false)); + $table->addColumn('test_string', 'string', array('notnull' => false)); + $table->addColumn('test_boolean', 'boolean', array('notnull' => false)); + $table->addColumn('test_bigint', 'bigint', array('notnull' => false)); + $table->addColumn('test_smallint', 'bigint', array('notnull' => false)); + $table->addColumn('test_datetime', 'datetime', array('notnull' => false)); + $table->addColumn('test_datetimetz', 'datetimetz', array('notnull' => false)); + $table->addColumn('test_date', 'date', array('notnull' => false)); + $table->addColumn('test_time', 'time', array('notnull' => false)); + $table->addColumn('test_text', 'text', array('notnull' => false)); + $table->addColumn('test_array', 'array', array('notnull' => false)); + $table->addColumn('test_object', 'object', array('notnull' => false)); + $table->addColumn('test_float', 'float', array('notnull' => false)); + $table->addColumn('test_decimal', 'decimal', array('notnull' => false, 'scale' => 2, 'precision' => 10)); + $table->setPrimaryKey(array('id')); + + try { + foreach ($this->_conn->getDatabasePlatform()->getCreateTableSQL($table) AS $sql) { + $this->_conn->executeQuery($sql); + } + } catch(\Exception $e) { + + } + } + + static public function dataIdempotentDataConversion() + { + $obj = new \stdClass(); + $obj->foo = "bar"; + $obj->bar = "baz"; + + return array( + array('string', 'ABCDEFGaaaBBB', 'string'), + array('boolean', true, 'bool'), + array('boolean', false, 'bool'), + array('bigint', 12345678, 'string'), + array('smallint', 123, 'int'), + array('datetime', new \DateTime('2010-04-05 10:10:10'), 'DateTime'), + array('datetimetz', new \DateTime('2010-04-05 10:10:10'), 'DateTime'), + array('date', new \DateTime('2010-04-05'), 'DateTime'), + array('time', new \DateTime('10:10:10'), 'DateTime'), + array('text', str_repeat('foo ', 1000), 'string'), + array('array', array('foo' => 'bar'), 'array'), + array('object', $obj, 'object'), + array('float', 1.5, 'float'), + array('decimal', 1.55, 'string'), + ); + } + + /** + * @dataProvider dataIdempotentDataConversion + * @param string $type + * @param mixed $originalValue + * @param string $expectedPhpType + */ + public function testIdempotentDataConversion($type, $originalValue, $expectedPhpType) + { + $columnName = "test_" . $type; + $typeInstance = Type::getType($type); + $insertionValue = $typeInstance->convertToDatabaseValue($originalValue, $this->_conn->getDatabasePlatform()); + + $this->_conn->insert('type_conversion', array('id' => ++self::$typeCounter, $columnName => $insertionValue)); + + $sql = "SELECT " . $columnName . " FROM type_conversion WHERE id = " . self::$typeCounter; + $actualDbValue = $typeInstance->convertToPHPValue($this->_conn->fetchColumn($sql), $this->_conn->getDatabasePlatform()); + + if ($originalValue instanceof \DateTime) { + $this->assertInstanceOf($expectedPhpType, $actualDbValue, "The expected type from the conversion to and back from the database should be " . $expectedPhpType); + } else { + $this->assertInternalType($expectedPhpType, $actualDbValue, "The expected type from the conversion to and back from the database should be " . $expectedPhpType); + } + + if ($type !== "datetimetz") { + $this->assertEquals($originalValue, $actualDbValue, "Conversion between values should produce the same out as in value, but doesnt!"); + + if ($originalValue instanceof \DateTime) { + $this->assertEquals($originalValue->getTimezone()->getName(), $actualDbValue->getTimezone()->getName(), "Timezones should be the same."); + } + } + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php new file mode 100644 index 0000000..f1a3a59 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php @@ -0,0 +1,185 @@ +addColumn('id', 'integer', array('autoincrement' => true)); + $table->addColumn('test_int', 'integer'); + $table->addColumn('test_string', 'string', array('notnull' => false)); + $table->setPrimaryKey(array('id')); + + foreach ($this->_conn->getDatabasePlatform()->getCreateTableSQL($table) AS $sql) { + $this->_conn->executeQuery($sql); + } + } catch(\Exception $e) { + + } + $this->_conn->executeUpdate('DELETE FROM write_table'); + } + + /** + * @group DBAL-80 + */ + public function testExecuteUpdateFirstTypeIsNull() + { + $sql = "INSERT INTO write_table (test_string, test_int) VALUES (?, ?)"; + $this->_conn->executeUpdate($sql, array("text", 1111), array(null, PDO::PARAM_INT)); + + $sql = "SELECT * FROM write_table WHERE test_string = ? AND test_int = ?"; + $this->assertTrue((bool)$this->_conn->fetchColumn($sql, array("text", 1111))); + } + + public function testExecuteUpdate() + { + $sql = "INSERT INTO write_table (test_int) VALUES ( " . $this->_conn->quote(1) . ")"; + $affected = $this->_conn->executeUpdate($sql); + + $this->assertEquals(1, $affected, "executeUpdate() should return the number of affected rows!"); + } + + public function testExecuteUpdateWithTypes() + { + $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)"; + $affected = $this->_conn->executeUpdate($sql, array(1, 'foo'), array(\PDO::PARAM_INT, \PDO::PARAM_STR)); + + $this->assertEquals(1, $affected, "executeUpdate() should return the number of affected rows!"); + } + + public function testPrepareRowCountReturnsAffectedRows() + { + $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)"; + $stmt = $this->_conn->prepare($sql); + + $stmt->bindValue(1, 1); + $stmt->bindValue(2, "foo"); + $stmt->execute(); + + $this->assertEquals(1, $stmt->rowCount()); + } + + public function testPrepareWithPdoTypes() + { + $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)"; + $stmt = $this->_conn->prepare($sql); + + $stmt->bindValue(1, 1, \PDO::PARAM_INT); + $stmt->bindValue(2, "foo", \PDO::PARAM_STR); + $stmt->execute(); + + $this->assertEquals(1, $stmt->rowCount()); + } + + public function testPrepareWithDbalTypes() + { + $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)"; + $stmt = $this->_conn->prepare($sql); + + $stmt->bindValue(1, 1, Type::getType('integer')); + $stmt->bindValue(2, "foo", Type::getType('string')); + $stmt->execute(); + + $this->assertEquals(1, $stmt->rowCount()); + } + + public function testPrepareWithDbalTypeNames() + { + $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)"; + $stmt = $this->_conn->prepare($sql); + + $stmt->bindValue(1, 1, 'integer'); + $stmt->bindValue(2, "foo", 'string'); + $stmt->execute(); + + $this->assertEquals(1, $stmt->rowCount()); + } + + public function insertRows() + { + $this->assertEquals(1, $this->_conn->insert('write_table', array('test_int' => 1, 'test_string' => 'foo'))); + $this->assertEquals(1, $this->_conn->insert('write_table', array('test_int' => 2, 'test_string' => 'bar'))); + } + + public function testInsert() + { + $this->insertRows(); + } + + public function testDelete() + { + $this->insertRows(); + + $this->assertEquals(1, $this->_conn->delete('write_table', array('test_int' => 2))); + $this->assertEquals(1, count($this->_conn->fetchAll('SELECT * FROM write_table'))); + + $this->assertEquals(1, $this->_conn->delete('write_table', array('test_int' => 1))); + $this->assertEquals(0, count($this->_conn->fetchAll('SELECT * FROM write_table'))); + } + + public function testUpdate() + { + $this->insertRows(); + + $this->assertEquals(1, $this->_conn->update('write_table', array('test_string' => 'bar'), array('test_string' => 'foo'))); + $this->assertEquals(2, $this->_conn->update('write_table', array('test_string' => 'baz'), array('test_string' => 'bar'))); + $this->assertEquals(0, $this->_conn->update('write_table', array('test_string' => 'baz'), array('test_string' => 'bar'))); + } + + public function testLastInsertId() + { + if ( ! $this->_conn->getDatabasePlatform()->prefersIdentityColumns()) { + $this->markTestSkipped('Test only works on platforms with identity columns.'); + } + + $this->assertEquals(1, $this->_conn->insert('write_table', array('test_int' => 2, 'test_string' => 'bar'))); + $num = $this->_conn->lastInsertId(); + + $this->assertNotNull($num, "LastInsertId() should not be null."); + $this->assertTrue($num > 0, "LastInsertId() should be non-negative number."); + } + + public function testLastInsertIdSequence() + { + if ( ! $this->_conn->getDatabasePlatform()->supportsSequences()) { + $this->markTestSkipped('Test only works on platforms with sequences.'); + } + + $sequence = new \Doctrine\DBAL\Schema\Sequence('write_table_id_seq'); + try { + $this->_conn->getSchemaManager()->createSequence($sequence); + } catch(\Exception $e) { + } + + $sequences = $this->_conn->getSchemaManager()->listSequences(); + $this->assertEquals(1, count(array_filter($sequences, function($sequence) { + return $sequence->getName() === 'write_table_id_seq'; + }))); + + $stmt = $this->_conn->query($this->_conn->getDatabasePlatform()->getSequenceNextValSQL('write_table_id_seq')); + $nextSequenceVal = $stmt->fetchColumn(); + + $lastInsertId = $this->_conn->lastInsertId('write_table_id_seq'); + + $this->assertTrue($lastInsertId > 0); + $this->assertEquals($nextSequenceVal, $lastInsertId); + } + + public function testLastInsertIdNoSequenceGiven() + { + if ( ! $this->_conn->getDatabasePlatform()->supportsSequences()) { + $this->markTestSkipped('Test only works on platforms with sequences.'); + } + + $this->assertFalse($this->_conn->lastInsertId( null )); + + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php new file mode 100644 index 0000000..00bc0b6 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php @@ -0,0 +1,47 @@ +logger = new \Doctrine\DBAL\Logging\DebugStack(); + } + + public function tearDown() + { + unset($this->logger); + } + + public function testLoggedQuery() + { + $this->logger->startQuery('SELECT column FROM table'); + $this->assertEquals( + array( + 1 => array( + 'sql' => 'SELECT column FROM table', + 'params' => null, + 'types' => null, + 'executionMS' => 0, + ), + ), + $this->logger->queries + ); + + $this->logger->stopQuery(); + $this->assertGreaterThan(0, $this->logger->queries[1]['executionMS']); + } + + public function testLoggedQueryDisabled() + { + $this->logger->enabled = false; + $this->logger->startQuery('SELECT column FROM table'); + $this->assertEquals(array(), $this->logger->queries); + + $this->logger->stopQuery(); + $this->assertEquals(array(), $this->logger->queries); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Mocks/MockPlatform.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Mocks/MockPlatform.php new file mode 100644 index 0000000..576430c --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Mocks/MockPlatform.php @@ -0,0 +1,49 @@ +_platform = $this->createPlatform(); + } + + /** + * @group DDC-1360 + */ + public function testQuoteIdentifier() + { + if ($this->_platform->getName() == "mssql") { + $this->markTestSkipped('Not working this way on mssql.'); + } + + $c = $this->_platform->getIdentifierQuoteCharacter(); + $this->assertEquals($c."test".$c, $this->_platform->quoteIdentifier("test")); + $this->assertEquals($c."test".$c.".".$c."test".$c, $this->_platform->quoteIdentifier("test.test")); + $this->assertEquals(str_repeat($c, 4), $this->_platform->quoteIdentifier($c)); + } + + /** + * @group DDC-1360 + */ + public function testQuoteSingleIdentifier() + { + if ($this->_platform->getName() == "mssql") { + $this->markTestSkipped('Not working this way on mssql.'); + } + + $c = $this->_platform->getIdentifierQuoteCharacter(); + $this->assertEquals($c."test".$c, $this->_platform->quoteSingleIdentifier("test")); + $this->assertEquals($c."test.test".$c, $this->_platform->quoteSingleIdentifier("test.test")); + $this->assertEquals(str_repeat($c, 4), $this->_platform->quoteSingleIdentifier($c)); + } + + public function testGetInvalidtForeignKeyReferentialActionSQL() + { + $this->setExpectedException('InvalidArgumentException'); + $this->_platform->getForeignKeyReferentialActionSQL('unknown'); + } + + public function testGetUnknownDoctrineMappingType() + { + $this->setExpectedException('Doctrine\DBAL\DBALException'); + $this->_platform->getDoctrineTypeMapping('foobar'); + } + + public function testRegisterDoctrineMappingType() + { + $this->_platform->registerDoctrineTypeMapping('foo', 'integer'); + $this->assertEquals('integer', $this->_platform->getDoctrineTypeMapping('foo')); + } + + public function testRegisterUnknownDoctrineMappingType() + { + $this->setExpectedException('Doctrine\DBAL\DBALException'); + $this->_platform->registerDoctrineTypeMapping('foo', 'bar'); + } + + public function testCreateWithNoColumns() + { + $table = new \Doctrine\DBAL\Schema\Table('test'); + + $this->setExpectedException('Doctrine\DBAL\DBALException'); + $sql = $this->_platform->getCreateTableSQL($table); + } + + public function testGeneratesTableCreationSql() + { + $table = new \Doctrine\DBAL\Schema\Table('test'); + $table->addColumn('id', 'integer', array('notnull' => true, 'autoincrement' => true)); + $table->addColumn('test', 'string', array('notnull' => false, 'length' => 255)); + $table->setPrimaryKey(array('id')); + + $sql = $this->_platform->getCreateTableSQL($table); + $this->assertEquals($this->getGenerateTableSql(), $sql[0]); + } + + abstract public function getGenerateTableSql(); + + public function testGenerateTableWithMultiColumnUniqueIndex() + { + $table = new \Doctrine\DBAL\Schema\Table('test'); + $table->addColumn('foo', 'string', array('notnull' => false, 'length' => 255)); + $table->addColumn('bar', 'string', array('notnull' => false, 'length' => 255)); + $table->addUniqueIndex(array("foo", "bar")); + + $sql = $this->_platform->getCreateTableSQL($table); + $this->assertEquals($this->getGenerateTableWithMultiColumnUniqueIndexSql(), $sql); + } + + abstract public function getGenerateTableWithMultiColumnUniqueIndexSql(); + + public function testGeneratesIndexCreationSql() + { + $indexDef = new \Doctrine\DBAL\Schema\Index('my_idx', array('user_name', 'last_login')); + + $this->assertEquals( + $this->getGenerateIndexSql(), + $this->_platform->getCreateIndexSQL($indexDef, 'mytable') + ); + } + + abstract public function getGenerateIndexSql(); + + public function testGeneratesUniqueIndexCreationSql() + { + $indexDef = new \Doctrine\DBAL\Schema\Index('index_name', array('test', 'test2'), true); + + $sql = $this->_platform->getCreateIndexSQL($indexDef, 'test'); + $this->assertEquals($this->getGenerateUniqueIndexSql(), $sql); + } + + abstract public function getGenerateUniqueIndexSql(); + + public function testGeneratesForeignKeyCreationSql() + { + $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('fk_name_id'), 'other_table', array('id'), ''); + + $sql = $this->_platform->getCreateForeignKeySQL($fk, 'test'); + $this->assertEquals($sql, $this->getGenerateForeignKeySql()); + } + + abstract public function getGenerateForeignKeySql(); + + public function testGeneratesConstraintCreationSql() + { + $idx = new \Doctrine\DBAL\Schema\Index('constraint_name', array('test'), true, false); + $sql = $this->_platform->getCreateConstraintSQL($idx, 'test'); + $this->assertEquals($this->getGenerateConstraintUniqueIndexSql(), $sql); + + $pk = new \Doctrine\DBAL\Schema\Index('constraint_name', array('test'), true, true); + $sql = $this->_platform->getCreateConstraintSQL($pk, 'test'); + $this->assertEquals($this->getGenerateConstraintPrimaryIndexSql(), $sql); + + $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('fk_name'), 'foreign', array('id'), 'constraint_fk'); + $sql = $this->_platform->getCreateConstraintSQL($fk, 'test'); + $this->assertEquals($this->getGenerateConstraintForeignKeySql(), $sql); + } + + protected function getBitAndComparisonExpressionSql($value1, $value2) + { + return '(' . $value1 . ' & ' . $value2 . ')'; + } + + /** + * @group DDC-1213 + */ + public function testGeneratesBitAndComparisonExpressionSql() + { + $sql = $this->_platform->getBitAndComparisonExpression(2, 4); + $this->assertEquals($this->getBitAndComparisonExpressionSql(2, 4), $sql); + } + + protected function getBitOrComparisonExpressionSql($value1, $value2) + { + return '(' . $value1 . ' | ' . $value2 . ')'; + } + + /** + * @group DDC-1213 + */ + public function testGeneratesBitOrComparisonExpressionSql() + { + $sql = $this->_platform->getBitOrComparisonExpression(2, 4); + $this->assertEquals($this->getBitOrComparisonExpressionSql(2, 4), $sql); + } + + public function getGenerateConstraintUniqueIndexSql() + { + return 'ALTER TABLE test ADD CONSTRAINT constraint_name UNIQUE (test)'; + } + + public function getGenerateConstraintPrimaryIndexSql() + { + return 'ALTER TABLE test ADD CONSTRAINT constraint_name PRIMARY KEY (test)'; + } + + public function getGenerateConstraintForeignKeySql() + { + return 'ALTER TABLE test ADD CONSTRAINT constraint_fk FOREIGN KEY (fk_name) REFERENCES foreign (id)'; + } + + abstract public function getGenerateAlterTableSql(); + + public function testGeneratesTableAlterationSql() + { + $expectedSql = $this->getGenerateAlterTableSql(); + + $tableDiff = new \Doctrine\DBAL\Schema\TableDiff('mytable'); + $tableDiff->newName = 'userlist'; + $tableDiff->addedColumns['quota'] = new \Doctrine\DBAL\Schema\Column('quota', \Doctrine\DBAL\Types\Type::getType('integer'), array('notnull' => false)); + $tableDiff->removedColumns['foo'] = new \Doctrine\DBAL\Schema\Column('foo', \Doctrine\DBAL\Types\Type::getType('integer')); + $tableDiff->changedColumns['bar'] = new \Doctrine\DBAL\Schema\ColumnDiff( + 'bar', new \Doctrine\DBAL\Schema\Column( + 'baz', \Doctrine\DBAL\Types\Type::getType('string'), array('default' => 'def') + ), + array('type', 'notnull', 'default') + ); + $tableDiff->changedColumns['bloo'] = new \Doctrine\DBAL\Schema\ColumnDiff( + 'bloo', new \Doctrine\DBAL\Schema\Column( + 'bloo', \Doctrine\DBAL\Types\Type::getType('boolean'), array('default' => false) + ), + array('type', 'notnull', 'default') + ); + + $sql = $this->_platform->getAlterTableSQL($tableDiff); + + $this->assertEquals($expectedSql, $sql); + } + + public function testGetCustomColumnDeclarationSql() + { + $field = array('columnDefinition' => 'MEDIUMINT(6) UNSIGNED'); + $this->assertEquals('foo MEDIUMINT(6) UNSIGNED', $this->_platform->getColumnDeclarationSQL('foo', $field)); + } + + public function testGetCreateTableSqlDispatchEvent() + { + $listenerMock = $this->getMock('GetCreateTableSqlDispatchEvenListener', array('onSchemaCreateTable', 'onSchemaCreateTableColumn')); + $listenerMock + ->expects($this->once()) + ->method('onSchemaCreateTable'); + $listenerMock + ->expects($this->exactly(2)) + ->method('onSchemaCreateTableColumn'); + + $eventManager = new EventManager(); + $eventManager->addEventListener(array(Events::onSchemaCreateTable, Events::onSchemaCreateTableColumn), $listenerMock); + + $this->_platform->setEventManager($eventManager); + + $table = new \Doctrine\DBAL\Schema\Table('test'); + $table->addColumn('foo', 'string', array('notnull' => false, 'length' => 255)); + $table->addColumn('bar', 'string', array('notnull' => false, 'length' => 255)); + + $this->_platform->getCreateTableSQL($table); + } + + public function testGetDropTableSqlDispatchEvent() + { + $listenerMock = $this->getMock('GetDropTableSqlDispatchEventListener', array('onSchemaDropTable')); + $listenerMock + ->expects($this->once()) + ->method('onSchemaDropTable'); + + $eventManager = new EventManager(); + $eventManager->addEventListener(array(Events::onSchemaDropTable), $listenerMock); + + $this->_platform->setEventManager($eventManager); + + $this->_platform->getDropTableSQL('TABLE'); + } + + public function testGetAlterTableSqlDispatchEvent() + { + $events = array( + 'onSchemaAlterTable', + 'onSchemaAlterTableAddColumn', + 'onSchemaAlterTableRemoveColumn', + 'onSchemaAlterTableChangeColumn', + 'onSchemaAlterTableRenameColumn' + ); + + $listenerMock = $this->getMock('GetAlterTableSqlDispatchEvenListener', $events); + $listenerMock + ->expects($this->once()) + ->method('onSchemaAlterTable'); + $listenerMock + ->expects($this->once()) + ->method('onSchemaAlterTableAddColumn'); + $listenerMock + ->expects($this->once()) + ->method('onSchemaAlterTableRemoveColumn'); + $listenerMock + ->expects($this->once()) + ->method('onSchemaAlterTableChangeColumn'); + $listenerMock + ->expects($this->once()) + ->method('onSchemaAlterTableRenameColumn'); + + $eventManager = new EventManager(); + $events = array( + Events::onSchemaAlterTable, + Events::onSchemaAlterTableAddColumn, + Events::onSchemaAlterTableRemoveColumn, + Events::onSchemaAlterTableChangeColumn, + Events::onSchemaAlterTableRenameColumn + ); + $eventManager->addEventListener($events, $listenerMock); + + $this->_platform->setEventManager($eventManager); + + $tableDiff = new \Doctrine\DBAL\Schema\TableDiff('mytable'); + $tableDiff->addedColumns['added'] = new \Doctrine\DBAL\Schema\Column('added', \Doctrine\DBAL\Types\Type::getType('integer'), array()); + $tableDiff->removedColumns['removed'] = new \Doctrine\DBAL\Schema\Column('removed', \Doctrine\DBAL\Types\Type::getType('integer'), array()); + $tableDiff->changedColumns['changed'] = new \Doctrine\DBAL\Schema\ColumnDiff( + 'changed', new \Doctrine\DBAL\Schema\Column( + 'changed2', \Doctrine\DBAL\Types\Type::getType('string'), array() + ), + array() + ); + $tableDiff->renamedColumns['renamed'] = new \Doctrine\DBAL\Schema\Column('renamed2', \Doctrine\DBAL\Types\Type::getType('integer'), array()); + + $this->_platform->getAlterTableSQL($tableDiff); + } + + /** + * @group DBAL-42 + */ + public function testCreateTableColumnComments() + { + $table = new \Doctrine\DBAL\Schema\Table('test'); + $table->addColumn('id', 'integer', array('comment' => 'This is a comment')); + $table->setPrimaryKey(array('id')); + + $this->assertEquals($this->getCreateTableColumnCommentsSQL(), $this->_platform->getCreateTableSQL($table)); + } + + /** + * @group DBAL-42 + */ + public function testAlterTableColumnComments() + { + $tableDiff = new \Doctrine\DBAL\Schema\TableDiff('mytable'); + $tableDiff->addedColumns['quota'] = new \Doctrine\DBAL\Schema\Column('quota', \Doctrine\DBAL\Types\Type::getType('integer'), array('comment' => 'A comment')); + $tableDiff->changedColumns['bar'] = new \Doctrine\DBAL\Schema\ColumnDiff( + 'bar', new \Doctrine\DBAL\Schema\Column( + 'baz', \Doctrine\DBAL\Types\Type::getType('string'), array('comment' => 'B comment') + ), + array('comment') + ); + + $this->assertEquals($this->getAlterTableColumnCommentsSQL(), $this->_platform->getAlterTableSQL($tableDiff)); + } + + public function testCreateTableColumnTypeComments() + { + $table = new \Doctrine\DBAL\Schema\Table('test'); + $table->addColumn('id', 'integer'); + $table->addColumn('data', 'array'); + $table->setPrimaryKey(array('id')); + + $this->assertEquals($this->getCreateTableColumnTypeCommentsSQL(), $this->_platform->getCreateTableSQL($table)); + } + + public function getCreateTableColumnCommentsSQL() + { + $this->markTestSkipped('Platform does not support Column comments.'); + } + + public function getAlterTableColumnCommentsSQL() + { + $this->markTestSkipped('Platform does not support Column comments.'); + } + + public function getCreateTableColumnTypeCommentsSQL() + { + $this->markTestSkipped('Platform does not support Column comments.'); + } + + /** + * @group DBAL-45 + */ + public function testKeywordList() + { + $keywordList = $this->_platform->getReservedKeywordsList(); + $this->assertInstanceOf('Doctrine\DBAL\Platforms\Keywords\KeywordList', $keywordList); + + $this->assertTrue($keywordList->isKeyword('table')); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php new file mode 100644 index 0000000..4702d4b --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php @@ -0,0 +1,229 @@ +addColumn("Bar", "integer"); + + $sql = $this->_platform->getCreateTableSQL($table); + $this->assertEquals('CREATE TABLE Foo (Bar INT NOT NULL) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB', array_shift($sql)); + } + + public function getGenerateTableSql() + { + return 'CREATE TABLE test (id INT AUTO_INCREMENT NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'; + } + + public function getGenerateTableWithMultiColumnUniqueIndexSql() + { + return array( + 'CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA (foo, bar)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB' + ); + } + + public function getGenerateAlterTableSql() + { + return array( + "ALTER TABLE mytable RENAME TO userlist, ADD quota INT DEFAULT NULL, DROP foo, CHANGE bar baz VARCHAR(255) DEFAULT 'def' NOT NULL, CHANGE bloo bloo TINYINT(1) DEFAULT '0' NOT NULL" + ); + } + + public function testGeneratesSqlSnippets() + { + $this->assertEquals('RLIKE', $this->_platform->getRegexpExpression(), 'Regular expression operator is not correct'); + $this->assertEquals('`', $this->_platform->getIdentifierQuoteCharacter(), 'Quote character is not correct'); + $this->assertEquals('CONCAT(column1, column2, column3)', $this->_platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation function is not correct'); + } + + public function testGeneratesTransactionsCommands() + { + $this->assertEquals( + 'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED), + '' + ); + $this->assertEquals( + 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED) + ); + $this->assertEquals( + 'SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ) + ); + $this->assertEquals( + 'SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE) + ); + } + + + public function testGeneratesDDLSnippets() + { + $this->assertEquals('SHOW DATABASES', $this->_platform->getShowDatabasesSQL()); + $this->assertEquals('CREATE DATABASE foobar', $this->_platform->getCreateDatabaseSQL('foobar')); + $this->assertEquals('DROP DATABASE foobar', $this->_platform->getDropDatabaseSQL('foobar')); + $this->assertEquals('DROP TABLE foobar', $this->_platform->getDropTableSQL('foobar')); + } + + public function testGeneratesTypeDeclarationForIntegers() + { + $this->assertEquals( + 'INT', + $this->_platform->getIntegerTypeDeclarationSQL(array()) + ); + $this->assertEquals( + 'INT AUTO_INCREMENT', + $this->_platform->getIntegerTypeDeclarationSQL(array('autoincrement' => true) + )); + $this->assertEquals( + 'INT AUTO_INCREMENT', + $this->_platform->getIntegerTypeDeclarationSQL( + array('autoincrement' => true, 'primary' => true) + )); + } + + public function testGeneratesTypeDeclarationForStrings() + { + $this->assertEquals( + 'CHAR(10)', + $this->_platform->getVarcharTypeDeclarationSQL( + array('length' => 10, 'fixed' => true) + )); + $this->assertEquals( + 'VARCHAR(50)', + $this->_platform->getVarcharTypeDeclarationSQL(array('length' => 50)), + 'Variable string declaration is not correct' + ); + $this->assertEquals( + 'VARCHAR(255)', + $this->_platform->getVarcharTypeDeclarationSQL(array()), + 'Long string declaration is not correct' + ); + } + + public function testPrefersIdentityColumns() + { + $this->assertTrue($this->_platform->prefersIdentityColumns()); + } + + public function testSupportsIdentityColumns() + { + $this->assertTrue($this->_platform->supportsIdentityColumns()); + } + + public function testDoesSupportSavePoints() + { + $this->assertTrue($this->_platform->supportsSavepoints()); + } + + public function getGenerateIndexSql() + { + return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; + } + + public function getGenerateUniqueIndexSql() + { + return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; + } + + public function getGenerateForeignKeySql() + { + return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)'; + } + + /** + * @group DBAL-126 + */ + public function testUniquePrimaryKey() + { + $keyTable = new Table("foo"); + $keyTable->addColumn("bar", "integer"); + $keyTable->addColumn("baz", "string"); + $keyTable->setPrimaryKey(array("bar")); + $keyTable->addUniqueIndex(array("baz")); + + $oldTable = new Table("foo"); + $oldTable->addColumn("bar", "integer"); + $oldTable->addColumn("baz", "string"); + + $c = new \Doctrine\DBAL\Schema\Comparator; + $diff = $c->diffTable($oldTable, $keyTable); + + $sql = $this->_platform->getAlterTableSQL($diff); + + $this->assertEquals(array( + "ALTER TABLE foo ADD PRIMARY KEY (bar)", + "CREATE UNIQUE INDEX UNIQ_8C73652178240498 ON foo (baz)", + ), $sql); + } + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT * FROM user LIMIT 10 OFFSET 0', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT * FROM user LIMIT 10', $sql); + } + + /** + * @group DDC-118 + */ + public function testGetDateTimeTypeDeclarationSql() + { + $this->assertEquals("DATETIME", $this->_platform->getDateTimeTypeDeclarationSQL(array('version' => false))); + $this->assertEquals("TIMESTAMP", $this->_platform->getDateTimeTypeDeclarationSQL(array('version' => true))); + $this->assertEquals("DATETIME", $this->_platform->getDateTimeTypeDeclarationSQL(array())); + } + + public function getCreateTableColumnCommentsSQL() + { + return array("CREATE TABLE test (id INT NOT NULL COMMENT 'This is a comment', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB"); + } + + public function getAlterTableColumnCommentsSQL() + { + return array("ALTER TABLE mytable ADD quota INT NOT NULL COMMENT 'A comment', CHANGE bar baz VARCHAR(255) NOT NULL COMMENT 'B comment'"); + } + + public function getCreateTableColumnTypeCommentsSQL() + { + return array("CREATE TABLE test (id INT NOT NULL, data LONGTEXT NOT NULL COMMENT '(DC2Type:array)', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB"); + } + + /** + * @group DBAL-237 + */ + public function testChangeIndexWithForeignKeys() + { + $index = new Index("idx", array("col"), false); + $unique = new Index("uniq", array("col"), true); + + $diff = new TableDiff("test", array(), array(), array(), array($unique), array(), array($index)); + $sql = $this->_platform->getAlterTableSQL($diff); + $this->assertEquals(array("ALTER TABLE test DROP INDEX idx, ADD UNIQUE INDEX uniq (col)"), $sql); + + $diff = new TableDiff("test", array(), array(), array(), array($index), array(), array($unique)); + $sql = $this->_platform->getAlterTableSQL($diff); + $this->assertEquals(array("ALTER TABLE test DROP INDEX uniq, ADD INDEX idx (col)"), $sql); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php new file mode 100644 index 0000000..6553ce6 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php @@ -0,0 +1,272 @@ +createPlatform(); + $platform->assertValidIdentifier($identifier); + } + + static public function dataInvalidIdentifiers() + { + return array( + array('1'), + array('abc&'), + array('abc-def'), + array('"'), + array('"foo"bar"'), + ); + } + + /** + * @dataProvider dataInvalidIdentifiers + */ + public function testInvalidIdentifiers($identifier) + { + $this->setExpectedException('Doctrine\DBAL\DBALException'); + $platform = $this->createPlatform(); + $platform->assertValidIdentifier($identifier); + } + + public function createPlatform() + { + return new OraclePlatform; + } + + public function getGenerateTableSql() + { + return 'CREATE TABLE test (id NUMBER(10) NOT NULL, test VARCHAR2(255) DEFAULT NULL, PRIMARY KEY(id))'; + } + + public function getGenerateTableWithMultiColumnUniqueIndexSql() + { + return array( + 'CREATE TABLE test (foo VARCHAR2(255) DEFAULT NULL, bar VARCHAR2(255) DEFAULT NULL)', + 'CREATE UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA ON test (foo, bar)', + ); + } + + public function getGenerateAlterTableSql() + { + return array( + 'ALTER TABLE mytable ADD (quota NUMBER(10) DEFAULT NULL)', + "ALTER TABLE mytable MODIFY (baz VARCHAR2(255) DEFAULT 'def' NOT NULL, bloo NUMBER(1) DEFAULT '0' NOT NULL)", + "ALTER TABLE mytable DROP (foo)", + "ALTER TABLE mytable RENAME TO userlist", + ); + } + + /** + * @expectedException Doctrine\DBAL\DBALException + */ + public function testRLike() + { + $this->assertEquals('RLIKE', $this->_platform->getRegexpExpression(), 'Regular expression operator is not correct'); + } + + public function testGeneratesSqlSnippets() + { + $this->assertEquals('"', $this->_platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct'); + $this->assertEquals('column1 || column2 || column3', $this->_platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct'); + } + + public function testGeneratesTransactionsCommands() + { + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED) + ); + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED) + ); + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ) + ); + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE) + ); + } + + /** + * @expectedException Doctrine\DBAL\DBALException + */ + public function testShowDatabasesThrowsException() + { + $this->assertEquals('SHOW DATABASES', $this->_platform->getShowDatabasesSQL()); + } + + /** + * @expectedException Doctrine\DBAL\DBALException + */ + public function testCreateDatabaseThrowsException() + { + $this->assertEquals('CREATE DATABASE foobar', $this->_platform->getCreateDatabaseSQL('foobar')); + } + + public function testDropDatabaseThrowsException() + { + $this->assertEquals('DROP USER foobar CASCADE', $this->_platform->getDropDatabaseSQL('foobar')); + } + + public function testDropTable() + { + $this->assertEquals('DROP TABLE foobar', $this->_platform->getDropTableSQL('foobar')); + } + + public function testGeneratesTypeDeclarationForIntegers() + { + $this->assertEquals( + 'NUMBER(10)', + $this->_platform->getIntegerTypeDeclarationSQL(array()) + ); + $this->assertEquals( + 'NUMBER(10)', + $this->_platform->getIntegerTypeDeclarationSQL(array('autoincrement' => true) + )); + $this->assertEquals( + 'NUMBER(10)', + $this->_platform->getIntegerTypeDeclarationSQL( + array('autoincrement' => true, 'primary' => true) + )); + } + + public function testGeneratesTypeDeclarationsForStrings() + { + $this->assertEquals( + 'CHAR(10)', + $this->_platform->getVarcharTypeDeclarationSQL( + array('length' => 10, 'fixed' => true) + )); + $this->assertEquals( + 'VARCHAR2(50)', + $this->_platform->getVarcharTypeDeclarationSQL(array('length' => 50)), + 'Variable string declaration is not correct' + ); + $this->assertEquals( + 'VARCHAR2(255)', + $this->_platform->getVarcharTypeDeclarationSQL(array()), + 'Long string declaration is not correct' + ); + } + + public function testPrefersIdentityColumns() + { + $this->assertFalse($this->_platform->prefersIdentityColumns()); + } + + public function testSupportsIdentityColumns() + { + $this->assertFalse($this->_platform->supportsIdentityColumns()); + } + + public function testSupportsSavePoints() + { + $this->assertTrue($this->_platform->supportsSavepoints()); + } + + public function getGenerateIndexSql() + { + return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; + } + + public function getGenerateUniqueIndexSql() + { + return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; + } + + public function getGenerateForeignKeySql() + { + return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)'; + } + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT a.* FROM (SELECT * FROM user) a WHERE ROWNUM <= 10', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT a.* FROM (SELECT * FROM user) a WHERE ROWNUM <= 10', $sql); + } + + public function testModifyLimitQueryWithAscOrderBy() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username ASC', 10); + $this->assertEquals('SELECT a.* FROM (SELECT * FROM user ORDER BY username ASC) a WHERE ROWNUM <= 10', $sql); + } + + public function testModifyLimitQueryWithDescOrderBy() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10); + $this->assertEquals('SELECT a.* FROM (SELECT * FROM user ORDER BY username DESC) a WHERE ROWNUM <= 10', $sql); + } + + public function getCreateTableColumnCommentsSQL() + { + return array( + "CREATE TABLE test (id NUMBER(10) NOT NULL, PRIMARY KEY(id))", + "COMMENT ON COLUMN test.id IS 'This is a comment'", + ); + } + + public function getCreateTableColumnTypeCommentsSQL() + { + return array( + "CREATE TABLE test (id NUMBER(10) NOT NULL, data CLOB NOT NULL, PRIMARY KEY(id))", + "COMMENT ON COLUMN test.data IS '(DC2Type:array)'" + ); + } + + public function getAlterTableColumnCommentsSQL() + { + return array( + "ALTER TABLE mytable ADD (quota NUMBER(10) NOT NULL)", + "ALTER TABLE mytable MODIFY (baz VARCHAR2(255) NOT NULL)", + "COMMENT ON COLUMN mytable.quota IS 'A comment'", + "COMMENT ON COLUMN mytable.baz IS 'B comment'", + ); + } + + public function getBitAndComparisonExpressionSql($value1, $value2) + { + return 'BITAND('.$value1 . ', ' . $value2 . ')'; + } + + public function getBitOrComparisonExpressionSql($value1, $value2) + { + return '(' . $value1 . '-' . + $this->getBitAndComparisonExpressionSql($value1, $value2) + . '+' . $value2 . ')'; + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php new file mode 100644 index 0000000..a3f0739 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php @@ -0,0 +1,228 @@ + 'CASCADE') + ); + $this->assertEquals( + "CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE", + $this->_platform->getForeignKeyDeclarationSQL($foreignKey) + ); + } + + public function testGeneratesSqlSnippets() + { + $this->assertEquals('SIMILAR TO', $this->_platform->getRegexpExpression(), 'Regular expression operator is not correct'); + $this->assertEquals('"', $this->_platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct'); + $this->assertEquals('column1 || column2 || column3', $this->_platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct'); + $this->assertEquals('SUBSTR(column, 5)', $this->_platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); + $this->assertEquals('SUBSTR(column, 0, 5)', $this->_platform->getSubstringExpression('column', 0, 5), 'Substring expression with length is not correct'); + } + + public function testGeneratesTransactionCommands() + { + $this->assertEquals( + 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED) + ); + $this->assertEquals( + 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED) + ); + $this->assertEquals( + 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ) + ); + $this->assertEquals( + 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE) + ); + } + + public function testGeneratesDDLSnippets() + { + $this->assertEquals('CREATE DATABASE foobar', $this->_platform->getCreateDatabaseSQL('foobar')); + $this->assertEquals('DROP DATABASE foobar', $this->_platform->getDropDatabaseSQL('foobar')); + $this->assertEquals('DROP TABLE foobar', $this->_platform->getDropTableSQL('foobar')); + } + + public function testGenerateTableWithAutoincrement() + { + $table = new \Doctrine\DBAL\Schema\Table('autoinc_table'); + $column = $table->addColumn('id', 'integer'); + $column->setAutoincrement(true); + + $this->assertEquals(array('CREATE TABLE autoinc_table (id SERIAL NOT NULL)'), $this->_platform->getCreateTableSQL($table)); + } + + public function testGeneratesTypeDeclarationForIntegers() + { + $this->assertEquals( + 'INT', + $this->_platform->getIntegerTypeDeclarationSQL(array()) + ); + $this->assertEquals( + 'SERIAL', + $this->_platform->getIntegerTypeDeclarationSQL(array('autoincrement' => true) + )); + $this->assertEquals( + 'SERIAL', + $this->_platform->getIntegerTypeDeclarationSQL( + array('autoincrement' => true, 'primary' => true) + )); + } + + public function testGeneratesTypeDeclarationForStrings() + { + $this->assertEquals( + 'CHAR(10)', + $this->_platform->getVarcharTypeDeclarationSQL( + array('length' => 10, 'fixed' => true)) + ); + $this->assertEquals( + 'VARCHAR(50)', + $this->_platform->getVarcharTypeDeclarationSQL(array('length' => 50)), + 'Variable string declaration is not correct' + ); + $this->assertEquals( + 'VARCHAR(255)', + $this->_platform->getVarcharTypeDeclarationSQL(array()), + 'Long string declaration is not correct' + ); + } + + public function getGenerateUniqueIndexSql() + { + return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; + } + + public function testGeneratesSequenceSqlCommands() + { + $sequence = new \Doctrine\DBAL\Schema\Sequence('myseq', 20, 1); + $this->assertEquals( + 'CREATE SEQUENCE myseq INCREMENT BY 20 MINVALUE 1 START 1', + $this->_platform->getCreateSequenceSQL($sequence) + ); + $this->assertEquals( + 'DROP SEQUENCE myseq', + $this->_platform->getDropSequenceSQL('myseq') + ); + $this->assertEquals( + "SELECT NEXTVAL('myseq')", + $this->_platform->getSequenceNextValSQL('myseq') + ); + } + + public function testDoesNotPreferIdentityColumns() + { + $this->assertFalse($this->_platform->prefersIdentityColumns()); + } + + public function testPrefersSequences() + { + $this->assertTrue($this->_platform->prefersSequences()); + } + + public function testSupportsIdentityColumns() + { + $this->assertTrue($this->_platform->supportsIdentityColumns()); + } + + public function testSupportsSavePoints() + { + $this->assertTrue($this->_platform->supportsSavepoints()); + } + + public function testSupportsSequences() + { + $this->assertTrue($this->_platform->supportsSequences()); + } + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT * FROM user LIMIT 10 OFFSET 0', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT * FROM user LIMIT 10', $sql); + } + + public function getCreateTableColumnCommentsSQL() + { + return array( + "CREATE TABLE test (id INT NOT NULL, PRIMARY KEY(id))", + "COMMENT ON COLUMN test.id IS 'This is a comment'", + ); + } + + public function getAlterTableColumnCommentsSQL() + { + return array( + "ALTER TABLE mytable ADD quota INT NOT NULL", + "COMMENT ON COLUMN mytable.quota IS 'A comment'", + "COMMENT ON COLUMN mytable.baz IS 'B comment'", + ); + } + + public function getCreateTableColumnTypeCommentsSQL() + { + return array( + "CREATE TABLE test (id INT NOT NULL, data TEXT NOT NULL, PRIMARY KEY(id))", + "COMMENT ON COLUMN test.data IS '(DC2Type:array)'" + ); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/ReservedKeywordsValidatorTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/ReservedKeywordsValidatorTest.php new file mode 100644 index 0000000..388115f --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/ReservedKeywordsValidatorTest.php @@ -0,0 +1,47 @@ +validator = new ReservedKeywordsValidator(array( + new \Doctrine\DBAL\Platforms\Keywords\MySQLKeywords() + )); + } + + public function testReservedTableName() + { + $table = new Table("TABLE"); + $this->validator->acceptTable($table); + + $this->assertEquals( + array('Table TABLE keyword violations: MySQL'), + $this->validator->getViolations() + ); + } + + public function testReservedColumnName() + { + $table = new Table("TABLE"); + $column = $table->addColumn('table', 'string'); + + $this->validator->acceptColumn($table, $column); + + $this->assertEquals( + array('Table TABLE column table keyword violations: MySQL'), + $this->validator->getViolations() + ); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php new file mode 100644 index 0000000..f66a0f8 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php @@ -0,0 +1,29 @@ +platform = new \Doctrine\DBAL\Platforms\SQLAzurePlatform(); + } + + public function testCreateFederatedOnTable() + { + $table = new \Doctrine\DBAL\Schema\Table("tbl"); + $table->addColumn("id", "integer"); + $table->addOption('azure.federatedOnDistributionName', 'TblId'); + $table->addOption('azure.federatedOnColumnName', 'id'); + + $this->assertEquals(array('CREATE TABLE tbl (id INT NOT NULL) FEDERATED ON (TblId = id)'), $this->platform->getCreateTableSQL($table)); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php new file mode 100644 index 0000000..28216bb --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php @@ -0,0 +1,224 @@ +assertEquals('RLIKE', $this->_platform->getRegexpExpression(), 'Regular expression operator is not correct'); + $this->assertEquals('"', $this->_platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct'); + $this->assertEquals('(column1 + column2 + column3)', $this->_platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct'); + } + + public function testGeneratesTransactionsCommands() + { + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED) + ); + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED) + ); + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ) + ); + $this->assertEquals( + 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE) + ); + } + + public function testGeneratesDDLSnippets() + { + $dropDatabaseExpectation = 'DROP DATABASE foobar'; + + $this->assertEquals('SHOW DATABASES', $this->_platform->getShowDatabasesSQL()); + $this->assertEquals('CREATE DATABASE foobar', $this->_platform->getCreateDatabaseSQL('foobar')); + $this->assertEquals($dropDatabaseExpectation, $this->_platform->getDropDatabaseSQL('foobar')); + $this->assertEquals('DROP TABLE foobar', $this->_platform->getDropTableSQL('foobar')); + } + + public function testGeneratesTypeDeclarationForIntegers() + { + $this->assertEquals( + 'INT', + $this->_platform->getIntegerTypeDeclarationSQL(array()) + ); + $this->assertEquals( + 'INT IDENTITY', + $this->_platform->getIntegerTypeDeclarationSQL(array('autoincrement' => true) + )); + $this->assertEquals( + 'INT IDENTITY', + $this->_platform->getIntegerTypeDeclarationSQL( + array('autoincrement' => true, 'primary' => true) + )); + } + + public function testGeneratesTypeDeclarationsForStrings() + { + $this->assertEquals( + 'NCHAR(10)', + $this->_platform->getVarcharTypeDeclarationSQL( + array('length' => 10, 'fixed' => true) + )); + $this->assertEquals( + 'NVARCHAR(50)', + $this->_platform->getVarcharTypeDeclarationSQL(array('length' => 50)), + 'Variable string declaration is not correct' + ); + $this->assertEquals( + 'NVARCHAR(255)', + $this->_platform->getVarcharTypeDeclarationSQL(array()), + 'Long string declaration is not correct' + ); + } + + public function testPrefersIdentityColumns() + { + $this->assertTrue($this->_platform->prefersIdentityColumns()); + } + + public function testSupportsIdentityColumns() + { + $this->assertTrue($this->_platform->supportsIdentityColumns()); + } + + public function testDoesNotSupportSavePoints() + { + $this->assertTrue($this->_platform->supportsSavepoints()); + } + + public function getGenerateIndexSql() + { + return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; + } + + public function getGenerateUniqueIndexSql() + { + return 'CREATE UNIQUE INDEX index_name ON test (test, test2) WHERE test IS NOT NULL AND test2 IS NOT NULL'; + } + + public function getGenerateForeignKeySql() + { + return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)'; + } + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT TOP 10 * FROM user', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT TOP 10 * FROM user', $sql); + } + + public function testModifyLimitQueryWithOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10, 5); + $this->assertEquals('SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY username DESC) AS doctrine_rownum, * FROM user) AS doctrine_tbl WHERE doctrine_rownum BETWEEN 6 AND 15', $sql); + } + + public function testModifyLimitQueryWithAscOrderBy() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username ASC', 10); + $this->assertEquals('SELECT TOP 10 * FROM user ORDER BY username ASC', $sql); + } + + public function testModifyLimitQueryWithDescOrderBy() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10); + $this->assertEquals('SELECT TOP 10 * FROM user ORDER BY username DESC', $sql); + } + + /** + * @group DDC-1360 + */ + public function testQuoteIdentifier() + { + $this->assertEquals('[fo][o]', $this->_platform->quoteIdentifier('fo]o')); + $this->assertEquals('[test]', $this->_platform->quoteIdentifier('test')); + $this->assertEquals('[test].[test]', $this->_platform->quoteIdentifier('test.test')); + } + + /** + * @group DDC-1360 + */ + public function testQuoteSingleIdentifier() + { + $this->assertEquals('[fo][o]', $this->_platform->quoteSingleIdentifier('fo]o')); + $this->assertEquals('[test]', $this->_platform->quoteSingleIdentifier('test')); + $this->assertEquals('[test.test]', $this->_platform->quoteSingleIdentifier('test.test')); + } + + /** + * @group DBAL-220 + */ + public function testCreateClusteredIndex() + { + $idx = new \Doctrine\DBAL\Schema\Index('idx', array('id')); + $idx->addFlag('clustered'); + $this->assertEquals('CREATE CLUSTERED INDEX idx ON tbl (id)', $this->_platform->getCreateIndexSQL($idx, 'tbl')); + } + + /** + * @group DBAL-220 + */ + public function testCreateNonClusteredPrimaryKeyInTable() + { + $table = new \Doctrine\DBAL\Schema\Table("tbl"); + $table->addColumn("id", "integer"); + $table->setPrimaryKey(Array("id")); + $table->getIndex('primary')->addFlag('nonclustered'); + + $this->assertEquals(array('CREATE TABLE tbl (id INT NOT NULL, PRIMARY KEY NONCLUSTERED (id))'), $this->_platform->getCreateTableSQL($table)); + } + + /** + * @group DBAL-220 + */ + public function testCreateNonClusteredPrimaryKey() + { + $idx = new \Doctrine\DBAL\Schema\Index('idx', array('id'), false, true); + $idx->addFlag('nonclustered'); + $this->assertEquals('ALTER TABLE tbl ADD PRIMARY KEY NONCLUSTERED (id)', $this->_platform->getCreatePrimaryKeySQL($idx, 'tbl')); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php new file mode 100644 index 0000000..6548cf8 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php @@ -0,0 +1,155 @@ +assertEquals('RLIKE', $this->_platform->getRegexpExpression(), 'Regular expression operator is not correct'); + $this->assertEquals('SUBSTR(column, 5, LENGTH(column))', $this->_platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); + $this->assertEquals('SUBSTR(column, 0, 5)', $this->_platform->getSubstringExpression('column', 0, 5), 'Substring expression with length is not correct'); + } + + public function testGeneratesTransactionCommands() + { + $this->assertEquals( + 'PRAGMA read_uncommitted = 0', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_UNCOMMITTED) + ); + $this->assertEquals( + 'PRAGMA read_uncommitted = 1', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_READ_COMMITTED) + ); + $this->assertEquals( + 'PRAGMA read_uncommitted = 1', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_REPEATABLE_READ) + ); + $this->assertEquals( + 'PRAGMA read_uncommitted = 1', + $this->_platform->getSetTransactionIsolationSQL(\Doctrine\DBAL\Connection::TRANSACTION_SERIALIZABLE) + ); + } + + public function testPrefersIdentityColumns() + { + $this->assertTrue($this->_platform->prefersIdentityColumns()); + } + + public function testGeneratesTypeDeclarationForIntegers() + { + $this->assertEquals( + 'INTEGER', + $this->_platform->getIntegerTypeDeclarationSQL(array()) + ); + $this->assertEquals( + 'INTEGER', + $this->_platform->getIntegerTypeDeclarationSQL(array('autoincrement' => true)) + ); + $this->assertEquals( + 'INTEGER', + $this->_platform->getIntegerTypeDeclarationSQL( + array('autoincrement' => true, 'primary' => true)) + ); + } + + public function testGeneratesTypeDeclarationForStrings() + { + $this->assertEquals( + 'CHAR(10)', + $this->_platform->getVarcharTypeDeclarationSQL( + array('length' => 10, 'fixed' => true)) + ); + $this->assertEquals( + 'VARCHAR(50)', + $this->_platform->getVarcharTypeDeclarationSQL(array('length' => 50)), + 'Variable string declaration is not correct' + ); + $this->assertEquals( + 'VARCHAR(255)', + $this->_platform->getVarcharTypeDeclarationSQL(array()), + 'Long string declaration is not correct' + ); + } + + public function getGenerateIndexSql() + { + return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; + } + + public function getGenerateUniqueIndexSql() + { + return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; + } + + public function getGenerateForeignKeySql() + { + $this->markTestSkipped('SQLite does not support ForeignKeys.'); + } + + public function testModifyLimitQuery() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0); + $this->assertEquals('SELECT * FROM user LIMIT 10 OFFSET 0', $sql); + } + + public function testModifyLimitQueryWithEmptyOffset() + { + $sql = $this->_platform->modifyLimitQuery('SELECT * FROM user', 10); + $this->assertEquals('SELECT * FROM user LIMIT 10', $sql); + } + + public function getGenerateAlterTableSql() + { + $this->markTestSkipped('SQlite does not support ALTER Table.'); + } + + public function testGetAlterTableSqlDispatchEvent() + { + $this->markTestSkipped('SQlite does not support ALTER Table.'); + } + + /** + * @group DDC-1845 + */ + public function testGenerateTableSqlShouldNotAutoQuotePrimaryKey() + { + $table = new \Doctrine\DBAL\Schema\Table('test'); + $table->addColumn('"like"', 'integer', array('notnull' => true, 'autoincrement' => true)); + $table->setPrimaryKey(array('"like"')); + + $createTableSQL = $this->_platform->getCreateTableSQL($table); + $this->assertEquals( + 'CREATE TABLE test ("like" INTEGER NOT NULL, PRIMARY KEY("like"))', + $createTableSQL[0] + ); + + $this->assertEquals( + 'ALTER TABLE test ADD PRIMARY KEY ("like")', + $this->_platform->getCreatePrimaryKeySQL($table->getIndex('primary'), 'test') + ); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php new file mode 100644 index 0000000..9939659 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php @@ -0,0 +1,82 @@ +assertEquals(1, count($expr)); + + $expr->add('u.group_id = 2'); + + $this->assertEquals(2, count($expr)); + } + + /** + * @dataProvider provideDataForConvertToString + */ + public function testCompositeUsageAndGeneration($type, $parts, $expects) + { + $expr = new CompositeExpression($type, $parts); + + $this->assertEquals($expects, (string) $expr); + } + + public function provideDataForConvertToString() + { + return array( + array( + CompositeExpression::TYPE_AND, + array('u.user = 1'), + 'u.user = 1' + ), + array( + CompositeExpression::TYPE_AND, + array('u.user = 1', 'u.group_id = 1'), + '(u.user = 1) AND (u.group_id = 1)' + ), + array( + CompositeExpression::TYPE_OR, + array('u.user = 1'), + 'u.user = 1' + ), + array( + CompositeExpression::TYPE_OR, + array('u.group_id = 1', 'u.group_id = 2'), + '(u.group_id = 1) OR (u.group_id = 2)' + ), + array( + CompositeExpression::TYPE_AND, + array( + 'u.user = 1', + new CompositeExpression( + CompositeExpression::TYPE_OR, + array('u.group_id = 1', 'u.group_id = 2') + ) + ), + '(u.user = 1) AND ((u.group_id = 1) OR (u.group_id = 2))' + ), + array( + CompositeExpression::TYPE_OR, + array( + 'u.group_id = 1', + new CompositeExpression( + CompositeExpression::TYPE_AND, + array('u.user = 1', 'u.group_id = 2') + ) + ), + '(u.group_id = 1) OR ((u.user = 1) AND (u.group_id = 2))' + ), + ); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php new file mode 100644 index 0000000..1893e97 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php @@ -0,0 +1,201 @@ +getMock('Doctrine\DBAL\Connection', array(), array(), '', false); + + $this->expr = new ExpressionBuilder($conn); + + $conn->expects($this->any()) + ->method('getExpressionBuilder') + ->will($this->returnValue($this->expr)); + } + + /** + * @dataProvider provideDataForAndX + */ + public function testAndX($parts, $expected) + { + $composite = $this->expr->andX(); + + foreach ($parts as $part) { + $composite->add($part); + } + + $this->assertEquals($expected, (string) $composite); + } + + public function provideDataForAndX() + { + return array( + array( + array('u.user = 1'), + 'u.user = 1' + ), + array( + array('u.user = 1', 'u.group_id = 1'), + '(u.user = 1) AND (u.group_id = 1)' + ), + array( + array('u.user = 1'), + 'u.user = 1' + ), + array( + array('u.group_id = 1', 'u.group_id = 2'), + '(u.group_id = 1) AND (u.group_id = 2)' + ), + array( + array( + 'u.user = 1', + new CompositeExpression( + CompositeExpression::TYPE_OR, + array('u.group_id = 1', 'u.group_id = 2') + ) + ), + '(u.user = 1) AND ((u.group_id = 1) OR (u.group_id = 2))' + ), + array( + array( + 'u.group_id = 1', + new CompositeExpression( + CompositeExpression::TYPE_AND, + array('u.user = 1', 'u.group_id = 2') + ) + ), + '(u.group_id = 1) AND ((u.user = 1) AND (u.group_id = 2))' + ), + ); + } + + /** + * @dataProvider provideDataForOrX + */ + public function testOrX($parts, $expected) + { + $composite = $this->expr->orX(); + + foreach ($parts as $part) { + $composite->add($part); + } + + $this->assertEquals($expected, (string) $composite); + } + + public function provideDataForOrX() + { + return array( + array( + array('u.user = 1'), + 'u.user = 1' + ), + array( + array('u.user = 1', 'u.group_id = 1'), + '(u.user = 1) OR (u.group_id = 1)' + ), + array( + array('u.user = 1'), + 'u.user = 1' + ), + array( + array('u.group_id = 1', 'u.group_id = 2'), + '(u.group_id = 1) OR (u.group_id = 2)' + ), + array( + array( + 'u.user = 1', + new CompositeExpression( + CompositeExpression::TYPE_OR, + array('u.group_id = 1', 'u.group_id = 2') + ) + ), + '(u.user = 1) OR ((u.group_id = 1) OR (u.group_id = 2))' + ), + array( + array( + 'u.group_id = 1', + new CompositeExpression( + CompositeExpression::TYPE_AND, + array('u.user = 1', 'u.group_id = 2') + ) + ), + '(u.group_id = 1) OR ((u.user = 1) AND (u.group_id = 2))' + ), + ); + } + + /** + * @dataProvider provideDataForComparison + */ + public function testComparison($leftExpr, $operator, $rightExpr, $expected) + { + $part = $this->expr->comparison($leftExpr, $operator, $rightExpr); + + $this->assertEquals($expected, (string) $part); + } + + public function provideDataForComparison() + { + return array( + array('u.user_id', ExpressionBuilder::EQ, '1', 'u.user_id = 1'), + array('u.user_id', ExpressionBuilder::NEQ, '1', 'u.user_id <> 1'), + array('u.salary', ExpressionBuilder::LT, '10000', 'u.salary < 10000'), + array('u.salary', ExpressionBuilder::LTE, '10000', 'u.salary <= 10000'), + array('u.salary', ExpressionBuilder::GT, '10000', 'u.salary > 10000'), + array('u.salary', ExpressionBuilder::GTE, '10000', 'u.salary >= 10000'), + ); + } + + public function testEq() + { + $this->assertEquals('u.user_id = 1', $this->expr->eq('u.user_id', '1')); + } + + public function testNeq() + { + $this->assertEquals('u.user_id <> 1', $this->expr->neq('u.user_id', '1')); + } + + public function testLt() + { + $this->assertEquals('u.salary < 10000', $this->expr->lt('u.salary', '10000')); + } + + public function testLte() + { + $this->assertEquals('u.salary <= 10000', $this->expr->lte('u.salary', '10000')); + } + + public function testGt() + { + $this->assertEquals('u.salary > 10000', $this->expr->gt('u.salary', '10000')); + } + + public function testGte() + { + $this->assertEquals('u.salary >= 10000', $this->expr->gte('u.salary', '10000')); + } + + public function testIsNull() + { + $this->assertEquals('u.deleted IS NULL', $this->expr->isNull('u.deleted')); + } + + public function testIsNotNull() + { + $this->assertEquals('u.updated IS NOT NULL', $this->expr->isNotNull('u.updated')); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php new file mode 100644 index 0000000..98f1616 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php @@ -0,0 +1,572 @@ +conn = $this->getMock('Doctrine\DBAL\Connection', array(), array(), '', false); + + $expressionBuilder = new ExpressionBuilder($this->conn); + + $this->conn->expects($this->any()) + ->method('getExpressionBuilder') + ->will($this->returnValue($expressionBuilder)); + } + + public function testSimpleSelect() + { + $qb = new QueryBuilder($this->conn); + + $qb->select('u.id') + ->from('users', 'u'); + + $this->assertEquals('SELECT u.id FROM users u', (string) $qb); + } + + public function testSelectWithSimpleWhere() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.id') + ->from('users', 'u') + ->where($expr->andX($expr->eq('u.nickname', '?'))); + + $this->assertEquals("SELECT u.id FROM users u WHERE u.nickname = ?", (string) $qb); + } + + public function testSelectWithLeftJoin() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->leftJoin('u', 'phones', 'p', $expr->eq('p.user_id', 'u.id')); + + $this->assertEquals('SELECT u.*, p.* FROM users u LEFT JOIN phones p ON p.user_id = u.id', (string) $qb); + } + + public function testSelectWithJoin() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->Join('u', 'phones', 'p', $expr->eq('p.user_id', 'u.id')); + + $this->assertEquals('SELECT u.*, p.* FROM users u INNER JOIN phones p ON p.user_id = u.id', (string) $qb); + } + + public function testSelectWithInnerJoin() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->innerJoin('u', 'phones', 'p', $expr->eq('p.user_id', 'u.id')); + + $this->assertEquals('SELECT u.*, p.* FROM users u INNER JOIN phones p ON p.user_id = u.id', (string) $qb); + } + + public function testSelectWithRightJoin() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->rightJoin('u', 'phones', 'p', $expr->eq('p.user_id', 'u.id')); + + $this->assertEquals('SELECT u.*, p.* FROM users u RIGHT JOIN phones p ON p.user_id = u.id', (string) $qb); + } + + public function testSelectWithAndWhereConditions() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->where('u.username = ?') + ->andWhere('u.name = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u WHERE (u.username = ?) AND (u.name = ?)', (string) $qb); + } + + public function testSelectWithOrWhereConditions() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->where('u.username = ?') + ->orWhere('u.name = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u WHERE (u.username = ?) OR (u.name = ?)', (string) $qb); + } + + public function testSelectWithOrOrWhereConditions() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->orWhere('u.username = ?') + ->orWhere('u.name = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u WHERE (u.username = ?) OR (u.name = ?)', (string) $qb); + } + + public function testSelectWithAndOrWhereConditions() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->where('u.username = ?') + ->andWhere('u.username = ?') + ->orWhere('u.name = ?') + ->andWhere('u.name = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u WHERE (((u.username = ?) AND (u.username = ?)) OR (u.name = ?)) AND (u.name = ?)', (string) $qb); + } + + public function testSelectGroupBy() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->groupBy('u.id'); + + $this->assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id', (string) $qb); + } + + public function testSelectEmptyGroupBy() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->groupBy(array()) + ->from('users', 'u'); + + $this->assertEquals('SELECT u.*, p.* FROM users u', (string) $qb); + } + + public function testSelectEmptyAddGroupBy() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->addGroupBy(array()) + ->from('users', 'u'); + + $this->assertEquals('SELECT u.*, p.* FROM users u', (string) $qb); + } + + public function testSelectAddGroupBy() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->groupBy('u.id') + ->addGroupBy('u.foo'); + + $this->assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id, u.foo', (string) $qb); + } + + public function testSelectAddGroupBys() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->groupBy('u.id') + ->addGroupBy('u.foo', 'u.bar'); + + $this->assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id, u.foo, u.bar', (string) $qb); + } + + public function testSelectHaving() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->groupBy('u.id') + ->having('u.name = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING u.name = ?', (string) $qb); + } + + public function testSelectAndHaving() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->groupBy('u.id') + ->andHaving('u.name = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING u.name = ?', (string) $qb); + } + + public function testSelectHavingAndHaving() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->groupBy('u.id') + ->having('u.name = ?') + ->andHaving('u.username = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING (u.name = ?) AND (u.username = ?)', (string) $qb); + } + + public function testSelectHavingOrHaving() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->groupBy('u.id') + ->having('u.name = ?') + ->orHaving('u.username = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING (u.name = ?) OR (u.username = ?)', (string) $qb); + } + + public function testSelectOrHavingOrHaving() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->groupBy('u.id') + ->orHaving('u.name = ?') + ->orHaving('u.username = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING (u.name = ?) OR (u.username = ?)', (string) $qb); + } + + public function testSelectHavingAndOrHaving() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->groupBy('u.id') + ->having('u.name = ?') + ->orHaving('u.username = ?') + ->andHaving('u.username = ?'); + + $this->assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING ((u.name = ?) OR (u.username = ?)) AND (u.username = ?)', (string) $qb); + } + + public function testSelectOrderBy() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->orderBy('u.name'); + + $this->assertEquals('SELECT u.*, p.* FROM users u ORDER BY u.name ASC', (string) $qb); + } + + public function testSelectAddOrderBy() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->orderBy('u.name') + ->addOrderBy('u.username', 'DESC'); + + $this->assertEquals('SELECT u.*, p.* FROM users u ORDER BY u.name ASC, u.username DESC', (string) $qb); + } + + public function testSelectAddAddOrderBy() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*', 'p.*') + ->from('users', 'u') + ->addOrderBy('u.name') + ->addOrderBy('u.username', 'DESC'); + + $this->assertEquals('SELECT u.*, p.* FROM users u ORDER BY u.name ASC, u.username DESC', (string) $qb); + } + + public function testEmptySelect() + { + $qb = new QueryBuilder($this->conn); + $qb2 = $qb->select(); + + $this->assertSame($qb, $qb2); + $this->assertEquals(QueryBuilder::SELECT, $qb->getType()); + } + + public function testSelectAddSelect() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*') + ->addSelect('p.*') + ->from('users', 'u'); + + $this->assertEquals('SELECT u.*, p.* FROM users u', (string) $qb); + } + + public function testEmptyAddSelect() + { + $qb = new QueryBuilder($this->conn); + $qb2 = $qb->addSelect(); + + $this->assertSame($qb, $qb2); + $this->assertEquals(QueryBuilder::SELECT, $qb->getType()); + } + + public function testSelectMultipleFrom() + { + $qb = new QueryBuilder($this->conn); + $expr = $qb->expr(); + + $qb->select('u.*') + ->addSelect('p.*') + ->from('users', 'u') + ->from('phonenumbers', 'p'); + + $this->assertEquals('SELECT u.*, p.* FROM users u, phonenumbers p', (string) $qb); + } + + public function testUpdate() + { + $qb = new QueryBuilder($this->conn); + $qb->update('users', 'u') + ->set('u.foo', '?') + ->set('u.bar', '?'); + + $this->assertEquals(QueryBuilder::UPDATE, $qb->getType()); + $this->assertEquals('UPDATE users u SET u.foo = ?, u.bar = ?', (string) $qb); + } + + public function testUpdateWithoutAlias() + { + $qb = new QueryBuilder($this->conn); + $qb->update('users') + ->set('foo', '?') + ->set('bar', '?'); + + $this->assertEquals('UPDATE users SET foo = ?, bar = ?', (string) $qb); + } + + public function testUpdateWhere() + { + $qb = new QueryBuilder($this->conn); + $qb->update('users', 'u') + ->set('u.foo', '?') + ->where('u.foo = ?'); + + $this->assertEquals('UPDATE users u SET u.foo = ? WHERE u.foo = ?', (string) $qb); + } + + public function testEmptyUpdate() + { + $qb = new QueryBuilder($this->conn); + $qb2 = $qb->update(); + + $this->assertEquals(QueryBuilder::UPDATE, $qb->getType()); + $this->assertSame($qb2, $qb); + } + + public function testDelete() + { + $qb = new QueryBuilder($this->conn); + $qb->delete('users', 'u'); + + $this->assertEquals(QueryBuilder::DELETE, $qb->getType()); + $this->assertEquals('DELETE FROM users u', (string) $qb); + } + + public function testDeleteWithoutAlias() + { + $qb = new QueryBuilder($this->conn); + $qb->delete('users'); + + $this->assertEquals(QueryBuilder::DELETE, $qb->getType()); + $this->assertEquals('DELETE FROM users', (string) $qb); + } + + public function testDeleteWhere() + { + $qb = new QueryBuilder($this->conn); + $qb->delete('users', 'u') + ->where('u.foo = ?'); + + $this->assertEquals('DELETE FROM users u WHERE u.foo = ?', (string) $qb); + } + + public function testEmptyDelete() + { + $qb = new QueryBuilder($this->conn); + $qb2 = $qb->delete(); + + $this->assertEquals(QueryBuilder::DELETE, $qb->getType()); + $this->assertSame($qb2, $qb); + } + + public function testGetConnection() + { + $qb = new QueryBuilder($this->conn); + $this->assertSame($this->conn, $qb->getConnection()); + } + + public function testGetState() + { + $qb = new QueryBuilder($this->conn); + + $this->assertEquals(QueryBuilder::STATE_CLEAN, $qb->getState()); + + $qb->select('u.*')->from('users', 'u'); + + $this->assertEquals(QueryBuilder::STATE_DIRTY, $qb->getState()); + + $sql1 = $qb->getSQL(); + + $this->assertEquals(QueryBuilder::STATE_CLEAN, $qb->getState()); + $this->assertEquals($sql1, $qb->getSQL()); + } + + public function testSetMaxResults() + { + $qb = new QueryBuilder($this->conn); + $qb->setMaxResults(10); + + $this->assertEquals(QueryBuilder::STATE_DIRTY, $qb->getState()); + $this->assertEQuals(10, $qb->getMaxResults()); + } + + public function testSetFirstResult() + { + $qb = new QueryBuilder($this->conn); + $qb->setFirstResult(10); + + $this->assertEquals(QueryBuilder::STATE_DIRTY, $qb->getState()); + $this->assertEQuals(10, $qb->getFirstResult()); + } + + public function testResetQueryPart() + { + $qb = new QueryBuilder($this->conn); + + $qb->select('u.*')->from('users', 'u')->where('u.name = ?'); + + $this->assertEquals('SELECT u.* FROM users u WHERE u.name = ?', (string)$qb); + $qb->resetQueryPart('where'); + $this->assertEquals('SELECT u.* FROM users u', (string)$qb); + } + + public function testResetQueryParts() + { + $qb = new QueryBuilder($this->conn); + + $qb->select('u.*')->from('users', 'u')->where('u.name = ?')->orderBy('u.name'); + + $this->assertEquals('SELECT u.* FROM users u WHERE u.name = ? ORDER BY u.name ASC', (string)$qb); + $qb->resetQueryParts(array('where', 'orderBy')); + $this->assertEquals('SELECT u.* FROM users u', (string)$qb); + } + + public function testCreateNamedParameter() + { + $qb = new QueryBuilder($this->conn); + + $qb->select('u.*')->from('users', 'u')->where( + $qb->expr()->eq('u.name', $qb->createNamedParameter(10, \PDO::PARAM_INT)) + ); + + $this->assertEquals('SELECT u.* FROM users u WHERE u.name = :dcValue1', (string)$qb); + $this->assertEquals(10, $qb->getParameter('dcValue1')); + } + + public function testCreateNamedParameterCustomPlaceholder() + { + $qb = new QueryBuilder($this->conn); + + $qb->select('u.*')->from('users', 'u')->where( + $qb->expr()->eq('u.name', $qb->createNamedParameter(10, \PDO::PARAM_INT, ':test')) + ); + + $this->assertEquals('SELECT u.* FROM users u WHERE u.name = :test', (string)$qb); + $this->assertEquals(10, $qb->getParameter('test')); + } + + public function testCreatePositionalParameter() + { + $qb = new QueryBuilder($this->conn); + + $qb->select('u.*')->from('users', 'u')->where( + $qb->expr()->eq('u.name', $qb->createPositionalParameter(10, \PDO::PARAM_INT)) + ); + + $this->assertEquals('SELECT u.* FROM users u WHERE u.name = ?', (string)$qb); + $this->assertEquals(10, $qb->getParameter(1)); + } + + /** + * @group DBAL-172 + */ + public function testReferenceJoinFromJoin() + { + $qb = new QueryBuilder($this->conn); + + $qb->select("l.id", "mdsh.xcode", "mdso.xcode") + ->from("location_tree", "l") + ->join("l", "location_tree_pos", "p", "l.id = p.tree_id") + ->rightJoin("l", "hotel", "h", "h.location_id = l.id") + ->leftJoin("l", "offer_location", "ol", "l.id=ol.location_id") + ->leftJoin("ol", "mds_offer", "mdso", "ol.offer_id = mdso.offer_id") + ->leftJoin("h", "mds_hotel", "mdsh", "h.id = mdsh.hotel_id") + ->where("p.parent_id IN (:ids)") + ->andWhere("(mdso.xcode IS NOT NULL OR mdsh.xcode IS NOT NULL)"); + + $this->setExpectedException('Doctrine\DBAL\Query\QueryException', "The given alias 'ol' is not part of any FROM clause table. The currently registered FROM-clause aliases are: l"); + $this->assertEquals('', $qb->getSQL()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php new file mode 100644 index 0000000..0e74c7d --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php @@ -0,0 +1,250 @@ + 'foo', 17 => 'bar')), + array('SELECT * FROM Foo WHERE bar IN (:name1, :name2)', false, array(32 => 'name1', 40 => 'name2')), + array('SELECT ":foo" FROM Foo WHERE bar IN (:name1, :name2)', false, array(37 => 'name1', 45 => 'name2')), + array("SELECT ':foo' FROM Foo WHERE bar IN (:name1, :name2)", false, array(37 => 'name1', 45 => 'name2')), + array('SELECT :foo_id', false, array(7 => 'foo_id')), // Ticket DBAL-231 + ); + } + + /** + * @dataProvider dataGetPlaceholderPositions + * @param type $query + * @param type $isPositional + * @param type $expectedParamPos + */ + public function testGetPlaceholderPositions($query, $isPositional, $expectedParamPos) + { + $actualParamPos = SQLParserUtils::getPlaceholderPositions($query, $isPositional); + $this->assertEquals($expectedParamPos, $actualParamPos); + } + + static public function dataExpandListParameters() + { + return array( + // Positional: Very simple with one needle + array( + "SELECT * FROM Foo WHERE foo IN (?)", + array(array(1, 2, 3)), + array(Connection::PARAM_INT_ARRAY), + 'SELECT * FROM Foo WHERE foo IN (?, ?, ?)', + array(1, 2, 3), + array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT) + ), + // Positional: One non-list before d one after list-needle + array( + "SELECT * FROM Foo WHERE foo = ? AND bar IN (?)", + array("string", array(1, 2, 3)), + array(\PDO::PARAM_STR, Connection::PARAM_INT_ARRAY), + 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?)', + array("string", 1, 2, 3), + array(\PDO::PARAM_STR, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT) + ), + // Positional: One non-list after list-needle + array( + "SELECT * FROM Foo WHERE bar IN (?) AND baz = ?", + array(array(1, 2, 3), "foo"), + array(Connection::PARAM_INT_ARRAY, \PDO::PARAM_STR), + 'SELECT * FROM Foo WHERE bar IN (?, ?, ?) AND baz = ?', + array(1, 2, 3, "foo"), + array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_STR) + ), + // Positional: One non-list before and one after list-needle + array( + "SELECT * FROM Foo WHERE foo = ? AND bar IN (?) AND baz = ?", + array(1, array(1, 2, 3), 4), + array(\PDO::PARAM_INT, Connection::PARAM_INT_ARRAY, \PDO::PARAM_INT), + 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ?', + array(1, 1, 2, 3, 4), + array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT) + ), + // Positional: Two lists + array( + "SELECT * FROM Foo WHERE foo IN (?, ?)", + array(array(1, 2, 3), array(4, 5)), + array(Connection::PARAM_INT_ARRAY, Connection::PARAM_INT_ARRAY), + 'SELECT * FROM Foo WHERE foo IN (?, ?, ?, ?, ?)', + array(1, 2, 3, 4, 5), + array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT) + ), + // Positional : Empty "integer" array DDC-1978 + array( + "SELECT * FROM Foo WHERE foo IN (?)", + array('foo'=>array()), + array('foo'=>Connection::PARAM_INT_ARRAY), + 'SELECT * FROM Foo WHERE foo IN (?)', + array(), + array() + ), + // Positional : Empty "str" array DDC-1978 + array( + "SELECT * FROM Foo WHERE foo IN (?)", + array('foo'=>array()), + array('foo'=>Connection::PARAM_STR_ARRAY), + 'SELECT * FROM Foo WHERE foo IN (?)', + array(), + array() + ), + // Named parameters : Very simple with param int + array( + "SELECT * FROM Foo WHERE foo = :foo", + array('foo'=>1), + array('foo'=>\PDO::PARAM_INT), + 'SELECT * FROM Foo WHERE foo = ?', + array(1), + array(\PDO::PARAM_INT) + ), + + // Named parameters : Very simple with param int and string + array( + "SELECT * FROM Foo WHERE foo = :foo AND bar = :bar", + array('bar'=>'Some String','foo'=>1), + array('foo'=>\PDO::PARAM_INT,'bar'=>\PDO::PARAM_STR), + 'SELECT * FROM Foo WHERE foo = ? AND bar = ?', + array(1,'Some String'), + array(\PDO::PARAM_INT, \PDO::PARAM_STR) + ), + + // Named parameters : Very simple with one needle + array( + "SELECT * FROM Foo WHERE foo IN (:foo)", + array('foo'=>array(1, 2, 3)), + array('foo'=>Connection::PARAM_INT_ARRAY), + 'SELECT * FROM Foo WHERE foo IN (?, ?, ?)', + array(1, 2, 3), + array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT) + ), + // Named parameters: One non-list before d one after list-needle + array( + "SELECT * FROM Foo WHERE foo = :foo AND bar IN (:bar)", + array('foo'=>"string", 'bar'=>array(1, 2, 3)), + array('foo'=>\PDO::PARAM_STR, 'bar'=>Connection::PARAM_INT_ARRAY), + 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?)', + array("string", 1, 2, 3), + array(\PDO::PARAM_STR, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT) + ), + // Named parameters: One non-list after list-needle + array( + "SELECT * FROM Foo WHERE bar IN (:bar) AND baz = :baz", + array('bar'=>array(1, 2, 3), 'baz'=>"foo"), + array('bar'=>Connection::PARAM_INT_ARRAY, 'baz'=>\PDO::PARAM_STR), + 'SELECT * FROM Foo WHERE bar IN (?, ?, ?) AND baz = ?', + array(1, 2, 3, "foo"), + array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_STR) + ), + // Named parameters: One non-list before and one after list-needle + array( + "SELECT * FROM Foo WHERE foo = :foo AND bar IN (:bar) AND baz = :baz", + array('bar'=>array(1, 2, 3),'foo'=>1, 'baz'=>4), + array('bar'=>Connection::PARAM_INT_ARRAY, 'foo'=>\PDO::PARAM_INT, 'baz'=>\PDO::PARAM_INT), + 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ?', + array(1, 1, 2, 3, 4), + array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT) + ), + // Named parameters: Two lists + array( + "SELECT * FROM Foo WHERE foo IN (:a, :b)", + array('b'=>array(4, 5),'a'=>array(1, 2, 3)), + array('a'=>Connection::PARAM_INT_ARRAY, 'b'=>Connection::PARAM_INT_ARRAY), + 'SELECT * FROM Foo WHERE foo IN (?, ?, ?, ?, ?)', + array(1, 2, 3, 4, 5), + array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT) + ), + // Named parameters : With the same name arg type string + array( + "SELECT * FROM Foo WHERE foo <> :arg AND bar = :arg", + array('arg'=>"Some String"), + array('arg'=>\PDO::PARAM_STR), + 'SELECT * FROM Foo WHERE foo <> ? AND bar = ?', + array("Some String","Some String"), + array(\PDO::PARAM_STR,\PDO::PARAM_STR,) + ), + // Named parameters : With the same name arg + array( + "SELECT * FROM Foo WHERE foo IN (:arg) AND NOT bar IN (:arg)", + array('arg'=>array(1, 2, 3)), + array('arg'=>Connection::PARAM_INT_ARRAY), + 'SELECT * FROM Foo WHERE foo IN (?, ?, ?) AND NOT bar IN (?, ?, ?)', + array(1, 2, 3, 1, 2, 3), + array(\PDO::PARAM_INT,\PDO::PARAM_INT, \PDO::PARAM_INT,\PDO::PARAM_INT,\PDO::PARAM_INT, \PDO::PARAM_INT) + ), + + // Named parameters : Same name, other name in between DBAL-299 + array( + "SELECT * FROM Foo WHERE (:foo = 2) AND (:bar = 3) AND (:foo = 2)", + array('foo'=>2,'bar'=>3), + array('foo'=>\PDO::PARAM_INT,'bar'=>\PDO::PARAM_INT), + 'SELECT * FROM Foo WHERE (? = 2) AND (? = 3) AND (? = 2)', + array(2, 3, 2), + array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT) + ), + // Named parameters : Empty "integer" array DDC-1978 + array( + "SELECT * FROM Foo WHERE foo IN (:foo)", + array('foo'=>array()), + array('foo'=>Connection::PARAM_INT_ARRAY), + 'SELECT * FROM Foo WHERE foo IN (?)', + array(), + array() + ), + // Named parameters : Two empty "str" array DDC-1978 + array( + "SELECT * FROM Foo WHERE foo IN (:foo) OR bar IN (:bar)", + array('foo'=>array(), 'bar'=>array()), + array('foo'=>Connection::PARAM_STR_ARRAY, 'bar'=>Connection::PARAM_STR_ARRAY), + 'SELECT * FROM Foo WHERE foo IN (?) OR bar IN (?)', + array(), + array() + ), + ); + } + + /** + * @dataProvider dataExpandListParameters + * @param type $q + * @param type $p + * @param type $t + * @param type $expectedQuery + * @param type $expectedParams + * @param type $expectedTypes + */ + public function testExpandListParameters($q, $p, $t, $expectedQuery, $expectedParams, $expectedTypes) + { + list($query, $params, $types) = SQLParserUtils::expandListParameters($q, $p, $t); + + $this->assertEquals($expectedQuery, $query, "Query was not rewritten correctly."); + $this->assertEquals($expectedParams, $params, "Params dont match"); + $this->assertEquals($expectedTypes, $types, "Types dont match"); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/ColumnTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/ColumnTest.php new file mode 100644 index 0000000..2051061 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/ColumnTest.php @@ -0,0 +1,114 @@ +createColumn(); + + $this->assertEquals("foo", $column->getName()); + $this->assertSame(Type::getType('string'), $column->getType()); + + $this->assertEquals(200, $column->getLength()); + $this->assertEquals(5, $column->getPrecision()); + $this->assertEquals(2, $column->getScale()); + $this->assertTrue($column->getUnsigned()); + $this->assertFalse($column->getNotNull()); + $this->assertTrue($column->getFixed()); + $this->assertEquals("baz", $column->getDefault()); + + $this->assertEquals(array('foo' => 'bar'), $column->getPlatformOptions()); + $this->assertTrue($column->hasPlatformOption('foo')); + $this->assertEquals('bar', $column->getPlatformOption('foo')); + $this->assertFalse($column->hasPlatformOption('bar')); + + $this->assertEquals(array('bar' => 'baz'), $column->getCustomSchemaOptions()); + $this->assertTrue($column->hasCustomSchemaOption('bar')); + $this->assertEquals('baz', $column->getCustomSchemaOption('bar')); + $this->assertFalse($column->hasCustomSchemaOption('foo')); + } + + public function testToArray() + { + $expected = array( + 'name' => 'foo', + 'type' => Type::getType('string'), + 'default' => 'baz', + 'notnull' => false, + 'length' => 200, + 'precision' => 5, + 'scale' => 2, + 'fixed' => true, + 'unsigned' => true, + 'autoincrement' => false, + 'columnDefinition' => null, + 'comment' => null, + 'foo' => 'bar', + 'bar' => 'baz' + ); + + $this->assertEquals($expected, $this->createColumn()->toArray()); + } + + /** + * @return Column + */ + public function createColumn() + { + $options = array( + 'length' => 200, + 'precision' => 5, + 'scale' => 2, + 'unsigned' => true, + 'notnull' => false, + 'fixed' => true, + 'default' => 'baz', + 'platformOptions' => array('foo' => 'bar'), + 'customSchemaOptions' => array('bar' => 'baz'), + ); + + $string = Type::getType('string'); + return new Column("foo", $string, $options); + } + + /** + * @group DBAL-64 + */ + public function testQuotedColumnName() + { + $string = Type::getType('string'); + $column = new Column("`bar`", $string, array()); + + $mysqlPlatform = new \Doctrine\DBAL\Platforms\MySqlPlatform(); + $sqlitePlatform = new \Doctrine\DBAL\Platforms\SqlitePlatform(); + + $this->assertEquals('bar', $column->getName()); + $this->assertEquals('`bar`', $column->getQuotedName($mysqlPlatform)); + $this->assertEquals('"bar"', $column->getQuotedName($sqlitePlatform)); + } + + /** + * @group DBAL-42 + */ + public function testColumnComment() + { + $column = new Column("bar", Type::getType('string')); + $this->assertNull($column->getComment()); + + $column->setComment("foo"); + $this->assertEquals("foo", $column->getComment()); + + $columnArray = $column->toArray(); + $this->assertArrayHasKey('comment', $columnArray); + $this->assertEquals('foo', $columnArray['comment']); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php new file mode 100644 index 0000000..c3fcdce --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php @@ -0,0 +1,809 @@ +. + */ + +namespace Doctrine\Tests\DBAL\Schema; + +require_once __DIR__ . '/../../TestInit.php'; + +use Doctrine\DBAL\Schema\Schema, + Doctrine\DBAL\Schema\SchemaConfig, + Doctrine\DBAL\Schema\Table, + Doctrine\DBAL\Schema\Column, + Doctrine\DBAL\Schema\Index, + Doctrine\DBAL\Schema\Sequence, + Doctrine\DBAL\Schema\SchemaDiff, + Doctrine\DBAL\Schema\TableDiff, + Doctrine\DBAL\Schema\Comparator, + Doctrine\DBAL\Types\Type, + Doctrine\DBAL\Schema\ForeignKeyConstraint; + +/** + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + */ +class ComparatorTest extends \PHPUnit_Framework_TestCase +{ + public function testCompareSame1() + { + $schema1 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer' ) ), + ) + ), + ) ); + $schema2 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer') ), + ) + ), + ) ); + + $this->assertEquals(new SchemaDiff(), Comparator::compareSchemas( $schema1, $schema2 ) ); + } + + public function testCompareSame2() + { + $schema1 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ) + ), + ) ); + $schema2 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + ) + ), + ) ); + $this->assertEquals(new SchemaDiff(), Comparator::compareSchemas( $schema1, $schema2 ) ); + } + + public function testCompareMissingTable() + { + $schemaConfig = new \Doctrine\DBAL\Schema\SchemaConfig; + $table = new Table('bugdb', array ('integerfield1' => new Column('integerfield1', Type::getType('integer')))); + $table->setSchemaConfig($schemaConfig); + + $schema1 = new Schema( array($table), array(), $schemaConfig ); + $schema2 = new Schema( array(), array(), $schemaConfig ); + + $expected = new SchemaDiff( array(), array(), array('bugdb' => $table) ); + + $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); + } + + public function testCompareNewTable() + { + $schemaConfig = new \Doctrine\DBAL\Schema\SchemaConfig; + $table = new Table('bugdb', array ('integerfield1' => new Column('integerfield1', Type::getType('integer')))); + $table->setSchemaConfig($schemaConfig); + + $schema1 = new Schema( array(), array(), $schemaConfig ); + $schema2 = new Schema( array($table), array(), $schemaConfig ); + + $expected = new SchemaDiff( array('bugdb' => $table), array(), array() ); + $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); + } + + public function testCompareOnlyAutoincrementChanged() + { + $column1 = new Column('foo', Type::getType('integer'), array('autoincrement' => true)); + $column2 = new Column('foo', Type::getType('integer'), array('autoincrement' => false)); + + $comparator = new Comparator(); + $changedProperties = $comparator->diffColumn($column1, $column2); + + $this->assertEquals(array('autoincrement'), $changedProperties); + } + + public function testCompareMissingField() + { + $missingColumn = new Column('integerfield1', Type::getType('integer')); + $schema1 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => $missingColumn, + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ) + ), + ) ); + $schema2 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ) + ), + ) ); + + $expected = new SchemaDiff ( array(), + array ( + 'bugdb' => new TableDiff( 'bugdb', array(), array(), + array ( + 'integerfield1' => $missingColumn, + ) + ) + ) + ); + $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); + } + + public function testCompareNewField() + { + $schema1 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + ) + ), + ) ); + $schema2 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ) + ), + ) ); + + $expected = new SchemaDiff ( array(), + array ( + 'bugdb' => new TableDiff ('bugdb', + array ( + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ) + ), + ) + ); + $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); + } + + public function testCompareChangedColumns_ChangeType() + { + $column1 = new Column('charfield1', Type::getType('string')); + $column2 = new Column('charfield1', Type::getType('integer')); + + $c = new Comparator(); + $this->assertEquals(array('type'), $c->diffColumn($column1, $column2)); + $this->assertEquals(array(), $c->diffColumn($column1, $column1)); + } + + public function testCompareChangedColumns_ChangeCustomSchemaOption() + { + $column1 = new Column('charfield1', Type::getType('string')); + $column2 = new Column('charfield1', Type::getType('string')); + + $column1->setCustomSchemaOption('foo', 'bar'); + $column2->setCustomSchemaOption('foo', 'bar'); + + $column1->setCustomSchemaOption('foo1', 'bar1'); + $column2->setCustomSchemaOption('foo2', 'bar2'); + + $c = new Comparator(); + $this->assertEquals(array('foo1', 'foo2'), $c->diffColumn($column1, $column2)); + $this->assertEquals(array(), $c->diffColumn($column1, $column1)); + } + + public function testCompareRemovedIndex() + { + $schema1 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ), + array ( + 'primary' => new Index('primary', + array( + 'integerfield1' + ), + true + ) + ) + ), + ) ); + $schema2 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ) + ), + ) ); + + $expected = new SchemaDiff ( array(), + array ( + 'bugdb' => new TableDiff( 'bugdb', array(), array(), array(), array(), array(), + array ( + 'primary' => new Index('primary', + array( + 'integerfield1' + ), + true + ) + ) + ), + ) + ); + $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); + } + + public function testCompareNewIndex() + { + $schema1 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ) + ), + ) ); + $schema2 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ), + array ( + 'primary' => new Index('primary', + array( + 'integerfield1' + ), + true + ) + ) + ), + ) ); + + $expected = new SchemaDiff ( array(), + array ( + 'bugdb' => new TableDiff( 'bugdb', array(), array(), array(), + array ( + 'primary' => new Index('primary', + array( + 'integerfield1' + ), + true + ) + ) + ), + ) + ); + $this->assertEquals($expected, Comparator::compareSchemas( $schema1, $schema2 ) ); + } + + public function testCompareChangedIndex() + { + $schema1 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ), + array ( + 'primary' => new Index('primary', + array( + 'integerfield1' + ), + true + ) + ) + ), + ) ); + $schema2 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ), + array ( + 'primary' => new Index('primary', + array('integerfield1', 'integerfield2'), + true + ) + ) + ), + ) ); + + $expected = new SchemaDiff ( array(), + array ( + 'bugdb' => new TableDiff( 'bugdb', array(), array(), array(), array(), + array ( + 'primary' => new Index('primary', + array( + 'integerfield1', + 'integerfield2' + ), + true + ) + ) + ), + ) + ); + $actual = Comparator::compareSchemas( $schema1, $schema2 ); + $this->assertEquals($expected, $actual); + } + + public function testCompareChangedIndexFieldPositions() + { + $schema1 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ), + array ( + 'primary' => new Index('primary', array('integerfield1', 'integerfield2'), true) + ) + ), + ) ); + $schema2 = new Schema( array( + 'bugdb' => new Table('bugdb', + array ( + 'integerfield1' => new Column('integerfield1', Type::getType('integer')), + 'integerfield2' => new Column('integerfield2', Type::getType('integer')), + ), + array ( + 'primary' => new Index('primary', array('integerfield2', 'integerfield1'), true) + ) + ), + ) ); + + $expected = new SchemaDiff ( array(), + array ( + 'bugdb' => new TableDiff('bugdb', array(), array(), array(), array(), + array ( + 'primary' => new Index('primary', array('integerfield2', 'integerfield1'), true) + ) + ), + ) + ); + $actual = Comparator::compareSchemas( $schema1, $schema2 ); + $this->assertEquals($expected, $actual); + } + + public function testCompareSequences() + { + $seq1 = new Sequence('foo', 1, 1); + $seq2 = new Sequence('foo', 1, 2); + $seq3 = new Sequence('foo', 2, 1); + + $c = new Comparator(); + + $this->assertTrue($c->diffSequence($seq1, $seq2)); + $this->assertTrue($c->diffSequence($seq1, $seq3)); + } + + public function testRemovedSequence() + { + $schema1 = new Schema(); + $seq = $schema1->createSequence('foo'); + + $schema2 = new Schema(); + + $c = new Comparator(); + $diffSchema = $c->compare($schema1, $schema2); + + $this->assertEquals(1, count($diffSchema->removedSequences)); + $this->assertSame($seq, $diffSchema->removedSequences[0]); + } + + public function testAddedSequence() + { + $schema1 = new Schema(); + + $schema2 = new Schema(); + $seq = $schema2->createSequence('foo'); + + $c = new Comparator(); + $diffSchema = $c->compare($schema1, $schema2); + + $this->assertEquals(1, count($diffSchema->newSequences)); + $this->assertSame($seq, $diffSchema->newSequences[0]); + } + + public function testTableAddForeignKey() + { + $tableForeign = new Table("bar"); + $tableForeign->addColumn('id', 'integer'); + + $table1 = new Table("foo"); + $table1->addColumn('fk', 'integer'); + + $table2 = new Table("foo"); + $table2->addColumn('fk', 'integer'); + $table2->addForeignKeyConstraint($tableForeign, array('fk'), array('id')); + + $c = new Comparator(); + $tableDiff = $c->diffTable($table1, $table2); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff); + $this->assertEquals(1, count($tableDiff->addedForeignKeys)); + } + + public function testTableRemoveForeignKey() + { + $tableForeign = new Table("bar"); + $tableForeign->addColumn('id', 'integer'); + + $table1 = new Table("foo"); + $table1->addColumn('fk', 'integer'); + + $table2 = new Table("foo"); + $table2->addColumn('fk', 'integer'); + $table2->addForeignKeyConstraint($tableForeign, array('fk'), array('id')); + + $c = new Comparator(); + $tableDiff = $c->diffTable($table2, $table1); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff); + $this->assertEquals(1, count($tableDiff->removedForeignKeys)); + } + + public function testTableUpdateForeignKey() + { + $tableForeign = new Table("bar"); + $tableForeign->addColumn('id', 'integer'); + + $table1 = new Table("foo"); + $table1->addColumn('fk', 'integer'); + $table1->addForeignKeyConstraint($tableForeign, array('fk'), array('id')); + + $table2 = new Table("foo"); + $table2->addColumn('fk', 'integer'); + $table2->addForeignKeyConstraint($tableForeign, array('fk'), array('id'), array('onUpdate' => 'CASCADE')); + + $c = new Comparator(); + $tableDiff = $c->diffTable($table1, $table2); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff); + $this->assertEquals(1, count($tableDiff->changedForeignKeys)); + } + + public function testTablesCaseInsensitive() + { + $schemaA = new Schema(); + $schemaA->createTable('foo'); + $schemaA->createTable('bAr'); + $schemaA->createTable('BAZ'); + $schemaA->createTable('new'); + + $schemaB = new Schema(); + $schemaB->createTable('FOO'); + $schemaB->createTable('bar'); + $schemaB->createTable('Baz'); + $schemaB->createTable('old'); + + $c = new Comparator(); + $diff = $c->compare($schemaA, $schemaB); + + $this->assertSchemaTableChangeCount($diff, 1, 0, 1); + } + + public function testSequencesCaseInsenstive() + { + $schemaA = new Schema(); + $schemaA->createSequence('foo'); + $schemaA->createSequence('BAR'); + $schemaA->createSequence('Baz'); + $schemaA->createSequence('new'); + + $schemaB = new Schema(); + $schemaB->createSequence('FOO'); + $schemaB->createSequence('Bar'); + $schemaB->createSequence('baz'); + $schemaB->createSequence('old'); + + $c = new Comparator(); + $diff = $c->compare($schemaA, $schemaB); + + $this->assertSchemaSequenceChangeCount($diff, 1, 0, 1); + } + + public function testCompareColumnCompareCaseInsensitive() + { + $tableA = new Table("foo"); + $tableA->addColumn('id', 'integer'); + + $tableB = new Table("foo"); + $tableB->addColumn('ID', 'integer'); + + $c = new Comparator(); + $tableDiff = $c->diffTable($tableA, $tableB); + + $this->assertFalse($tableDiff); + } + + public function testCompareIndexBasedOnPropertiesNotName() + { + $tableA = new Table("foo"); + $tableA->addColumn('id', 'integer'); + $tableA->addIndex(array("id"), "foo_bar_idx"); + + $tableB = new Table("foo"); + $tableB->addColumn('ID', 'integer'); + $tableB->addIndex(array("id"), "bar_foo_idx"); + + $c = new Comparator(); + $tableDiff = $c->diffTable($tableA, $tableB); + + $this->assertFalse($tableDiff); + } + + public function testCompareForeignKeyBasedOnPropertiesNotName() + { + $tableA = new Table("foo"); + $tableA->addColumn('id', 'integer'); + $tableA->addNamedForeignKeyConstraint('foo_constraint', 'bar', array('id'), array('id')); + + $tableB = new Table("foo"); + $tableB->addColumn('ID', 'integer'); + $tableB->addNamedForeignKeyConstraint('bar_constraint', 'bar', array('id'), array('id')); + + $c = new Comparator(); + $tableDiff = $c->diffTable($tableA, $tableB); + + $this->assertFalse($tableDiff); + } + + public function testCompareForeignKey_RestrictNoAction_AreTheSame() + { + $fk1 = new ForeignKeyConstraint(array("foo"), "bar", array("baz"), "fk1", array('onDelete' => 'NO ACTION')); + $fk2 = new ForeignKeyConstraint(array("foo"), "bar", array("baz"), "fk1", array('onDelete' => 'RESTRICT')); + + $c = new Comparator(); + $this->assertFalse($c->diffForeignKey($fk1, $fk2)); + } + + public function testDetectRenameColumn() + { + $tableA = new Table("foo"); + $tableA->addColumn('foo', 'integer'); + + $tableB = new Table("foo"); + $tableB->addColumn('bar', 'integer'); + + $c = new Comparator(); + $tableDiff = $c->diffTable($tableA, $tableB); + + $this->assertEquals(0, count($tableDiff->addedColumns)); + $this->assertEquals(0, count($tableDiff->removedColumns)); + $this->assertArrayHasKey('foo', $tableDiff->renamedColumns); + $this->assertEquals('bar', $tableDiff->renamedColumns['foo']->getName()); + } + + /** + * You can easily have ambiguouties in the column renaming. If these + * are detected no renaming should take place, instead adding and dropping + * should be used exclusively. + * + * @group DBAL-24 + */ + public function testDetectRenameColumnAmbiguous() + { + $tableA = new Table("foo"); + $tableA->addColumn('foo', 'integer'); + $tableA->addColumn('bar', 'integer'); + + $tableB = new Table("foo"); + $tableB->addColumn('baz', 'integer'); + + $c = new Comparator(); + $tableDiff = $c->diffTable($tableA, $tableB); + + $this->assertEquals(1, count($tableDiff->addedColumns), "'baz' should be added, not created through renaming!"); + $this->assertArrayHasKey('baz', $tableDiff->addedColumns, "'baz' should be added, not created through renaming!"); + $this->assertEquals(2, count($tableDiff->removedColumns), "'foo' and 'bar' should both be dropped, an ambigouty exists which one could be renamed to 'baz'."); + $this->assertArrayHasKey('foo', $tableDiff->removedColumns, "'foo' should be removed."); + $this->assertArrayHasKey('bar', $tableDiff->removedColumns, "'bar' should be removed."); + $this->assertEquals(0, count($tableDiff->renamedColumns), "no renamings should take place."); + } + + public function testDetectChangeIdentifierType() + { + $this->markTestSkipped('DBAL-2 was reopened, this test cannot work anymore.'); + + $tableA = new Table("foo"); + $tableA->addColumn('id', 'integer', array('autoincrement' => false)); + + $tableB = new Table("foo"); + $tableB->addColumn('id', 'integer', array('autoincrement' => true)); + + $c = new Comparator(); + $tableDiff = $c->diffTable($tableA, $tableB); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff); + $this->assertArrayHasKey('id', $tableDiff->changedColumns); + } + + + /** + * @group DBAL-105 + */ + public function testDiff() + { + $table = new \Doctrine\DBAL\Schema\Table('twitter_users'); + $table->addColumn('id', 'integer', array('autoincrement' => true)); + $table->addColumn('twitterId', 'integer', array('nullable' => false)); + $table->addColumn('displayName', 'string', array('nullable' => false)); + $table->setPrimaryKey(array('id')); + + $newtable = new \Doctrine\DBAL\Schema\Table('twitter_users'); + $newtable->addColumn('id', 'integer', array('autoincrement' => true)); + $newtable->addColumn('twitter_id', 'integer', array('nullable' => false)); + $newtable->addColumn('display_name', 'string', array('nullable' => false)); + $newtable->addColumn('logged_in_at', 'datetime', array('nullable' => true)); + $newtable->setPrimaryKey(array('id')); + + $c = new Comparator(); + $tableDiff = $c->diffTable($table, $newtable); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff); + $this->assertEquals(array('twitterid', 'displayname'), array_keys($tableDiff->renamedColumns)); + $this->assertEquals(array('logged_in_at'), array_keys($tableDiff->addedColumns)); + $this->assertEquals(0, count($tableDiff->removedColumns)); + } + + + /** + * @group DBAL-112 + */ + public function testChangedSequence() + { + $schema = new Schema(); + $sequence = $schema->createSequence('baz'); + + $schemaNew = clone $schema; + /* @var $schemaNew Schema */ + $schemaNew->getSequence('baz')->setAllocationSize(20); + + $c = new \Doctrine\DBAL\Schema\Comparator; + $diff = $c->compare($schema, $schemaNew); + + $this->assertSame($diff->changedSequences[0] , $schemaNew->getSequence('baz')); + } + + /** + * @group DBAL-106 + */ + public function testDiffDecimalWithNullPrecision() + { + $column = new Column('foo', Type::getType('decimal')); + $column->setPrecision(null); + + $column2 = new Column('foo', Type::getType('decimal')); + + $c = new Comparator(); + $this->assertEquals(array(), $c->diffColumn($column, $column2)); + } + + /** + * @group DBAL-204 + */ + public function testFqnSchemaComparision() + { + $config = new SchemaConfig(); + $config->setName("foo"); + + $oldSchema = new Schema(array(), array(), $config); + $oldSchema->createTable('bar'); + + $newSchema= new Schema(array(), array(), $config); + $newSchema->createTable('foo.bar'); + + $c = new Comparator(); + $this->assertEquals(new SchemaDiff(), $c->compare($oldSchema, $newSchema)); + } + + /** + * @group DBAL-204 + */ + public function testFqnSchemaComparisionDifferentSchemaNameButSameTableNoDiff() + { + $config = new SchemaConfig(); + $config->setName("foo"); + + $oldSchema = new Schema(array(), array(), $config); + $oldSchema->createTable('foo.bar'); + + $newSchema = new Schema(); + $newSchema->createTable('bar'); + + $c = new Comparator(); + $diff = $c->compare($oldSchema, $newSchema); + $this->assertEquals(new SchemaDiff(), $c->compare($oldSchema, $newSchema)); + } + + /** + * @group DBAL-204 + */ + public function testFqnSchemaComparisionNoSchemaSame() + { + $config = new SchemaConfig(); + $config->setName("foo"); + $oldSchema = new Schema(array(), array(), $config); + $oldSchema->createTable('bar'); + + $newSchema = new Schema(); + $newSchema->createTable('bar'); + + $c = new Comparator(); + $diff = $c->compare($oldSchema, $newSchema); + + $this->assertEquals(new SchemaDiff(), $c->compare($oldSchema, $newSchema)); + } + + /** + * @group DDC-1657 + */ + public function testAutoIncremenetSequences() + { + $oldSchema = new Schema(); + $table = $oldSchema->createTable("foo"); + $table->addColumn("id", "integer", array("autoincrement" => true)); + $table->setPrimaryKey(array("id")); + $oldSchema->createSequence("foo_id_seq"); + + $newSchema = new Schema(); + $table = $newSchema->createTable("foo"); + $table->addColumn("id", "integer", array("autoincrement" => true)); + $table->setPrimaryKey(array("id")); + + $c = new Comparator(); + $diff = $c->compare($oldSchema, $newSchema); + + $this->assertCount(0, $diff->removedSequences); + } + + /** + * @param SchemaDiff $diff + * @param int $newTableCount + * @param int $changeTableCount + * @param int $removeTableCount + */ + public function assertSchemaTableChangeCount($diff, $newTableCount=0, $changeTableCount=0, $removeTableCount=0) + { + $this->assertEquals($newTableCount, count($diff->newTables)); + $this->assertEquals($changeTableCount, count($diff->changedTables)); + $this->assertEquals($removeTableCount, count($diff->removedTables)); + } + + /** + * @param SchemaDiff $diff + * @param int $newSequenceCount + * @param int $changeSequenceCount + * @param int $changeSequenceCount + */ + public function assertSchemaSequenceChangeCount($diff, $newSequenceCount=0, $changeSequenceCount=0, $removeSequenceCount=0) + { + $this->assertEquals($newSequenceCount, count($diff->newSequences), "Expected number of new sequences is wrong."); + $this->assertEquals($changeSequenceCount, count($diff->changedSequences), "Expected number of changed sequences is wrong."); + $this->assertEquals($removeSequenceCount, count($diff->removedSequences), "Expected number of removed sequences is wrong."); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/IndexTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/IndexTest.php new file mode 100644 index 0000000..ed6b070 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/IndexTest.php @@ -0,0 +1,115 @@ +createIndex(); + $this->assertEquals("foo", $idx->getName()); + $columns = $idx->getColumns(); + $this->assertEquals(2, count($columns)); + $this->assertEquals(array("bar", "baz"), $columns); + $this->assertFalse($idx->isUnique()); + $this->assertFalse($idx->isPrimary()); + } + + public function testCreatePrimary() + { + $idx = $this->createIndex(false, true); + $this->assertTrue($idx->isUnique()); + $this->assertTrue($idx->isPrimary()); + } + + public function testCreateUnique() + { + $idx = $this->createIndex(true, false); + $this->assertTrue($idx->isUnique()); + $this->assertFalse($idx->isPrimary()); + } + + /** + * @group DBAL-50 + */ + public function testFullfilledByUnique() + { + $idx1 = $this->createIndex(true, false); + $idx2 = $this->createIndex(true, false); + $idx3 = $this->createIndex(); + + $this->assertTrue($idx1->isFullfilledBy($idx2)); + $this->assertFalse($idx1->isFullfilledBy($idx3)); + } + + /** + * @group DBAL-50 + */ + public function testFullfilledByPrimary() + { + $idx1 = $this->createIndex(true, true); + $idx2 = $this->createIndex(true, true); + $idx3 = $this->createIndex(true, false); + + $this->assertTrue($idx1->isFullfilledBy($idx2)); + $this->assertFalse($idx1->isFullfilledBy($idx3)); + } + + /** + * @group DBAL-50 + */ + public function testFullfilledByIndex() + { + $idx1 = $this->createIndex(); + $idx2 = $this->createIndex(); + $pri = $this->createIndex(true, true); + $uniq = $this->createIndex(true); + + $this->assertTrue($idx1->isFullfilledBy($idx2)); + $this->assertTrue($idx1->isFullfilledBy($pri)); + $this->assertTrue($idx1->isFullfilledBy($uniq)); + } + + /** + * @group DBAL-220 + */ + public function testFlags() + { + $idx1 = $this->createIndex(); + $this->assertFalse($idx1->hasFlag('clustered')); + + $idx1->addFlag('clustered'); + $this->assertTrue($idx1->hasFlag('clustered')); + $this->assertTrue($idx1->hasFlag('CLUSTERED')); + + $idx1->removeFlag('clustered'); + $this->assertFalse($idx1->hasFlag('clustered')); + } + + /** + * @group DBAL-285 + */ + public function testIndexQuotes() + { + $index = new Index("foo", array("`bar`", "`baz`")); + + $this->assertTrue($index->spansColumns(array("bar", "baz"))); + $this->assertTrue($index->hasColumnAtPosition("bar", 0)); + $this->assertTrue($index->hasColumnAtPosition("baz", 1)); + + $this->assertFalse($index->hasColumnAtPosition("bar", 1)); + $this->assertFalse($index->hasColumnAtPosition("baz", 0)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php new file mode 100644 index 0000000..ff093fb --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php @@ -0,0 +1,74 @@ +getMock('Doctrine\DBAL\Driver'); + $platform = $this->getMock('Doctrine\DBAL\Platforms\MySqlPlatform'); + $this->conn = $this->getMock( + 'Doctrine\DBAL\Connection', + array('fetchAll'), + array(array('platform' => $platform), $driverMock, new Configuration(), $eventManager) + ); + $this->manager = new MySqlSchemaManager($this->conn); + } + + public function testCompositeForeignKeys() + { + $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue($this->getFKDefinition())); + $fkeys = $this->manager->listTableForeignKeys('dummy'); + $this->assertEquals(1, count($fkeys), "Table has to have one foreign key."); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $fkeys[0]); + $this->assertEquals(array('column_1', 'column_2', 'column_3'), array_map('strtolower', $fkeys[0]->getLocalColumns())); + $this->assertEquals(array('column_1', 'column_2', 'column_3'), array_map('strtolower', $fkeys[0]->getForeignColumns())); + } + + public function getFKDefinition() + { + return array( + array( + "CONSTRAINT_NAME" => "FK_C1B1712387FE737264DE5A5511B8B3E", + "COLUMN_NAME" => "column_1", + "REFERENCED_TABLE_NAME" => "dummy", + "REFERENCED_COLUMN_NAME" => "column_1", + "update_rule" => "RESTRICT", + "delete_rule" => "RESTRICT", + ), + array( + "CONSTRAINT_NAME" => "FK_C1B1712387FE737264DE5A5511B8B3E", + "COLUMN_NAME" => "column_2", + "REFERENCED_TABLE_NAME" => "dummy", + "REFERENCED_COLUMN_NAME" => "column_2", + "update_rule" => "RESTRICT", + "delete_rule" => "RESTRICT", + ), + array( + "CONSTRAINT_NAME" => "FK_C1B1712387FE737264DE5A5511B8B3E", + "COLUMN_NAME" => "column_3", + "REFERENCED_TABLE_NAME" => "dummy", + "REFERENCED_COLUMN_NAME" => "column_3", + "update_rule" => "RESTRICT", + "delete_rule" => "RESTRICT", + ) + ); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Platforms/MySQLSchemaTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Platforms/MySQLSchemaTest.php new file mode 100644 index 0000000..651a5ee --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Platforms/MySQLSchemaTest.php @@ -0,0 +1,88 @@ +comparator = new \Doctrine\DBAL\Schema\Comparator; + $this->platform = new \Doctrine\DBAL\Platforms\MySqlPlatform; + } + + public function testSwitchPrimaryKeyOrder() + { + $tableOld = new Table("test"); + $tableOld->addColumn('foo_id', 'integer'); + $tableOld->addColumn('bar_id', 'integer'); + $tableNew = clone $tableOld; + + $tableOld->setPrimaryKey(array('foo_id', 'bar_id')); + $tableNew->setPrimaryKey(array('bar_id', 'foo_id')); + + $diff = $this->comparator->diffTable($tableOld, $tableNew); + $sql = $this->platform->getAlterTableSQL($diff); + + $this->assertEquals( + array( + 'ALTER TABLE test DROP PRIMARY KEY', + 'ALTER TABLE test ADD PRIMARY KEY (bar_id, foo_id)' + ), $sql + ); + } + + /** + * @group DBAL-132 + */ + public function testGenerateForeignKeySQL() + { + $tableOld = new Table("test"); + $tableOld->addColumn('foo_id', 'integer'); + $tableOld->addUnnamedForeignKeyConstraint('test_foreign', array('foo_id'), array('foo_id')); + + $sqls = array(); + foreach ($tableOld->getForeignKeys() AS $fk) { + $sqls[] = $this->platform->getCreateForeignKeySQL($fk, $tableOld); + } + + $this->assertEquals(array("ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C8E48560F FOREIGN KEY (foo_id) REFERENCES test_foreign (foo_id)"), $sqls); + } + + /** + * @group DDC-1737 + */ + public function testClobNoAlterTable() + { + $tableOld = new Table("test"); + $tableOld->addColumn('id', 'integer'); + $tableOld->addColumn('description', 'string', array('length' => 65536)); + $tableNew = clone $tableOld; + + $tableNew->setPrimaryKey(array('id')); + + $diff = $this->comparator->diffTable($tableOld, $tableNew); + $sql = $this->platform->getAlterTableSQL($diff); + + $this->assertEquals( + array('ALTER TABLE test ADD PRIMARY KEY (id)'), + $sql + ); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php new file mode 100644 index 0000000..16bf92a --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php @@ -0,0 +1,109 @@ +createSchemaDiff(); + $platform = $this->createPlatform(true); + + $sql = $diff->toSql($platform); + + $expected = array('drop_orphan_fk', 'alter_seq', 'drop_seq', 'create_seq', 'create_table', 'create_foreign_key', 'drop_table', 'alter_table'); + + $this->assertEquals($expected, $sql); + } + + public function testSchemaDiffToSaveSql() + { + $diff = $this->createSchemaDiff(); + $platform = $this->createPlatform(false); + + $sql = $diff->toSaveSql($platform); + + $expected = array('alter_seq', 'create_seq', 'create_table', 'create_foreign_key', 'alter_table'); + + $this->assertEquals($expected, $sql); + } + + public function createPlatform($unsafe = false) + { + $platform = $this->getMock('Doctrine\Tests\DBAL\Mocks\MockPlatform'); + if ($unsafe) { + $platform->expects($this->exactly(1)) + ->method('getDropSequenceSql') + ->with($this->isInstanceOf('Doctrine\DBAL\Schema\Sequence')) + ->will($this->returnValue('drop_seq')); + } + $platform->expects($this->exactly(1)) + ->method('getAlterSequenceSql') + ->with($this->isInstanceOf('Doctrine\DBAL\Schema\Sequence')) + ->will($this->returnValue('alter_seq')); + $platform->expects($this->exactly(1)) + ->method('getCreateSequenceSql') + ->with($this->isInstanceOf('Doctrine\DBAL\Schema\Sequence')) + ->will($this->returnValue('create_seq')); + if ($unsafe) { + $platform->expects($this->exactly(1)) + ->method('getDropTableSql') + ->with($this->isInstanceof('Doctrine\DBAL\Schema\Table')) + ->will($this->returnValue('drop_table')); + } + $platform->expects($this->exactly(1)) + ->method('getCreateTableSql') + ->with($this->isInstanceof('Doctrine\DBAL\Schema\Table')) + ->will($this->returnValue(array('create_table'))); + $platform->expects($this->exactly(1)) + ->method('getCreateForeignKeySQL') + ->with($this->isInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint')) + ->will($this->returnValue('create_foreign_key')); + $platform->expects($this->exactly(1)) + ->method('getAlterTableSql') + ->with($this->isInstanceOf('Doctrine\DBAL\Schema\TableDiff')) + ->will($this->returnValue(array('alter_table'))); + if ($unsafe) { + $platform->expects($this->exactly(1)) + ->method('getDropForeignKeySql') + ->with($this->isInstanceof('Doctrine\DBAL\Schema\ForeignKeyConstraint'), $this->equalTo('local_table')) + ->will($this->returnValue('drop_orphan_fk')); + } + $platform->expects($this->exactly(1)) + ->method('supportsSequences') + ->will($this->returnValue(true)); + $platform->expects($this->exactly(2)) + ->method('supportsForeignKeyConstraints') + ->will($this->returnValue(true)); + return $platform; + } + + public function createSchemaDiff() + { + $diff = new SchemaDiff(); + $diff->changedSequences['foo_seq'] = new Sequence('foo_seq'); + $diff->newSequences['bar_seq'] = new Sequence('bar_seq'); + $diff->removedSequences['baz_seq'] = new Sequence('baz_seq'); + $diff->newTables['foo_table'] = new Table('foo_table'); + $diff->removedTables['bar_table'] = new Table('bar_table'); + $diff->changedTables['baz_table'] = new TableDiff('baz_table'); + $diff->newTables['foo_table']->addColumn('foreign_id', 'integer'); + $diff->newTables['foo_table']->addForeignKeyConstraint('foreign_table', array('foreign_id'), array('id')); + $fk = new \Doctrine\DBAL\Schema\ForeignKeyConstraint(array('id'), 'foreign_table', array('id')); + $fk->setLocalTable(new Table('local_table')); + $diff->orphanedForeignKeys[] = $fk; + return $diff; + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php new file mode 100644 index 0000000..096ede7 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php @@ -0,0 +1,224 @@ +assertTrue($schema->hasTable($tableName)); + + $tables = $schema->getTables(); + $this->assertTrue( isset($tables[$tableName]) ); + $this->assertSame($table, $tables[$tableName]); + $this->assertSame($table, $schema->getTable($tableName)); + $this->assertTrue($schema->hasTable($tableName)); + } + + public function testTableMatchingCaseInsenstive() + { + $table = new Table("Foo"); + + $schema = new Schema(array($table)); + $this->assertTrue($schema->hasTable("foo")); + $this->assertTrue($schema->hasTable("FOO")); + + $this->assertSame($table, $schema->getTable('FOO')); + $this->assertSame($table, $schema->getTable('foo')); + $this->assertSame($table, $schema->getTable('Foo')); + } + + public function testGetUnknownTableThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $schema = new Schema(); + $schema->getTable("unknown"); + } + + public function testCreateTableTwiceThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $tableName = "foo"; + $table = new Table($tableName); + $tables = array($table, $table); + + $schema = new Schema($tables); + } + + public function testRenameTable() + { + $tableName = "foo"; + $table = new Table($tableName); + $schema = new Schema(array($table)); + + $this->assertTrue($schema->hasTable("foo")); + $schema->renameTable("foo", "bar"); + $this->assertFalse($schema->hasTable("foo")); + $this->assertTrue($schema->hasTable("bar")); + $this->assertSame($table, $schema->getTable("bar")); + } + + public function testDropTable() + { + $tableName = "foo"; + $table = new Table($tableName); + $schema = new Schema(array($table)); + + $this->assertTrue($schema->hasTable("foo")); + + $schema->dropTable("foo"); + + $this->assertFalse($schema->hasTable("foo")); + } + + public function testCreateTable() + { + $schema = new Schema(); + + $this->assertFalse($schema->hasTable("foo")); + + $table = $schema->createTable("foo"); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\Table', $table); + $this->assertEquals("foo", $table->getName()); + $this->assertTrue($schema->hasTable("foo")); + } + + public function testAddSequences() + { + $sequence = new Sequence("a_seq", 1, 1); + + $schema = new Schema(array(), array($sequence)); + + $this->assertTrue($schema->hasSequence("a_seq")); + $this->assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $schema->getSequence("a_seq")); + + $sequences = $schema->getSequences(); + $this->assertArrayHasKey('public.a_seq', $sequences); + } + + public function testSequenceAccessCaseInsensitive() + { + $sequence = new Sequence("a_Seq"); + + $schema = new Schema(array(), array($sequence)); + $this->assertTrue($schema->hasSequence('a_seq')); + $this->assertTrue($schema->hasSequence('a_Seq')); + $this->assertTrue($schema->hasSequence('A_SEQ')); + + $this->assertEquals($sequence, $schema->getSequence('a_seq')); + $this->assertEquals($sequence, $schema->getSequence('a_Seq')); + $this->assertEquals($sequence, $schema->getSequence('A_SEQ')); + } + + public function testGetUnknownSequenceThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $schema = new Schema(); + $schema->getSequence("unknown"); + } + + public function testCreateSequence() + { + $schema = new Schema(); + $sequence = $schema->createSequence('a_seq', 10, 20); + + $this->assertEquals('a_seq', $sequence->getName()); + $this->assertEquals(10, $sequence->getAllocationSize()); + $this->assertEquals(20, $sequence->getInitialValue()); + + $this->assertTrue($schema->hasSequence("a_seq")); + $this->assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $schema->getSequence("a_seq")); + + $sequences = $schema->getSequences(); + $this->assertArrayHasKey('public.a_seq', $sequences); + } + + public function testDropSequence() + { + $sequence = new Sequence("a_seq", 1, 1); + + $schema = new Schema(array(), array($sequence)); + + $schema->dropSequence("a_seq"); + $this->assertFalse($schema->hasSequence("a_seq")); + } + + public function testAddSequenceTwiceThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $sequence = new Sequence("a_seq", 1, 1); + + $schema = new Schema(array(), array($sequence, $sequence)); + } + + public function testConfigMaxIdentifierLength() + { + $schemaConfig = new \Doctrine\DBAL\Schema\SchemaConfig(); + $schemaConfig->setMaxIdentifierLength(5); + + $schema = new Schema(array(), array(), $schemaConfig); + $table = $schema->createTable("smalltable"); + $table->addColumn('long_id', 'integer'); + $table->addIndex(array('long_id')); + + $index = current($table->getIndexes()); + $this->assertEquals(5, strlen($index->getName())); + } + + public function testDeepClone() + { + $schema = new Schema(); + $sequence = $schema->createSequence('baz'); + + $tableA = $schema->createTable('foo'); + $tableA->addColumn('id', 'integer'); + + $tableB = $schema->createTable('bar'); + $tableB->addColumn('id', 'integer'); + $tableB->addColumn('foo_id', 'integer'); + $tableB->addForeignKeyConstraint($tableA, array('foo_id'), array('id')); + + $schemaNew = clone $schema; + + $this->assertNotSame($sequence, $schemaNew->getSequence('baz')); + + $this->assertNotSame($tableA, $schemaNew->getTable('foo')); + $this->assertNotSame($tableA->getColumn('id'), $schemaNew->getTable('foo')->getColumn('id')); + + $this->assertNotSame($tableB, $schemaNew->getTable('bar')); + $this->assertNotSame($tableB->getColumn('id'), $schemaNew->getTable('bar')->getColumn('id')); + + $fk = $schemaNew->getTable('bar')->getForeignKeys(); + $fk = current($fk); + $this->assertSame($schemaNew->getTable('bar'), $this->readAttribute($fk, '_localTable')); + } + + /** + * @group DBAL-219 + */ + public function testHasTableForQuotedAsset() + { + $schema = new Schema(); + + $tableA = $schema->createTable('foo'); + $tableA->addColumn('id', 'integer'); + + $this->assertTrue($schema->hasTable('`foo`')); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SequenceTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SequenceTest.php new file mode 100644 index 0000000..3ee0937 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/SequenceTest.php @@ -0,0 +1,28 @@ +addColumn("id", "integer", array("autoincrement" => true)); + $table->setPrimaryKey(array("id")); + + $sequence = new Sequence("foo_id_seq"); + $sequence2 = new Sequence("bar_id_seq"); + $sequence3 = new Sequence("other.foo_id_seq"); + + $this->assertTrue($sequence->isAutoIncrementsFor($table)); + $this->assertFalse($sequence2->isAutoIncrementsFor($table)); + $this->assertFalse($sequence3->isAutoIncrementsFor($table)); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizerTest.php new file mode 100644 index 0000000..e2f52c4 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Synchronizer/SingleDatabaseSynchronizerTest.php @@ -0,0 +1,88 @@ +. + */ + +namespace Doctrine\Tests\DBAL\Schema\Synchronizer; + +use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Schema\Synchronizer\SingleDatabaseSynchronizer; + +class SingleDatabaseSynchronizerTest extends \PHPUnit_Framework_TestCase +{ + private $conn; + private $synchronizer; + + public function setUp() + { + $this->conn = DriverManager::getConnection(array( + 'driver' => 'pdo_sqlite', + 'memory' => true, + )); + $this->synchronizer = new SingleDatabaseSynchronizer($this->conn); + } + + public function testGetCreateSchema() + { + $schema = new Schema(); + $table = $schema->createTable('test'); + $table->addColumn('id', 'integer'); + $table->setPrimaryKey(array('id')); + + $sql = $this->synchronizer->getCreateSchema($schema); + $this->assertEquals(array('CREATE TABLE test (id INTEGER NOT NULL, PRIMARY KEY(id))'), $sql); + } + + public function testGetUpdateSchema() + { + $schema = new Schema(); + $table = $schema->createTable('test'); + $table->addColumn('id', 'integer'); + $table->setPrimaryKey(array('id')); + + $sql = $this->synchronizer->getUpdateSchema($schema); + $this->assertEquals(array('CREATE TABLE test (id INTEGER NOT NULL, PRIMARY KEY(id))'), $sql); + } + + public function testGetDropSchema() + { + $schema = new Schema(); + $table = $schema->createTable('test'); + $table->addColumn('id', 'integer'); + $table->setPrimaryKey(array('id')); + + $this->synchronizer->createSchema($schema); + + $sql = $this->synchronizer->getDropSchema($schema); + $this->assertEquals(array('DROP TABLE test'), $sql); + } + + public function testGetDropAllSchema() + { + $schema = new Schema(); + $table = $schema->createTable('test'); + $table->addColumn('id', 'integer'); + $table->setPrimaryKey(array('id')); + + $this->synchronizer->createSchema($schema); + + $sql = $this->synchronizer->getDropAllSchema(); + $this->assertEquals(array('DROP TABLE test'), $sql); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/TableTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/TableTest.php new file mode 100644 index 0000000..79f2205 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/TableTest.php @@ -0,0 +1,528 @@ +setExpectedException('Doctrine\DBAL\DBALException'); + $table = new \Doctrine\DBAL\Schema\Table(''); + } + + public function testGetName() + { + $table = new Table("foo", array(), array(), array()); + $this->assertEquals("foo", $table->getName()); + } + + public function testColumns() + { + $type = Type::getType('integer'); + $columns = array(); + $columns[] = new Column("foo", $type); + $columns[] = new Column("bar", $type); + $table = new Table("foo", $columns, array(), array()); + + $this->assertTrue($table->hasColumn("foo")); + $this->assertTrue($table->hasColumn("bar")); + $this->assertFalse($table->hasColumn("baz")); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\Column', $table->getColumn("foo")); + $this->assertInstanceOf('Doctrine\DBAL\Schema\Column', $table->getColumn("bar")); + + $this->assertEquals(2, count($table->getColumns())); + } + + public function testColumnsCaseInsensitive() + { + $table = new Table("foo"); + $column = $table->addColumn('Foo', 'integer'); + + $this->assertTrue($table->hasColumn('Foo')); + $this->assertTrue($table->hasColumn('foo')); + $this->assertTrue($table->hasColumn('FOO')); + + $this->assertSame($column, $table->getColumn('Foo')); + $this->assertSame($column, $table->getColumn('foo')); + $this->assertSame($column, $table->getColumn('FOO')); + } + + public function testCreateColumn() + { + $type = Type::getType('integer'); + + $table = new Table("foo"); + + $this->assertFalse($table->hasColumn("bar")); + $table->addColumn("bar", 'integer'); + $this->assertTrue($table->hasColumn("bar")); + $this->assertSame($type, $table->getColumn("bar")->getType()); + } + + public function testDropColumn() + { + $type = Type::getType('integer'); + $columns = array(); + $columns[] = new Column("foo", $type); + $columns[] = new Column("bar", $type); + $table = new Table("foo", $columns, array(), array()); + + $this->assertTrue($table->hasColumn("foo")); + $this->assertTrue($table->hasColumn("bar")); + + $table->dropColumn("foo")->dropColumn("bar"); + + $this->assertFalse($table->hasColumn("foo")); + $this->assertFalse($table->hasColumn("bar")); + } + + public function testGetUnknownColumnThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $table = new Table("foo", array(), array(), array()); + $table->getColumn('unknown'); + } + + public function testAddColumnTwiceThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $type = \Doctrine\DBAL\Types\Type::getType('integer'); + $columns = array(); + $columns[] = new Column("foo", $type); + $columns[] = new Column("foo", $type); + $table = new Table("foo", $columns, array(), array()); + } + + public function testCreateIndex() + { + $type = \Doctrine\DBAL\Types\Type::getType('integer'); + $columns = array(new Column("foo", $type), new Column("bar", $type), new Column("baz", $type)); + $table = new Table("foo", $columns); + + $table->addIndex(array("foo", "bar"), "foo_foo_bar_idx"); + $table->addUniqueIndex(array("bar", "baz"), "foo_bar_baz_uniq"); + + $this->assertTrue($table->hasIndex("foo_foo_bar_idx")); + $this->assertTrue($table->hasIndex("foo_bar_baz_uniq")); + } + + public function testIndexCaseInsensitive() + { + $type = \Doctrine\DBAL\Types\Type::getType('integer'); + $columns = array( + new Column("foo", $type), + new Column("bar", $type), + new Column("baz", $type) + ); + $table = new Table("foo", $columns); + + $table->addIndex(array("foo", "bar", "baz"), "Foo_Idx"); + + $this->assertTrue($table->hasIndex('foo_idx')); + $this->assertTrue($table->hasIndex('Foo_Idx')); + $this->assertTrue($table->hasIndex('FOO_IDX')); + } + + public function testAddIndexes() + { + $type = \Doctrine\DBAL\Types\Type::getType('integer'); + $columns = array( + new Column("foo", $type), + new Column("bar", $type), + ); + $indexes = array( + new Index("the_primary", array("foo"), true, true), + new Index("bar_idx", array("bar"), false, false), + ); + $table = new Table("foo", $columns, $indexes, array()); + + $this->assertTrue($table->hasIndex("the_primary")); + $this->assertTrue($table->hasIndex("bar_idx")); + $this->assertFalse($table->hasIndex("some_idx")); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\Index', $table->getPrimaryKey()); + $this->assertInstanceOf('Doctrine\DBAL\Schema\Index', $table->getIndex('the_primary')); + $this->assertInstanceOf('Doctrine\DBAL\Schema\Index', $table->getIndex('bar_idx')); + } + + public function testGetUnknownIndexThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $table = new Table("foo", array(), array(), array()); + $table->getIndex("unknownIndex"); + } + + public function testAddTwoPrimaryThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $type = \Doctrine\DBAL\Types\Type::getType('integer'); + $columns = array(new Column("foo", $type), new Column("bar", $type)); + $indexes = array( + new Index("the_primary", array("foo"), true, true), + new Index("other_primary", array("bar"), true, true), + ); + $table = new Table("foo", $columns, $indexes, array()); + } + + public function testAddTwoIndexesWithSameNameThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $type = \Doctrine\DBAL\Types\Type::getType('integer'); + $columns = array(new Column("foo", $type), new Column("bar", $type)); + $indexes = array( + new Index("an_idx", array("foo"), false, false), + new Index("an_idx", array("bar"), false, false), + ); + $table = new Table("foo", $columns, $indexes, array()); + } + + public function testConstraints() + { + $constraint = new ForeignKeyConstraint(array(), "foo", array()); + + $tableA = new Table("foo", array(), array(), array($constraint)); + $constraints = $tableA->getForeignKeys(); + + $this->assertEquals(1, count($constraints)); + $this->assertSame($constraint, array_shift($constraints)); + } + + public function testOptions() + { + $table = new Table("foo", array(), array(), array(), false, array("foo" => "bar")); + + $this->assertTrue($table->hasOption("foo")); + $this->assertEquals("bar", $table->getOption("foo")); + } + + public function testBuilderSetPrimaryKey() + { + $table = new Table("foo"); + + $table->addColumn("bar", 'integer'); + $table->setPrimaryKey(array("bar")); + + $this->assertTrue($table->hasIndex("primary")); + $this->assertInstanceOf('Doctrine\DBAL\Schema\Index', $table->getPrimaryKey()); + $this->assertTrue($table->getIndex("primary")->isUnique()); + $this->assertTrue($table->getIndex("primary")->isPrimary()); + } + + public function testBuilderAddUniqueIndex() + { + $table = new Table("foo"); + + $table->addColumn("bar", 'integer'); + $table->addUniqueIndex(array("bar"), "my_idx"); + + $this->assertTrue($table->hasIndex("my_idx")); + $this->assertTrue($table->getIndex("my_idx")->isUnique()); + $this->assertFalse($table->getIndex("my_idx")->isPrimary()); + } + + public function testBuilderAddIndex() + { + $table = new Table("foo"); + + $table->addColumn("bar", 'integer'); + $table->addIndex(array("bar"), "my_idx"); + + $this->assertTrue($table->hasIndex("my_idx")); + $this->assertFalse($table->getIndex("my_idx")->isUnique()); + $this->assertFalse($table->getIndex("my_idx")->isPrimary()); + } + + public function testBuilderAddIndexWithInvalidNameThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $table = new Table("foo"); + $table->addColumn("bar",'integer'); + $table->addIndex(array("bar"), "invalid name %&/"); + } + + public function testBuilderAddIndexWithUnknownColumnThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $table = new Table("foo"); + $table->addIndex(array("bar"), "invalidName"); + } + + public function testBuilderOptions() + { + $table = new Table("foo"); + $table->addOption("foo", "bar"); + $this->assertTrue($table->hasOption("foo")); + $this->assertEquals("bar", $table->getOption("foo")); + } + + public function testAddForeignKeyConstraint_UnknownLocalColumn_ThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $table = new Table("foo"); + $table->addColumn("id", 'integer'); + + $foreignTable = new Table("bar"); + $foreignTable->addColumn("id", 'integer'); + + $table->addForeignKeyConstraint($foreignTable, array("foo"), array("id")); + } + + public function testAddForeignKeyConstraint_UnknownForeignColumn_ThrowsException() + { + $this->setExpectedException("Doctrine\DBAL\Schema\SchemaException"); + + $table = new Table("foo"); + $table->addColumn("id", 'integer'); + + $foreignTable = new Table("bar"); + $foreignTable->addColumn("id", 'integer'); + + $table->addForeignKeyConstraint($foreignTable, array("id"), array("foo")); + } + + public function testAddForeignKeyConstraint() + { + $table = new Table("foo"); + $table->addColumn("id", 'integer'); + + $foreignTable = new Table("bar"); + $foreignTable->addColumn("id", 'integer'); + + $table->addForeignKeyConstraint($foreignTable, array("id"), array("id"), array("foo" => "bar")); + + $constraints = $table->getForeignKeys(); + $this->assertEquals(1, count($constraints)); + $constraint = current($constraints); + + $this->assertInstanceOf('Doctrine\DBAL\Schema\ForeignKeyConstraint', $constraint); + + $this->assertTrue($constraint->hasOption("foo")); + $this->assertEquals("bar", $constraint->getOption("foo")); + } + + public function testAddIndexWithCaseSensitiveColumnProblem() + { + $table = new Table("foo"); + $table->addColumn("id", 'integer'); + + $table->addIndex(array("ID"), "my_idx"); + + $this->assertTrue($table->hasIndex('my_idx')); + $this->assertEquals(array("ID"), $table->getIndex("my_idx")->getColumns()); + $this->assertTrue($table->getIndex('my_idx')->spansColumns(array('id'))); + } + + public function testAddPrimaryKey_ColumnsAreExplicitlySetToNotNull() + { + $table = new Table("foo"); + $column = $table->addColumn("id", 'integer', array('notnull' => false)); + + $this->assertFalse($column->getNotnull()); + + $table->setPrimaryKey(array('id')); + + $this->assertTrue($column->getNotnull()); + } + + /** + * @group DDC-133 + */ + public function testAllowImplicitSchemaTableInAutogeneratedIndexNames() + { + $table = new Table("foo.bar"); + $table->addColumn('baz', 'integer', array()); + $table->addIndex(array('baz')); + + $this->assertEquals(1, count($table->getIndexes())); + } + + /** + * @group DBAL-50 + */ + public function testAddIndexTwice_IgnoreSecond() + { + $table = new Table("foo.bar"); + $table->addColumn('baz', 'integer', array()); + $table->addIndex(array('baz')); + $table->addIndex(array('baz')); + + $this->assertEquals(1, count($table->getIndexes())); + } + + /** + * @group DBAL-50 + */ + public function testAddForeignKeyIndexImplicitly() + { + $table = new Table("foo"); + $table->addColumn("id", 'integer'); + + $foreignTable = new Table("bar"); + $foreignTable->addColumn("id", 'integer'); + + $table->addForeignKeyConstraint($foreignTable, array("id"), array("id"), array("foo" => "bar")); + + $indexes = $table->getIndexes(); + $this->assertEquals(1, count($indexes)); + $index = current($indexes); + + $this->assertTrue($table->hasIndex($index->getName())); + $this->assertEquals(array('id'), $index->getColumns()); + } + + /** + * @group DBAL-50 + */ + public function testOverruleIndex() + { + $table = new Table("bar"); + $table->addColumn('baz', 'integer', array()); + $table->addIndex(array('baz')); + + $indexes = $table->getIndexes(); + $this->assertEquals(1, count($indexes)); + $index = current($indexes); + + $table->addUniqueIndex(array('baz')); + $this->assertEquals(1, count($table->getIndexes())); + $this->assertFalse($table->hasIndex($index->getName())); + } + + public function testPrimaryKeyOverrulesUniqueIndex() + { + $table = new Table("bar"); + $table->addColumn('baz', 'integer', array()); + $table->addUniqueIndex(array('baz')); + + $table->setPrimaryKey(array('baz')); + + $indexes = $table->getIndexes(); + $this->assertEquals(1, count($indexes), "Table should only contain the primary key table index, not the unique one anymore, because it was overruled."); + + $index = current($indexes); + $this->assertTrue($index->isPrimary()); + } + + /** + * @group DBAL-64 + */ + public function testQuotedTableName() + { + $table = new Table("`bar`"); + + $mysqlPlatform = new \Doctrine\DBAL\Platforms\MySqlPlatform(); + $sqlitePlatform = new \Doctrine\DBAL\Platforms\SqlitePlatform(); + + $this->assertEquals('bar', $table->getName()); + $this->assertEquals('`bar`', $table->getQuotedName($mysqlPlatform)); + $this->assertEquals('"bar"', $table->getQuotedName($sqlitePlatform)); + } + + /** + * @group DBAL-79 + */ + public function testTableHasPrimaryKey() + { + $table = new Table("test"); + + $this->assertFalse($table->hasPrimaryKey()); + + $table->addColumn("foo", "integer"); + $table->setPrimaryKey(array("foo")); + + $this->assertTrue($table->hasPrimaryKey()); + } + + /** + * @group DBAL-91 + */ + public function testAddIndexWithQuotedColumns() + { + $table = new Table("test"); + $table->addColumn('"foo"', 'integer'); + $table->addColumn('bar', 'integer'); + $table->addIndex(array('"foo"', '"bar"')); + } + + /** + * @group DBAL-91 + */ + public function testAddForeignKeyWithQuotedColumnsAndTable() + { + $table = new Table("test"); + $table->addColumn('"foo"', 'integer'); + $table->addColumn('bar', 'integer'); + $table->addForeignKeyConstraint('"boing"', array('"foo"', '"bar"'), array("id")); + } + + /** + * @group DBAL-177 + */ + public function testQuoteSchemaPrefixed() + { + $table = new Table("`test`.`test`"); + $this->assertEquals("test.test", $table->getName()); + $this->assertEquals("`test`.`test`", $table->getQuotedName(new \Doctrine\DBAL\Platforms\MySqlPlatform)); + } + + /** + * @group DBAL-204 + */ + public function testFullQualifiedTableName() + { + $table = new Table("`test`.`test`"); + $this->assertEquals('test.test', $table->getFullQualifiedName("test")); + $this->assertEquals('test.test', $table->getFullQualifiedName("other")); + + $table = new Table("test"); + $this->assertEquals('test.test', $table->getFullQualifiedName("test")); + $this->assertEquals('other.test', $table->getFullQualifiedName("other")); + } + + /** + * @group DBAL-224 + */ + public function testDropIndex() + { + $table = new Table("test"); + $table->addColumn('id', 'integer'); + $table->addIndex(array('id'), 'idx'); + + $this->assertTrue($table->hasIndex('idx')); + + $table->dropIndex('idx'); + $this->assertFalse($table->hasIndex('idx')); + } + + /** + * @group DBAL-224 + */ + public function testDropPrimaryKey() + { + $table = new Table("test"); + $table->addColumn('id', 'integer'); + $table->setPrimaryKey(array('id')); + + $this->assertTrue($table->hasPrimaryKey()); + + $table->dropPrimaryKey(); + $this->assertFalse($table->hasPrimaryKey()); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Visitor/RemoveNamespacedAssetsTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Visitor/RemoveNamespacedAssetsTest.php new file mode 100644 index 0000000..e5b660f --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Visitor/RemoveNamespacedAssetsTest.php @@ -0,0 +1,77 @@ +setName("test"); + $schema = new Schema(array(), array(), $config); + + $schema->createTable("test.test"); + $schema->createTable("foo.bar"); + $schema->createTable("baz"); + + $schema->visit(new RemoveNamespacedAssets()); + + $tables = $schema->getTables(); + $this->assertEquals(array("test.test", "test.baz"), array_keys($tables), "Only 2 tables should be present, both in 'test' namespace."); + } + + /** + * @group DBAL-204 + */ + public function testCleanupForeignKeys() + { + $config = new SchemaConfig; + $config->setName("test"); + $schema = new Schema(array(), array(), $config); + + $fooTable = $schema->createTable("foo.bar"); + $fooTable->addColumn('id', 'integer'); + + $testTable = $schema->createTable("test.test"); + $testTable->addColumn('id', 'integer'); + + $testTable->addForeignKeyConstraint("foo.bar", array("id"), array("id")); + + $schema->visit(new RemoveNamespacedAssets()); + + $sql = $schema->toSql(new MySqlPlatform()); + $this->assertEquals(1, count($sql), "Just one CREATE TABLE statement, no foreign key and table to foo.bar"); + } + + /** + * @group DBAL-204 + */ + public function testCleanupForeignKeysDifferentOrder() + { + $config = new SchemaConfig; + $config->setName("test"); + $schema = new Schema(array(), array(), $config); + + $testTable = $schema->createTable("test.test"); + $testTable->addColumn('id', 'integer'); + + $fooTable = $schema->createTable("foo.bar"); + $fooTable->addColumn('id', 'integer'); + + $testTable->addForeignKeyConstraint("foo.bar", array("id"), array("id")); + + $schema->visit(new RemoveNamespacedAssets()); + + $sql = $schema->toSql(new MySqlPlatform()); + $this->assertEquals(1, count($sql), "Just one CREATE TABLE statement, no foreign key and table to foo.bar"); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Visitor/SchemaSqlCollectorTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Visitor/SchemaSqlCollectorTest.php new file mode 100644 index 0000000..8dfd2b2 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Schema/Visitor/SchemaSqlCollectorTest.php @@ -0,0 +1,80 @@ +getMock( + 'Doctrine\DBAL\Platforms\MySqlPlatform', + array('getCreateTableSql', 'getCreateSequenceSql', 'getCreateForeignKeySql') + ); + $platformMock->expects($this->exactly(2)) + ->method('getCreateTableSql') + ->will($this->returnValue(array("foo"))); + $platformMock->expects($this->exactly(1)) + ->method('getCreateSequenceSql') + ->will($this->returnValue(array("bar"))); + $platformMock->expects($this->exactly(1)) + ->method('getCreateForeignKeySql') + ->will($this->returnValue(array("baz"))); + + $schema = $this->createFixtureSchema(); + + $sql = $schema->toSql($platformMock); + + $this->assertEquals(array("foo", "foo", "bar", "baz"), $sql); + } + + public function testDropSchema() + { + $platformMock = $this->getMock( + 'Doctrine\DBAL\Platforms\MySqlPlatform', + array('getDropTableSql', 'getDropSequenceSql', 'getDropForeignKeySql') + ); + $platformMock->expects($this->exactly(2)) + ->method('getDropTableSql') + ->will($this->returnValue("tbl")); + $platformMock->expects($this->exactly(1)) + ->method('getDropSequenceSql') + ->will($this->returnValue("seq")); + $platformMock->expects($this->exactly(1)) + ->method('getDropForeignKeySql') + ->will($this->returnValue("fk")); + + $schema = $this->createFixtureSchema(); + + $sql = $schema->toDropSql($platformMock); + + $this->assertEquals(array("fk", "seq", "tbl", "tbl"), $sql); + } + + /** + * @return Schema + */ + public function createFixtureSchema() + { + $schema = new Schema(); + $tableA = $schema->createTable("foo"); + $tableA->addColumn("id", 'integer'); + $tableA->addColumn("bar", 'string', array('length' => 255)); + $tableA->setPrimaryKey(array("id")); + + $schema->createSequence("foo_seq"); + + $tableB = $schema->createTable("bar"); + $tableB->addColumn("id", 'integer'); + $tableB->setPrimaryKey(array("id")); + + $tableA->addForeignKeyConstraint($tableB, array("bar"), array("id")); + + return $schema; + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php new file mode 100644 index 0000000..59259fd --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php @@ -0,0 +1,182 @@ +. + */ + +namespace Doctrine\Tests\DBAL\Sharding; + +use Doctrine\DBAL\DriverManager; + +class PoolingShardConnectionTest extends \PHPUnit_Framework_TestCase +{ + public function testConnect() + { + $conn = DriverManager::getConnection(array( + 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + 'driver' => 'pdo_sqlite', + 'global' => array('memory' => true), + 'shards' => array( + array('id' => 1, 'memory' => true), + array('id' => 2, 'memory' => true), + ), + 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', + )); + + $this->assertFalse($conn->isConnected(0)); + $conn->connect(0); + $this->assertEquals(1, $conn->fetchColumn('SELECT 1')); + $this->assertTrue($conn->isConnected(0)); + + $this->assertFalse($conn->isConnected(1)); + $conn->connect(1); + $this->assertEquals(1, $conn->fetchColumn('SELECT 1')); + $this->assertTrue($conn->isConnected(1)); + + $this->assertFalse($conn->isConnected(2)); + $conn->connect(2); + $this->assertEquals(1, $conn->fetchColumn('SELECT 1')); + $this->assertTrue($conn->isConnected(2)); + + $conn->close(); + $this->assertFalse($conn->isConnected(0)); + $this->assertFalse($conn->isConnected(1)); + $this->assertFalse($conn->isConnected(2)); + } + + public function testNoGlobalServerException() + { + $this->setExpectedException('InvalidArgumentException', "Connection Parameters require 'global' and 'shards' configurations."); + + $conn = DriverManager::getConnection(array( + 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + 'driver' => 'pdo_sqlite', + 'shards' => array( + array('id' => 1, 'memory' => true), + array('id' => 2, 'memory' => true), + ), + 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', + )); + } + + public function testNoShardsServersExecption() + { + $this->setExpectedException('InvalidArgumentException', "Connection Parameters require 'global' and 'shards' configurations."); + + $conn = DriverManager::getConnection(array( + 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + 'driver' => 'pdo_sqlite', + 'global' => array('memory' => true), + 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', + )); + } + + public function testNoShardsChoserExecption() + { + $this->setExpectedException('InvalidArgumentException', "Missing Shard Choser configuration 'shardChoser'"); + + $conn = DriverManager::getConnection(array( + 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + 'driver' => 'pdo_sqlite', + 'global' => array('memory' => true), + 'shards' => array( + array('id' => 1, 'memory' => true), + array('id' => 2, 'memory' => true), + ), + )); + } + + public function testShardChoserWrongInstance() + { + $this->setExpectedException('InvalidArgumentException', "The 'shardChoser' configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser"); + + $conn = DriverManager::getConnection(array( + 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + 'driver' => 'pdo_sqlite', + 'global' => array('memory' => true), + 'shards' => array( + array('id' => 1, 'memory' => true), + array('id' => 2, 'memory' => true), + ), + 'shardChoser' => new \stdClass, + )); + } + + public function testShardNonNumericId() + { + $this->setExpectedException('InvalidArgumentException', "Shard Id has to be a non-negative number."); + + $conn = DriverManager::getConnection(array( + 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + 'driver' => 'pdo_sqlite', + 'global' => array('memory' => true), + 'shards' => array( + array('id' => 'foo', 'memory' => true), + ), + 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', + )); + } + + public function testShardMissingId() + { + $this->setExpectedException('InvalidArgumentException', "Missing 'id' for one configured shard. Please specificy a unique shard-id."); + + $conn = DriverManager::getConnection(array( + 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + 'driver' => 'pdo_sqlite', + 'global' => array('memory' => true), + 'shards' => array( + array('memory' => true), + ), + 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', + )); + } + + public function testDuplicateShardId() + { + $this->setExpectedException('InvalidArgumentException', "Shard 1 is duplicated in the configuration."); + + $conn = DriverManager::getConnection(array( + 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + 'driver' => 'pdo_sqlite', + 'global' => array('memory' => true), + 'shards' => array( + array('id' => 1, 'memory' => true), + array('id' => 1, 'memory' => true), + ), + 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', + )); + } + + public function testSwitchShardWithOpenTransactionException() + { + $conn = DriverManager::getConnection(array( + 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', + 'driver' => 'pdo_sqlite', + 'global' => array('memory' => true), + 'shards' => array( + array('id' => 1, 'memory' => true), + ), + 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', + )); + + $conn->beginTransaction(); + + $this->setExpectedException('Doctrine\DBAL\Sharding\ShardingException', 'Cannot switch shard when transaction is active.'); + $conn->connect(1); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php new file mode 100644 index 0000000..002f9f0 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php @@ -0,0 +1,108 @@ +. + */ +namespace Doctrine\Tests\DBAL\Sharding; + +use Doctrine\DBAL\Sharding\PoolingShardManager; + +class PoolingShardManagerTest extends \PHPUnit_Framework_TestCase +{ + private function createConnectionMock() + { + return $this->getMock('Doctrine\DBAL\Sharding\PoolingShardConnection', array('connect', 'getParams', 'fetchAll'), array(), '', false); + } + + private function createPassthroughShardChoser() + { + $mock = $this->getMock('Doctrine\DBAL\Sharding\ShardChoser\ShardChoser'); + $mock->expects($this->any()) + ->method('pickShard') + ->will($this->returnCallback(function($value) { return $value; })); + return $mock; + } + + public function testSelectGlobal() + { + $conn = $this->createConnectionMock(); + $conn->expects($this->once())->method('connect')->with($this->equalTo(0)); + + $shardManager = new PoolingShardManager($conn, $this->createPassthroughShardChoser()); + $shardManager->selectGlobal(); + + $this->assertNull($shardManager->getCurrentDistributionValue()); + } + + public function testSelectShard() + { + $shardId = 10; + $conn = $this->createConnectionMock(); + $conn->expects($this->at(0))->method('getParams')->will($this->returnValue(array('shardChoser' => $this->createPassthroughShardChoser()))); + $conn->expects($this->at(1))->method('connect')->with($this->equalTo($shardId)); + + $shardManager = new PoolingShardManager($conn); + $shardManager->selectShard($shardId); + + $this->assertEquals($shardId, $shardManager->getCurrentDistributionValue()); + } + + public function testGetShards() + { + $conn = $this->createConnectionMock(); + $conn->expects($this->any())->method('getParams')->will( + $this->returnValue( + array('shards' => array( array('id' => 1), array('id' => 2) ), 'shardChoser' => $this->createPassthroughShardChoser()) + ) + ); + + $shardManager = new PoolingShardManager($conn, $this->createPassthroughShardChoser()); + $shards = $shardManager->getShards(); + + $this->assertEquals(array(array('id' => 1), array('id' => 2)), $shards); + } + + public function testQueryAll() + { + $sql = "SELECT * FROM table"; + $params = array(1); + $types = array(1); + + $conn = $this->createConnectionMock(); + $conn->expects($this->at(0))->method('getParams')->will($this->returnValue( + array('shards' => array( array('id' => 1), array('id' => 2) ), 'shardChoser' => $this->createPassthroughShardChoser()) + )); + $conn->expects($this->at(1))->method('getParams')->will($this->returnValue( + array('shards' => array( array('id' => 1), array('id' => 2) ), 'shardChoser' => $this->createPassthroughShardChoser()) + )); + $conn->expects($this->at(2))->method('connect')->with($this->equalTo(1)); + $conn->expects($this->at(3)) + ->method('fetchAll') + ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) + ->will($this->returnValue(array( array('id' => 1) ) )); + $conn->expects($this->at(4))->method('connect')->with($this->equalTo(2)); + $conn->expects($this->at(5)) + ->method('fetchAll') + ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) + ->will($this->returnValue(array( array('id' => 2) ) )); + + $shardManager = new PoolingShardManager($conn, $this->createPassthroughShardChoser()); + $result = $shardManager->queryAll($sql, $params, $types); + + $this->assertEquals(array(array('id' => 1), array('id' => 2)), $result); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php new file mode 100644 index 0000000..ccf185c --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php @@ -0,0 +1,82 @@ +markTestSkipped('No driver or sqlserver driver specified.'); + } + + $params = array( + 'driver' => $GLOBALS['db_type'], + 'dbname' => $GLOBALS['db_name'], + 'user' => $GLOBALS['db_username'], + 'password' => $GLOBALS['db_password'], + 'host' => $GLOBALS['db_host'], + 'sharding' => array( + 'federationName' => 'Orders_Federation', + 'distributionKey' => 'CustID', + 'distributionType' => 'integer', + 'filteringEnabled' => false, + ), + 'driverOptions' => array('MultipleActiveResultSets' => false) + ); + $this->conn = DriverManager::getConnection($params); + // assume database is created and schema is: + // Global products table + // Customers, Orders, OrderItems federation tables. + // See http://cloud.dzone.com/articles/using-sql-azure-federations + $this->sm = new SQLAzureShardManager($this->conn); + } + + public function createShopSchema() + { + $schema = new Schema(); + + $products = $schema->createTable('Products'); + $products->addColumn('ProductID', 'integer'); + $products->addColumn('SupplierID', 'integer'); + $products->addColumn('ProductName', 'string'); + $products->addColumn('Price', 'decimal', array('scale' => 2, 'precision' => 12)); + $products->setPrimaryKey(array('ProductID')); + $products->addOption('azure.federated', true); + + $customers = $schema->createTable('Customers'); + $customers->addColumn('CustomerID', 'integer'); + $customers->addColumn('CompanyName', 'string'); + $customers->addColumn('FirstName', 'string'); + $customers->addColumn('LastName', 'string'); + $customers->setPrimaryKey(array('CustomerID')); + $customers->addOption('azure.federated', true); + $customers->addOption('azure.federatedOnColumnName', 'CustomerID'); + + $orders = $schema->createTable('Orders'); + $orders->addColumn('CustomerID', 'integer'); + $orders->addColumn('OrderID', 'integer'); + $orders->addColumn('OrderDate', 'datetime'); + $orders->setPrimaryKey(array('CustomerID', 'OrderID')); + $orders->addOption('azure.federated', true); + $orders->addOption('azure.federatedOnColumnName', 'CustomerID'); + + $orderItems = $schema->createTable('OrderItems'); + $orderItems->addColumn('CustomerID', 'integer'); + $orderItems->addColumn('OrderID', 'integer'); + $orderItems->addColumn('ProductID', 'integer'); + $orderItems->addColumn('Quantity', 'integer'); + $orderItems->setPrimaryKey(array('CustomerID', 'OrderID', 'ProductID')); + $orderItems->addOption('azure.federated', true); + $orderItems->addOption('azure.federatedOnColumnName', 'CustomerID'); + + return $schema; + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/FunctionalTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/FunctionalTest.php new file mode 100644 index 0000000..1051efb --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/FunctionalTest.php @@ -0,0 +1,44 @@ +createShopSchema(); + + $synchronizer = new SQLAzureSchemaSynchronizer($this->conn, $this->sm); + $synchronizer->dropAllSchema(); + $synchronizer->createSchema($schema); + + $this->sm->selectShard(0); + + $this->conn->insert("Products", array( + "ProductID" => 1, + "SupplierID" => 2, + "ProductName" => "Test", + "Price" => 10.45 + )); + + $this->conn->insert("Customers", array( + "CustomerID" => 1, + "CompanyName" => "Foo", + "FirstName" => "Benjamin", + "LastName" => "E.", + )); + + $query = "SELECT * FROM Products"; + $data = $this->conn->fetchAll($query); + $this->assertTrue(count($data) > 0); + + $query = "SELECT * FROM Customers"; + $data = $this->conn->fetchAll($query); + $this->assertTrue(count($data) > 0); + + $data = $this->sm->queryAll("SELECT * FROM Customers"); + $this->assertTrue(count($data) > 0); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/MultiTenantVisitorTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/MultiTenantVisitorTest.php new file mode 100644 index 0000000..7eb038f --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/MultiTenantVisitorTest.php @@ -0,0 +1,65 @@ +. + */ + +namespace Doctrine\Tests\DBAL\Sharding\SQLAzure; + +use Doctrine\DBAL\Platforms\SQLAzurePlatform; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Sharding\SQLAzure\Schema\MultiTenantVisitor; + +class MultiTenantVisitorTest extends \PHPUnit_Framework_TestCase +{ + public function testMultiTenantPrimaryKey() + { + $platform = new SQLAzurePlatform(); + $visitor = new MultiTenantVisitor(); + + $schema = new Schema(); + $foo = $schema->createTable('foo'); + $foo->addColumn('id', 'string'); + $foo->setPrimaryKey(array('id')); + $schema->visit($visitor); + + $this->assertEquals(array('id', 'tenant_id'), $foo->getPrimaryKey()->getColumns()); + $this->assertTrue($foo->hasColumn('tenant_id')); + } + + public function testMultiTenantNonPrimaryKey() + { + $platform = new SQLAzurePlatform(); + $visitor = new MultiTenantVisitor(); + + $schema = new Schema(); + $foo = $schema->createTable('foo'); + $foo->addColumn('id', 'string'); + $foo->addColumn('created', 'datetime'); + $foo->setPrimaryKey(array('id')); + $foo->addIndex(array('created'), 'idx'); + + $foo->getPrimaryKey()->addFlag('nonclustered'); + $foo->getIndex('idx')->addFlag('clustered'); + + $schema->visit($visitor); + + $this->assertEquals(array('id'), $foo->getPrimaryKey()->getColumns()); + $this->assertTrue($foo->hasColumn('tenant_id')); + $this->assertEquals(array('created', 'tenant_id'), $foo->getIndex('idx')->getColumns()); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizerTest.php new file mode 100644 index 0000000..091a363 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizerTest.php @@ -0,0 +1,50 @@ +createShopSchema(); + + $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); + $sql = $synchronizer->getCreateSchema($schema); + + $this->assertEquals(array ( + "--Create Federation\nCREATE FEDERATION Orders_Federation (CustID INT RANGE)", + "USE FEDERATION Orders_Federation (CustID = 0) WITH RESET, FILTERING = OFF;", + "CREATE TABLE Products (ProductID INT NOT NULL, SupplierID INT NOT NULL, ProductName NVARCHAR(255) NOT NULL, Price NUMERIC(12, 2) NOT NULL, PRIMARY KEY (ProductID))", + "CREATE TABLE Customers (CustomerID INT NOT NULL, CompanyName NVARCHAR(255) NOT NULL, FirstName NVARCHAR(255) NOT NULL, LastName NVARCHAR(255) NOT NULL, PRIMARY KEY (CustomerID))", + "CREATE TABLE Orders (CustomerID INT NOT NULL, OrderID INT NOT NULL, OrderDate DATETIME2(6) NOT NULL, PRIMARY KEY (CustomerID, OrderID))", + "CREATE TABLE OrderItems (CustomerID INT NOT NULL, OrderID INT NOT NULL, ProductID INT NOT NULL, Quantity INT NOT NULL, PRIMARY KEY (CustomerID, OrderID, ProductID))", + ), $sql); + } + + public function testUpdateSchema() + { + $schema = $this->createShopSchema(); + + $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); + $synchronizer->dropAllSchema(); + + $sql = $synchronizer->getUpdateSchema($schema); + + $this->assertEquals(array(), $sql); + } + + public function testDropSchema() + { + $schema = $this->createShopSchema(); + + $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); + $synchronizer->dropAllSchema(); + $synchronizer->createSchema($schema); + $sql = $synchronizer->getDropSchema($schema); + + $this->assertEQuals(5, count($sql)); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureShardManagerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureShardManagerTest.php new file mode 100644 index 0000000..f73e494 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureShardManagerTest.php @@ -0,0 +1,93 @@ +setExpectedException('Doctrine\DBAL\Sharding\ShardingException', 'SQLAzure requires a federation name to be set during sharding configuration.'); + + $conn = $this->createConnection(array('sharding' => array('distributionKey' => 'abc', 'distributionType' => 'integer'))); + $sm = new SQLAzureShardManager($conn); + } + + public function testNoDistributionKey() + { + $this->setExpectedException('Doctrine\DBAL\Sharding\ShardingException', 'SQLAzure requires a distribution key to be set during sharding configuration.'); + + $conn = $this->createConnection(array('sharding' => array('federationName' => 'abc', 'distributionType' => 'integer'))); + $sm = new SQLAzureShardManager($conn); + } + + public function testNoDistributionType() + { + $this->setExpectedException('Doctrine\DBAL\Sharding\ShardingException'); + + $conn = $this->createConnection(array('sharding' => array('federationName' => 'abc', 'distributionKey' => 'foo'))); + $sm = new SQLAzureShardManager($conn); + } + + public function testGetDefaultDistributionValue() + { + $conn = $this->createConnection(array('sharding' => array('federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer'))); + + $sm = new SQLAzureShardManager($conn); + $this->assertNull($sm->getCurrentDistributionValue()); + } + + public function testSelectGlobalTransactionActive() + { + $conn = $this->createConnection(array('sharding' => array('federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer'))); + $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(true)); + + $this->setExpectedException('Doctrine\DBAL\Sharding\ShardingException', 'Cannot switch shard during an active transaction.'); + + $sm = new SQLAzureShardManager($conn); + $sm->selectGlobal(); + } + + public function testSelectGlobal() + { + $conn = $this->createConnection(array('sharding' => array('federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer'))); + $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(false)); + $conn->expects($this->at(2))->method('exec')->with($this->equalTo('USE FEDERATION ROOT WITH RESET')); + + $sm = new SQLAzureShardManager($conn); + $sm->selectGlobal(); + } + + public function testSelectShard() + { + $conn = $this->createConnection(array('sharding' => array('federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer'))); + $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(true)); + + $this->setExpectedException('Doctrine\DBAL\Sharding\ShardingException', 'Cannot switch shard during an active transaction.'); + + $sm = new SQLAzureShardManager($conn); + $sm->selectShard(1234); + + $this->assertEquals(1234, $sm->getCurrentDistributionValue()); + } + + public function testSelectShardNoDistriubtionValue() + { + $conn = $this->createConnection(array('sharding' => array('federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer'))); + $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(false)); + + $this->setExpectedException('Doctrine\DBAL\Sharding\ShardingException', 'You have to specify a string or integer as shard distribution value.'); + + $sm = new SQLAzureShardManager($conn); + $sm->selectShard(null); + } + + private function createConnection(array $params) + { + $conn = $this->getMock('Doctrine\DBAL\Connection', array('getParams', 'exec', 'isTransactionActive'), array(), '', false); + $conn->expects($this->at(0))->method('getParams')->will($this->returnValue($params)); + return $conn; + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/ShardChoser/MultiTenantShardChoserTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/ShardChoser/MultiTenantShardChoserTest.php new file mode 100644 index 0000000..4e06f8d --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Sharding/ShardChoser/MultiTenantShardChoserTest.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\Tests\DBAL\Sharding\ShardChoser; + +use Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser; + +class MultiTenantShardChoserTest extends \PHPUnit_Framework_TestCase +{ + public function testPickShard() + { + $choser = new MultiTenantShardChoser(); + $conn = $this->createConnectionMock(); + + $this->assertEquals(1, $choser->pickShard(1, $conn)); + $this->assertEquals(2, $choser->pickShard(2, $conn)); + } + + private function createConnectionMock() + { + return $this->getMock('Doctrine\DBAL\Sharding\PoolingShardConnection', array('connect', 'getParams', 'fetchAll'), array(), '', false); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/ArrayTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/ArrayTest.php new file mode 100644 index 0000000..ac4244d --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/ArrayTest.php @@ -0,0 +1,61 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('array'); + } + + public function tearDown() + { + error_reporting(-1); // reactive all error levels + } + + + public function testArrayConvertsToDatabaseValue() + { + $this->assertTrue( + is_string($this->_type->convertToDatabaseValue(array(), $this->_platform)) + ); + } + + public function testArrayConvertsToPHPValue() + { + $this->assertTrue( + is_array($this->_type->convertToPHPValue(serialize(array()), $this->_platform)) + ); + } + + public function testConversionFailure() + { + error_reporting( (E_ALL | E_STRICT) - \E_NOTICE ); + $this->setExpectedException('Doctrine\DBAL\Types\ConversionException'); + $this->_type->convertToPHPValue('abcdefg', $this->_platform); + } + + public function testNullConversion() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } + + /** + * @group DBAL-73 + */ + public function testFalseConversion() + { + $this->assertFalse($this->_type->convertToPHPValue(serialize(false), $this->_platform)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/BlobTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/BlobTest.php new file mode 100644 index 0000000..756487d --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/BlobTest.php @@ -0,0 +1,26 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('blob'); + } + + public function testBlobNullConvertsToPHPValue() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/BooleanTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/BooleanTest.php new file mode 100644 index 0000000..753cfb4 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/BooleanTest.php @@ -0,0 +1,36 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('boolean'); + } + + public function testBooleanConvertsToDatabaseValue() + { + $this->assertInternalType('integer', $this->_type->convertToDatabaseValue(1, $this->_platform)); + } + + public function testBooleanConvertsToPHPValue() + { + $this->assertInternalType('bool', $this->_type->convertToPHPValue(0, $this->_platform)); + } + + public function testBooleanNullConvertsToPHPValue() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTest.php new file mode 100644 index 0000000..e3763fd --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTest.php @@ -0,0 +1,81 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('date'); + $this->_tz = date_default_timezone_get(); + } + + public function tearDown() + { + date_default_timezone_set($this->_tz); + } + + public function testDateConvertsToDatabaseValue() + { + $this->assertTrue( + is_string($this->_type->convertToDatabaseValue(new \DateTime(), $this->_platform)) + ); + } + + public function testDateConvertsToPHPValue() + { + // Birthday of jwage and also birthday of Doctrine. Send him a present ;) + $this->assertTrue( + $this->_type->convertToPHPValue('1985-09-01', $this->_platform) + instanceof \DateTime + ); + } + + public function testDateResetsNonDatePartsToZeroUnixTimeValues() + { + $date = $this->_type->convertToPHPValue('1985-09-01', $this->_platform); + + $this->assertEquals('00:00:00', $date->format('H:i:s')); + } + + public function testDateRests_SummerTimeAffection() + { + date_default_timezone_set('Europe/Berlin'); + + $date = $this->_type->convertToPHPValue('2009-08-01', $this->_platform); + $this->assertEquals('00:00:00', $date->format('H:i:s')); + $this->assertEquals('2009-08-01', $date->format('Y-m-d')); + + $date = $this->_type->convertToPHPValue('2009-11-01', $this->_platform); + $this->assertEquals('00:00:00', $date->format('H:i:s')); + $this->assertEquals('2009-11-01', $date->format('Y-m-d')); + } + + public function testInvalidDateFormatConversion() + { + $this->setExpectedException('Doctrine\DBAL\Types\ConversionException'); + $this->_type->convertToPHPValue('abcdefg', $this->_platform); + } + + public function testNullConversion() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } + + public function testConvertDateTimeToPHPValue() + { + $date = new \DateTime("now"); + $this->assertSame($date, $this->_type->convertToPHPValue($date, $this->_platform)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php new file mode 100644 index 0000000..58129d2 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php @@ -0,0 +1,56 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('datetime'); + } + + public function testDateTimeConvertsToDatabaseValue() + { + $date = new \DateTime('1985-09-01 10:10:10'); + + $expected = $date->format($this->_platform->getDateTimeTzFormatString()); + $actual = $this->_type->convertToDatabaseValue($date, $this->_platform); + + $this->assertEquals($expected, $actual); + } + + public function testDateTimeConvertsToPHPValue() + { + // Birthday of jwage and also birthday of Doctrine. Send him a present ;) + $date = $this->_type->convertToPHPValue('1985-09-01 00:00:00', $this->_platform); + $this->assertInstanceOf('DateTime', $date); + $this->assertEquals('1985-09-01 00:00:00', $date->format('Y-m-d H:i:s')); + } + + public function testInvalidDateTimeFormatConversion() + { + $this->setExpectedException('Doctrine\DBAL\Types\ConversionException'); + $this->_type->convertToPHPValue('abcdefg', $this->_platform); + } + + public function testNullConversion() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } + + public function testConvertDateTimeToPHPValue() + { + $date = new \DateTime("now"); + $this->assertSame($date, $this->_type->convertToPHPValue($date, $this->_platform)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php new file mode 100644 index 0000000..08c250a --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php @@ -0,0 +1,56 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('datetimetz'); + } + + public function testDateTimeConvertsToDatabaseValue() + { + $date = new \DateTime('1985-09-01 10:10:10'); + + $expected = $date->format($this->_platform->getDateTimeTzFormatString()); + $actual = $this->_type->convertToDatabaseValue($date, $this->_platform); + + $this->assertEquals($expected, $actual); + } + + public function testDateTimeConvertsToPHPValue() + { + // Birthday of jwage and also birthday of Doctrine. Send him a present ;) + $date = $this->_type->convertToPHPValue('1985-09-01 00:00:00', $this->_platform); + $this->assertInstanceOf('DateTime', $date); + $this->assertEquals('1985-09-01 00:00:00', $date->format('Y-m-d H:i:s')); + } + + public function testInvalidDateFormatConversion() + { + $this->setExpectedException('Doctrine\DBAL\Types\ConversionException'); + $this->_type->convertToPHPValue('abcdefg', $this->_platform); + } + + public function testNullConversion() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } + + public function testConvertDateTimeToPHPValue() + { + $date = new \DateTime("now"); + $this->assertSame($date, $this->_type->convertToPHPValue($date, $this->_platform)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DecimalTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DecimalTest.php new file mode 100644 index 0000000..983029c --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/DecimalTest.php @@ -0,0 +1,31 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('decimal'); + } + + public function testDecimalConvertsToPHPValue() + { + $this->assertInternalType('string', $this->_type->convertToPHPValue('5.5', $this->_platform)); + } + + public function testDecimalNullConvertsToPHPValue() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/FloatTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/FloatTest.php new file mode 100644 index 0000000..38d9237 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/FloatTest.php @@ -0,0 +1,39 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('float'); + } + + public function testFloatConvertsToPHPValue() + { + $this->assertInternalType('float', $this->_type->convertToPHPValue('5.5', $this->_platform)); + } + + public function testFloatNullConvertsToPHPValue() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } + + public function testFloatConvertToDatabaseValue() + { + $this->assertInternalType('float', $this->_type->convertToDatabaseValue(5.5, $this->_platform)); + } + + public function testFloatNullConvertToDatabaseValue() + { + $this->assertNull($this->_type->convertToDatabaseValue(null, $this->_platform)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/GuidTypeTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/GuidTypeTest.php new file mode 100644 index 0000000..0f61183 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/GuidTypeTest.php @@ -0,0 +1,31 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('guid'); + } + + public function testConvertToPHPValue() + { + $this->assertInternalType("string", $this->_type->convertToPHPValue("foo", $this->_platform)); + $this->assertInternalType("string", $this->_type->convertToPHPValue("", $this->_platform)); + } + + public function testNullConversion() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } +} + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/IntegerTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/IntegerTest.php new file mode 100644 index 0000000..adcde53 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/IntegerTest.php @@ -0,0 +1,32 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('integer'); + } + + public function testIntegerConvertsToPHPValue() + { + $this->assertInternalType('integer', $this->_type->convertToPHPValue('1', $this->_platform)); + $this->assertInternalType('integer', $this->_type->convertToPHPValue('0', $this->_platform)); + } + + public function testIntegerNullConvertsToPHPValue() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/ObjectTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/ObjectTest.php new file mode 100644 index 0000000..d25c49a --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/ObjectTest.php @@ -0,0 +1,56 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('object'); + } + + public function tearDown() + { + error_reporting(-1); // reactive all error levels + } + + public function testObjectConvertsToDatabaseValue() + { + $this->assertInternalType('string', $this->_type->convertToDatabaseValue(new \stdClass(), $this->_platform)); + } + + public function testObjectConvertsToPHPValue() + { + $this->assertInternalType('object', $this->_type->convertToPHPValue(serialize(new \stdClass), $this->_platform)); + } + + public function testConversionFailure() + { + error_reporting( (E_ALL | E_STRICT) - \E_NOTICE ); + $this->setExpectedException('Doctrine\DBAL\Types\ConversionException'); + $this->_type->convertToPHPValue('abcdefg', $this->_platform); + } + + public function testNullConversion() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } + + /** + * @group DBAL-73 + */ + public function testFalseConversion() + { + $this->assertFalse($this->_type->convertToPHPValue(serialize(false), $this->_platform)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/SmallIntTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/SmallIntTest.php new file mode 100644 index 0000000..399095c --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/SmallIntTest.php @@ -0,0 +1,32 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('smallint'); + } + + public function testSmallIntConvertsToPHPValue() + { + $this->assertInternalType('integer', $this->_type->convertToPHPValue('1', $this->_platform)); + $this->assertInternalType('integer', $this->_type->convertToPHPValue('0', $this->_platform)); + } + + public function testSmallIntNullConvertsToPHPValue() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/StringTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/StringTest.php new file mode 100644 index 0000000..52d2955 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/StringTest.php @@ -0,0 +1,49 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('string'); + } + + public function testReturnsSqlDeclarationFromPlatformVarchar() + { + $this->assertEquals("DUMMYVARCHAR()", $this->_type->getSqlDeclaration(array(), $this->_platform)); + } + + public function testReturnsDefaultLengthFromPlatformVarchar() + { + $this->assertEquals(255, $this->_type->getDefaultLength($this->_platform)); + } + + public function testConvertToPHPValue() + { + $this->assertInternalType("string", $this->_type->convertToPHPValue("foo", $this->_platform)); + $this->assertInternalType("string", $this->_type->convertToPHPValue("", $this->_platform)); + } + + public function testNullConversion() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } + + public function testSQLConversion() + { + $this->assertFalse($this->_type->canRequireSQLConversion(), "String type can never require SQL conversion to work."); + $this->assertEquals('t.foo', $this->_type->convertToDatabaseValueSQL('t.foo', $this->_platform)); + $this->assertEquals('t.foo', $this->_type->convertToPHPValueSQL('t.foo', $this->_platform)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/TimeTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/TimeTest.php new file mode 100644 index 0000000..8a07b9b --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/TimeTest.php @@ -0,0 +1,53 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('time'); + } + + public function testTimeConvertsToDatabaseValue() + { + $this->assertTrue( + is_string($this->_type->convertToDatabaseValue(new \DateTime(), $this->_platform)) + ); + } + + public function testTimeConvertsToPHPValue() + { + $this->assertTrue( + $this->_type->convertToPHPValue('5:30:55', $this->_platform) + instanceof \DateTime + ); + } + + public function testInvalidTimeFormatConversion() + { + $this->setExpectedException('Doctrine\DBAL\Types\ConversionException'); + $this->_type->convertToPHPValue('abcdefg', $this->_platform); + } + + public function testNullConversion() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } + + public function testConvertDateTimeToPHPValue() + { + $date = new \DateTime("now"); + $this->assertSame($date, $this->_type->convertToPHPValue($date, $this->_platform)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/VarDateTimeTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/VarDateTimeTest.php new file mode 100644 index 0000000..329ef8c --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/Types/VarDateTimeTest.php @@ -0,0 +1,68 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + if (!Type::hasType('vardatetime')) { + Type::addType('vardatetime', 'Doctrine\DBAL\Types\VarDateTimeType'); + } + $this->_type = Type::getType('vardatetime'); + } + + public function testDateTimeConvertsToDatabaseValue() + { + $date = new \DateTime('1985-09-01 10:10:10'); + + $expected = $date->format($this->_platform->getDateTimeTzFormatString()); + $actual = $this->_type->convertToDatabaseValue($date, $this->_platform); + + $this->assertEquals($expected, $actual); + } + + public function testDateTimeConvertsToPHPValue() + { + // Birthday of jwage and also birthday of Doctrine. Send him a present ;) + $date = $this->_type->convertToPHPValue('1985-09-01 00:00:00', $this->_platform); + $this->assertInstanceOf('DateTime', $date); + $this->assertEquals('1985-09-01 00:00:00', $date->format('Y-m-d H:i:s')); + $this->assertEquals('000000', $date->format('u')); + } + + public function testInvalidDateTimeFormatConversion() + { + $this->setExpectedException('Doctrine\DBAL\Types\ConversionException'); + $this->_type->convertToPHPValue('abcdefg', $this->_platform); + } + + public function testConversionWithMicroseconds() + { + $date = $this->_type->convertToPHPValue('1985-09-01 00:00:00.123456', $this->_platform); + $this->assertInstanceOf('DateTime', $date); + $this->assertEquals('1985-09-01 00:00:00', $date->format('Y-m-d H:i:s')); + $this->assertEquals('123456', $date->format('u')); + } + + public function testNullConversion() + { + $this->assertNull($this->_type->convertToPHPValue(null, $this->_platform)); + } + + public function testConvertDateTimeToPHPValue() + { + $date = new \DateTime("now"); + $this->assertSame($date, $this->_type->convertToPHPValue($date, $this->_platform)); + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/UtilTest.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/UtilTest.php new file mode 100644 index 0000000..b793e35 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DBAL/UtilTest.php @@ -0,0 +1,78 @@ + ':param1') + ), + array( + 'SELECT name FROM users WHERE id = ? AND status = ?', + 'SELECT name FROM users WHERE id = :param1 AND status = :param2', + array(1 => ':param1', 2 => ':param2'), + ), + array( + "UPDATE users SET name = '???', status = ?", + "UPDATE users SET name = '???', status = :param1", + array(1 => ':param1'), + ), + array( + "UPDATE users SET status = ?, name = '???'", + "UPDATE users SET status = :param1, name = '???'", + array(1 => ':param1'), + ), + array( + "UPDATE users SET foo = ?, name = '???', status = ?", + "UPDATE users SET foo = :param1, name = '???', status = :param2", + array(1 => ':param1', 2 => ':param2'), + ), + array( + 'UPDATE users SET name = "???", status = ?', + 'UPDATE users SET name = "???", status = :param1', + array(1 => ':param1'), + ), + array( + 'UPDATE users SET status = ?, name = "???"', + 'UPDATE users SET status = :param1, name = "???"', + array(1 => ':param1'), + ), + array( + 'UPDATE users SET foo = ?, name = "???", status = ?', + 'UPDATE users SET foo = :param1, name = "???", status = :param2', + array(1 => ':param1', 2 => ':param2'), + ), + array( + 'SELECT * FROM users WHERE id = ? AND name = "" AND status = ?', + 'SELECT * FROM users WHERE id = :param1 AND name = "" AND status = :param2', + array(1 => ':param1', 2 => ':param2'), + ), + array( + "SELECT * FROM users WHERE id = ? AND name = '' AND status = ?", + "SELECT * FROM users WHERE id = :param1 AND name = '' AND status = :param2", + array(1 => ':param1', 2 => ':param2'), + ) + ); + } + + /** + * @dataProvider dataConvertPositionalToNamedParameters + * @param string $inputSQL + * @param string $expectedOutputSQL + * @param array $expectedOutputParamsMap + */ + public function testConvertPositionalToNamedParameters($inputSQL, $expectedOutputSQL, $expectedOutputParamsMap) + { + list($statement, $params) = \Doctrine\DBAL\Driver\OCI8\OCI8Statement::convertPositionalToNamedPlaceholders($inputSQL); + + $this->assertEquals($expectedOutputSQL, $statement); + $this->assertEquals($expectedOutputParamsMap, $params); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DbalFunctionalTestCase.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DbalFunctionalTestCase.php new file mode 100644 index 0000000..27dd149 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DbalFunctionalTestCase.php @@ -0,0 +1,77 @@ +close(); + self::$_sharedConn = null; + } + } + + protected function setUp() + { + if ( ! isset(self::$_sharedConn)) { + self::$_sharedConn = TestUtil::getConnection(); + } + $this->_conn = self::$_sharedConn; + + $this->_sqlLoggerStack = new \Doctrine\DBAL\Logging\DebugStack(); + $this->_conn->getConfiguration()->setSQLLogger($this->_sqlLoggerStack); + } + + protected function onNotSuccessfulTest(\Exception $e) + { + if ($e instanceof \PHPUnit_Framework_AssertionFailedError) { + throw $e; + } + + if(isset($this->_sqlLoggerStack->queries) && count($this->_sqlLoggerStack->queries)) { + $queries = ""; + $i = count($this->_sqlLoggerStack->queries); + foreach (array_reverse($this->_sqlLoggerStack->queries) AS $query) { + $params = array_map(function($p) { if (is_object($p)) return get_class($p); else return "'".$p."'"; }, $query['params'] ?: array()); + $queries .= ($i+1).". SQL: '".$query['sql']."' Params: ".implode(", ", $params).PHP_EOL; + $i--; + } + + $trace = $e->getTrace(); + $traceMsg = ""; + foreach($trace AS $part) { + if(isset($part['file'])) { + if(strpos($part['file'], "PHPUnit/") !== false) { + // Beginning with PHPUnit files we don't print the trace anymore. + break; + } + + $traceMsg .= $part['file'].":".$part['line'].PHP_EOL; + } + } + + $message = "[".get_class($e)."] ".$e->getMessage().PHP_EOL.PHP_EOL."With queries:".PHP_EOL.$queries.PHP_EOL."Trace:".PHP_EOL.$traceMsg; + + throw new \Exception($message, (int)$e->getCode(), $e); + } + throw $e; + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/DbalTestCase.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/DbalTestCase.php new file mode 100644 index 0000000..2478e7b --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/DbalTestCase.php @@ -0,0 +1,10 @@ +_platformMock = new DatabasePlatformMock(); + + parent::__construct($params, $driver, $config, $eventManager); + + // Override possible assignment of platform to database platform mock + $this->_platform = $this->_platformMock; + } + + /** + * @override + */ + public function getDatabasePlatform() + { + return $this->_platformMock; + } + + /** + * @override + */ + public function insert($tableName, array $data, array $types = array()) + { + $this->_inserts[$tableName][] = $data; + } + + /** + * @override + */ + public function lastInsertId($seqName = null) + { + return $this->_lastInsertId; + } + + /** + * @override + */ + public function fetchColumn($statement, array $params = array(), $colnum = 0) + { + return $this->_fetchOneResult; + } + + /** + * @override + */ + public function quote($input, $type = null) + { + if (is_string($input)) { + return "'" . $input . "'"; + } + return $input; + } + + /* Mock API */ + + public function setFetchOneResult($fetchOneResult) + { + $this->_fetchOneResult = $fetchOneResult; + } + + public function setDatabasePlatform($platform) + { + $this->_platformMock = $platform; + } + + public function setLastInsertId($id) + { + $this->_lastInsertId = $id; + } + + public function getInserts() + { + return $this->_inserts; + } + + public function reset() + { + $this->_inserts = array(); + $this->_lastInsertId = 0; + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php new file mode 100644 index 0000000..0153f9b --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php @@ -0,0 +1,98 @@ +_prefersIdentityColumns; + } + + /** + * @override + */ + public function prefersSequences() + { + return $this->_prefersSequences; + } + + /** @override */ + public function getSequenceNextValSQL($sequenceName) + { + return $this->_sequenceNextValSql; + } + + /** @override */ + public function getBooleanTypeDeclarationSQL(array $field) {} + + /** @override */ + public function getIntegerTypeDeclarationSQL(array $field) {} + + /** @override */ + public function getBigIntTypeDeclarationSQL(array $field) {} + + /** @override */ + public function getSmallIntTypeDeclarationSQL(array $field) {} + + /** @override */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) {} + + /** @override */ + public function getVarcharTypeDeclarationSQL(array $field) {} + + /** @override */ + public function getClobTypeDeclarationSQL(array $field) {} + + /* MOCK API */ + + public function setPrefersIdentityColumns($bool) + { + $this->_prefersIdentityColumns = $bool; + } + + public function setPrefersSequences($bool) + { + $this->_prefersSequences = $bool; + } + + public function setSequenceNextValSql($sql) + { + $this->_sequenceNextValSql = $sql; + } + + public function getName() + { + return 'mock'; + } + protected function initializeDoctrineTypeMappings() { + } + protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) + { + + } + /** + * Gets the SQL Snippet used to declare a BLOB column type. + */ + public function getBlobTypeDeclarationSQL(array $field) + { + throw DBALException::notSupported(__METHOD__); + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php new file mode 100644 index 0000000..03d44ca --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php @@ -0,0 +1,17 @@ +_platformMock) { + $this->_platformMock = new DatabasePlatformMock; + } + return $this->_platformMock; + } + + /** + * @override + */ + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + if($this->_schemaManagerMock == null) { + return new SchemaManagerMock($conn); + } else { + return $this->_schemaManagerMock; + } + } + + /* MOCK API */ + + public function setDatabasePlatform(\Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + $this->_platformMock = $platform; + } + + public function setSchemaManager(\Doctrine\DBAL\Schema\AbstractSchemaManager $sm) + { + $this->_schemaManagerMock = $sm; + } + + public function getName() + { + return 'mock'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + return; + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/HydratorMockStatement.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/HydratorMockStatement.php new file mode 100644 index 0000000..629352f --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/HydratorMockStatement.php @@ -0,0 +1,101 @@ + + */ +class HydratorMockStatement implements \Doctrine\DBAL\Driver\Statement +{ + private $_resultSet; + + /** + * Creates a new mock statement that will serve the provided fake result set to clients. + * + * @param array $resultSet The faked SQL result set. + */ + public function __construct(array $resultSet) + { + $this->_resultSet = $resultSet; + } + + /** + * Fetches all rows from the result set. + * + * @return array + */ + public function fetchAll($fetchMode = null, $columnIndex = null, array $ctorArgs = null) + { + return $this->_resultSet; + } + + public function fetchColumn($columnNumber = 0) + { + $row = current($this->_resultSet); + if ( ! is_array($row)) return false; + $val = array_shift($row); + return $val !== null ? $val : false; + } + + /** + * Fetches the next row in the result set. + * + */ + public function fetch($fetchMode = null) + { + $current = current($this->_resultSet); + next($this->_resultSet); + return $current; + } + + /** + * Closes the cursor, enabling the statement to be executed again. + * + * @return boolean + */ + public function closeCursor() + { + return true; + } + + public function setResultSet(array $resultSet) + { + reset($resultSet); + $this->_resultSet = $resultSet; + } + + public function bindColumn($column, &$param, $type = null) + { + } + + public function bindValue($param, $value, $type = null) + { + } + + public function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array()) + { + } + + public function columnCount() + { + } + + public function errorCode() + { + } + + public function errorInfo() + { + } + + public function execute($params = array()) + { + } + + public function rowCount() + { + } +} \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/SchemaManagerMock.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/SchemaManagerMock.php new file mode 100644 index 0000000..d4c3c28 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/Mocks/SchemaManagerMock.php @@ -0,0 +1,13 @@ +. + */ + +namespace Doctrine\Tests\Mocks; + +use Doctrine\Common\Cli\AbstractNamespace; + +/** + * TaskMock used for testing the CLI interface. + * @author Nils Adermann + */ +class TaskMock extends \Doctrine\Common\Cli\Tasks\AbstractTask +{ + /** + * Since instances of this class can be created elsewhere all instances + * register themselves in this array for later inspection. + * + * @var array(TaskMock) + */ + static public $instances = array(); + + private $runCounter = 0; + + /** + * Constructor of Task Mock Object. + * Makes sure the object can be inspected later. + * + * @param AbstractNamespace CLI Namespace, passed to parent constructor + */ + function __construct(AbstractNamespace $namespace) + { + self::$instances[] = $this; + + parent::__construct($namespace); + } + + /** + * Returns the number of times run() was called on this object. + * + * @return int + */ + public function getRunCounter() + { + return $this->runCounter; + } + + /* Mock API */ + + /** + * Method invoked by CLI to run task. + */ + public function run() + { + $this->runCounter++; + } + + /** + * Method supposed to generate the CLI Task Documentation + */ + public function buildDocumentation() + { + } +} diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/TestInit.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/TestInit.php new file mode 100644 index 0000000..6580343 --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/TestInit.php @@ -0,0 +1,22 @@ +register(); + +$classLoader = new \Doctrine\Common\ClassLoader('Doctrine\DBAL', __DIR__ . '/../../../lib'); +$classLoader->register(); + +$classLoader = new \Doctrine\Common\ClassLoader('Doctrine\Tests', __DIR__ . '/../../'); +$classLoader->register(); + +$classLoader = new \Doctrine\Common\ClassLoader('Symfony', __DIR__ . "/../../../lib/vendor"); +$classLoader->register(); + diff --git a/vendor/doctrine/dbal/tests/Doctrine/Tests/TestUtil.php b/vendor/doctrine/dbal/tests/Doctrine/Tests/TestUtil.php new file mode 100644 index 0000000..8701c0a --- /dev/null +++ b/vendor/doctrine/dbal/tests/Doctrine/Tests/TestUtil.php @@ -0,0 +1,130 @@ +real database connection using the following parameters + * of the $GLOBALS array: + * + * 'db_type' : The name of the Doctrine DBAL database driver to use. + * 'db_username' : The username to use for connecting. + * 'db_password' : The password to use for connecting. + * 'db_host' : The hostname of the database to connect to. + * 'db_name' : The name of the database to connect to. + * 'db_port' : The port of the database to connect to. + * + * Usually these variables of the $GLOBALS array are filled by PHPUnit based + * on an XML configuration file. If no such parameters exist, an SQLite + * in-memory database is used. + * + * IMPORTANT: + * 1) Each invocation of this method returns a NEW database connection. + * 2) The database is dropped and recreated to ensure it's clean. + * + * @return \Doctrine\DBAL\Connection The database connection instance. + */ + public static function getConnection() + { + if (isset($GLOBALS['db_type'], $GLOBALS['db_username'], $GLOBALS['db_password'], + $GLOBALS['db_host'], $GLOBALS['db_name'], $GLOBALS['db_port']) && + isset($GLOBALS['tmpdb_type'], $GLOBALS['tmpdb_username'], $GLOBALS['tmpdb_password'], + $GLOBALS['tmpdb_host'], $GLOBALS['tmpdb_name'], $GLOBALS['tmpdb_port'])) { + $realDbParams = array( + 'driver' => $GLOBALS['db_type'], + 'user' => $GLOBALS['db_username'], + 'password' => $GLOBALS['db_password'], + 'host' => $GLOBALS['db_host'], + 'dbname' => $GLOBALS['db_name'], + 'port' => $GLOBALS['db_port'] + ); + $tmpDbParams = array( + 'driver' => $GLOBALS['tmpdb_type'], + 'user' => $GLOBALS['tmpdb_username'], + 'password' => $GLOBALS['tmpdb_password'], + 'host' => $GLOBALS['tmpdb_host'], + 'dbname' => $GLOBALS['tmpdb_name'], + 'port' => $GLOBALS['tmpdb_port'] + ); + + if (isset($GLOBALS['db_unix_socket'])) { + $realDbParams['unix_socket'] = $GLOBALS['db_unix_socket']; + } + + if (isset($GLOBALS['tmpdb_unix_socket'])) { + $tmpDbParams['unix_socket'] = $GLOBALS['tmpdb_unix_socket']; + } + + $realConn = \Doctrine\DBAL\DriverManager::getConnection($realDbParams); + + $platform = $realConn->getDatabasePlatform(); + + if ($platform->supportsCreateDropDatabase()) { + $dbname = $realConn->getDatabase(); + // Connect to tmpdb in order to drop and create the real test db. + $tmpConn = \Doctrine\DBAL\DriverManager::getConnection($tmpDbParams); + $realConn->close(); + + $tmpConn->getSchemaManager()->dropAndCreateDatabase($dbname); + + $tmpConn->close(); + } else { + $sm = $realConn->getSchemaManager(); + + /* @var $schema Schema */ + $schema = $sm->createSchema(); + $stmts = $schema->toDropSql($realConn->getDatabasePlatform()); + + foreach ($stmts AS $stmt) { + $realConn->exec($stmt); + } + } + + $conn = \Doctrine\DBAL\DriverManager::getConnection($realDbParams, null, null); + } else { + $params = array( + 'driver' => 'pdo_sqlite', + 'memory' => true + ); + if (isset($GLOBALS['db_path'])) { + $params['path'] = $GLOBALS['db_path']; + unlink($GLOBALS['db_path']); + } + $conn = \Doctrine\DBAL\DriverManager::getConnection($params); + } + + if (isset($GLOBALS['db_event_subscribers'])) { + $evm = $conn->getEventManager(); + foreach (explode(",", $GLOBALS['db_event_subscribers']) AS $subscriberClass) { + $subscriberInstance = new $subscriberClass(); + $evm->addEventSubscriber($subscriberInstance); + } + } + + return $conn; + } + + /** + * @return \Doctrine\DBAL\Connection + */ + public static function getTempConnection() + { + $tmpDbParams = array( + 'driver' => $GLOBALS['tmpdb_type'], + 'user' => $GLOBALS['tmpdb_username'], + 'password' => $GLOBALS['tmpdb_password'], + 'host' => $GLOBALS['tmpdb_host'], + 'dbname' => $GLOBALS['tmpdb_name'], + 'port' => $GLOBALS['tmpdb_port'] + ); + + // Connect to tmpdb in order to drop and create the real test db. + return \Doctrine\DBAL\DriverManager::getConnection($tmpDbParams); + } +} diff --git a/vendor/doctrine/dbal/tests/README.markdown b/vendor/doctrine/dbal/tests/README.markdown new file mode 100644 index 0000000..c1027ac --- /dev/null +++ b/vendor/doctrine/dbal/tests/README.markdown @@ -0,0 +1,25 @@ +# Running the Doctrine 2 Testsuite + +## Setting up a PHPUnit Configuration XML + +.. + +## Testing Lock-Support + +The Lock support in Doctrine 2 is tested using Gearman, which allows to run concurrent tasks in parallel. +Install Gearman with PHP as follows: + +1. Go to http://www.gearman.org and download the latest Gearman Server +2. Compile it and then call ldconfig +3. Start it up "gearmand -vvvv" +4. Install pecl/gearman by calling "gearman-beta" + +You can then go into tests/ and start up two workers: + + php Doctrine/Tests/ORM/Functional/Locking/LockAgentWorker.php + +Then run the locking test-suite: + + phpunit --configuration Doctrine/Tests/ORM/Functional/Locking/GearmanLockTest.php + +This can run considerable time, because it is using sleep() to test for the timing ranges of locks. \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/travis/mysql.travis.xml b/vendor/doctrine/dbal/tests/travis/mysql.travis.xml new file mode 100644 index 0000000..c80f4d2 --- /dev/null +++ b/vendor/doctrine/dbal/tests/travis/mysql.travis.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + ./../Doctrine/Tests/DBAL + + + + + performance + locking_functional + + + + + diff --git a/vendor/doctrine/dbal/tests/travis/mysqli.travis.xml b/vendor/doctrine/dbal/tests/travis/mysqli.travis.xml new file mode 100644 index 0000000..ace5df4 --- /dev/null +++ b/vendor/doctrine/dbal/tests/travis/mysqli.travis.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + ./../Doctrine/Tests/DBAL + + + + + performance + locking_functional + + + + + diff --git a/vendor/doctrine/dbal/tests/travis/pgsql.travis.xml b/vendor/doctrine/dbal/tests/travis/pgsql.travis.xml new file mode 100644 index 0000000..e3bd7ea --- /dev/null +++ b/vendor/doctrine/dbal/tests/travis/pgsql.travis.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + ./../Doctrine/Tests/DBAL + + + + + performance + locking_functional + + + \ No newline at end of file diff --git a/vendor/doctrine/dbal/tests/travis/sqlite.travis.xml b/vendor/doctrine/dbal/tests/travis/sqlite.travis.xml new file mode 100644 index 0000000..944f137 --- /dev/null +++ b/vendor/doctrine/dbal/tests/travis/sqlite.travis.xml @@ -0,0 +1,14 @@ + + + + + ./../Doctrine/Tests/DBAL + + + + + performance + locking_functional + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/.gitignore b/vendor/doctrine/orm/.gitignore new file mode 100644 index 0000000..b49fac4 --- /dev/null +++ b/vendor/doctrine/orm/.gitignore @@ -0,0 +1,11 @@ +build/ +logs/ +reports/ +dist/ +download/ +lib/api/ +lib/Doctrine/Common +lib/Doctrine/DBAL +/.settings/ +.buildpath +.project \ No newline at end of file diff --git a/vendor/doctrine/orm/.gitmodules b/vendor/doctrine/orm/.gitmodules new file mode 100644 index 0000000..2d52e9a --- /dev/null +++ b/vendor/doctrine/orm/.gitmodules @@ -0,0 +1,15 @@ +[submodule "lib/vendor/doctrine-common"] + path = lib/vendor/doctrine-common + url = git://github.com/doctrine/common.git +[submodule "lib/vendor/doctrine-dbal"] + path = lib/vendor/doctrine-dbal + url = git://github.com/doctrine/dbal.git +[submodule "lib/vendor/Symfony/Component/Console"] + path = lib/vendor/Symfony/Component/Console + url = git://github.com/symfony/Console.git +[submodule "lib/vendor/Symfony/Component/Yaml"] + path = lib/vendor/Symfony/Component/Yaml + url = git://github.com/symfony/Yaml.git +[submodule "lib/vendor/doctrine-build-common"] + path = lib/vendor/doctrine-build-common + url = git://github.com/doctrine/doctrine-build-common.git diff --git a/vendor/doctrine/orm/.travis.yml b/vendor/doctrine/orm/.travis.yml new file mode 100644 index 0000000..716b9b6 --- /dev/null +++ b/vendor/doctrine/orm/.travis.yml @@ -0,0 +1,19 @@ +language: php + +php: + - 5.3 + - 5.4 +env: + - DB=mysql + - DB=pgsql + - DB=sqlite + +before_script: + - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS doctrine_tests;' -U postgres; fi" + - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS doctrine_tests_tmp;' -U postgres; fi" + - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests;' -U postgres; fi" + - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database doctrine_tests_tmp;' -U postgres; fi" + - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS doctrine_tests_tmp;create database IF NOT EXISTS doctrine_tests;'; fi" + - git submodule update --init + +script: phpunit --configuration tests/travis/$DB.travis.xml \ No newline at end of file diff --git a/vendor/doctrine/orm/LICENSE b/vendor/doctrine/orm/LICENSE new file mode 100644 index 0000000..4a91f0b --- /dev/null +++ b/vendor/doctrine/orm/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2012 Doctrine Project + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/doctrine/orm/README.markdown b/vendor/doctrine/orm/README.markdown new file mode 100644 index 0000000..54e9e8e --- /dev/null +++ b/vendor/doctrine/orm/README.markdown @@ -0,0 +1,19 @@ +# Doctrine 2 ORM + +Master: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=master)](http://travis-ci.org/doctrine/doctrine2) +2.2: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.2)](http://travis-ci.org/doctrine/doctrine2) +2.1: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.1.x)](http://travis-ci.org/doctrine/doctrine2) + +Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.2+ that provides transparent persistence +for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features +is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL), +inspired by Hibernates HQL. This provides developers with a powerful alternative to SQL that maintains flexibility +without requiring unnecessary code duplication. + +## More resources: + +* [Website](http://www.doctrine-project.org) +* [Documentation](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html) +* [Issue Tracker](http://www.doctrine-project.org/jira/browse/DDC) +* [Downloads](http://github.com/doctrine/doctrine2/downloads) + diff --git a/vendor/doctrine/orm/UPGRADE.md b/vendor/doctrine/orm/UPGRADE.md new file mode 100644 index 0000000..ef30c4f --- /dev/null +++ b/vendor/doctrine/orm/UPGRADE.md @@ -0,0 +1,467 @@ +# Upgrade to 2.3 + +## EntityGenerator add*() method generation + +When generating an add*() method for a collection the EntityGenerator will now not +use the Type-Hint to get the singular for the collection name, but use the field-name +and strip a trailing "s" character if there is one. + +## Merge copies non persisted properties too + +When merging an entity in UoW not only mapped properties are copied, but also others. + +## Query, QueryBuilder and NativeQuery parameters *BC break* + +From now on, parameters in queries is an ArrayCollection instead of a simple array. +This affects heavily the usage of setParameters(), because it will not append anymore +parameters to query, but will actually override the already defined ones. +Whenever you are retrieving a parameter (ie. $query->getParameter(1)), you will +receive an instance of Query\Parameter, which contains the methods "getName", +"getValue" and "getType". Parameters are also only converted to when necessary, and +not when they are set. + +Also, related functions were affected: + +* execute($parameters, $hydrationMode) the argument $parameters can be either an key=>value array or an ArrayCollection instance +* iterate($parameters, $hydrationMode) the argument $parameters can be either an key=>value array or an ArrayCollection instance +* setParameters($parameters) the argument $parameters can be either an key=>value array or an ArrayCollection instance +* getParameters() now returns ArrayCollection instead of array +* getParameter($key) now returns Parameter instance instead of parameter value + +## Query TreeWalker method renamed + +Internal changes were made to DQL and SQL generation. If you have implemented your own TreeWalker, +you probably need to update it. The method walkJoinVariableDeclaration is now named walkJoin. + +## Metadata Drivers + +Metadata drivers have been rewritten to reuse code from Doctrine\Common. Anyone who is using the +`Doctrine\ORM\Mapping\Driver\Driver` interface should instead refer to +`Doctrine\Common\Persistence\Mapping\Driver\MappingDriver`. Same applies to +`Doctrine\ORM\Mapping\Driver\AbstractFileDriver`: you should now refer to +`Doctrine\Common\Persistence\Mapping\Driver\FileDriver`. + +Also, following mapping drivers have been deprecated, please use their replacements in Doctrine\Common as listed: + + * `Doctrine\ORM\Mapping\Driver\DriverChain` => `Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain` + * `Doctrine\ORM\Mapping\Driver\PHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\PHPDriver` + * `Doctrine\ORM\Mapping\Driver\StaticPHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver` + +# Upgrade to 2.2 + +## ResultCache implementation rewritten + +The result cache is completely rewritten and now works on the database result level, not inside the ORM AbstractQuery +anymore. This means that for result cached queries the hydration will now always be performed again, regardless of +the hydration mode. Affected areas are: + +1. Fixes the problem that entities coming from the result cache were not registered in the UnitOfWork + leading to problems during EntityManager#flush. Calls to EntityManager#merge are not necessary anymore. +2. Affects the array hydrator which now includes the overhead of hydration compared to caching the final result. + +The API is backwards compatible however most of the getter methods on the `AbstractQuery` object are now +deprecated in favor of calling AbstractQuery#getQueryCacheProfile(). This method returns a `Doctrine\DBAL\Cache\QueryCacheProfile` +instance with access to result cache driver, lifetime and cache key. + + +## EntityManager#getPartialReference() creates read-only entity + +Entities returned from EntityManager#getPartialReference() are now marked as read-only if they +haven't been in the identity map before. This means objects of this kind never lead to changes +in the UnitOfWork. + + +## Fields omitted in a partial DQL query or a native query are never updated + +Fields of an entity that are not returned from a partial DQL Query or native SQL query +will never be updated through an UPDATE statement. + + +## Removed support for onUpdate in @JoinColumn + +The onUpdate foreign key handling makes absolutely no sense in an ORM. Additionally Oracle doesn't even support it. Support for it is removed. + + +## Changes in Annotation Handling + +There have been some changes to the annotation handling in Common 2.2 again, that affect how people with old configurations +from 2.0 have to configure the annotation driver if they don't use `Configuration::newDefaultAnnotationDriver()`: + + // Register the ORM Annotations in the AnnotationRegistry + AnnotationRegistry::registerFile('path/to/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php'); + + $reader = new \Doctrine\Common\Annotations\SimpleAnnotationReader(); + $reader->addNamespace('Doctrine\ORM\Mapping'); + $reader = new \Doctrine\Common\Annotations\CachedReader($reader, new ArrayCache()); + + $driver = new AnnotationDriver($reader, (array)$paths); + + $config->setMetadataDriverImpl($driver); + + +## Scalar mappings can now be ommitted from DQL result + +You are now allowed to mark scalar SELECT expressions as HIDDEN an they are not hydrated anymore. +Example: + +SELECT u, SUM(a.id) AS HIDDEN numArticles FROM User u LEFT JOIN u.Articles a ORDER BY numArticles DESC HAVING numArticles > 10 + +Your result will be a collection of Users, and not an array with key 0 as User object instance and "numArticles" as the number of articles per user + + +## Map entities as scalars in DQL result + +When hydrating to array or even a mixed result in object hydrator, previously you had the 0 index holding you entity instance. +You are now allowed to alias this, providing more flexibility for you code. +Example: + +SELECT u AS user FROM User u + +Will now return a collection of arrays with index "user" pointing to the User object instance. + + +## Performance optimizations + +Thousands of lines were completely reviewed and optimized for best performance. +Removed redundancy and improved code readability made now internal Doctrine code easier to understand. +Also, Doctrine 2.2 now is around 10-15% faster than 2.1. + +## EntityManager#find(null) + +Previously EntityManager#find(null) returned null. It now throws an exception. + +# Upgrade to 2.1 + +## Interface for EntityRepository + +The EntityRepository now has an interface Doctrine\Common\Persistence\ObjectRepository. This means that your classes that override EntityRepository and extend find(), findOneBy() or findBy() must be adjusted to follow this interface. + +## AnnotationReader changes + +The annotation reader was heavily refactored between 2.0 and 2.1-RC1. In theory the operation of the new reader should be backwards compatible, but it has to be setup differently to work that way: + + // new call to the AnnotationRegistry + \Doctrine\Common\Annotations\AnnotationRegistry::registerFile('/doctrine-src/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php'); + + $reader = new \Doctrine\Common\Annotations\AnnotationReader(); + $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); + // new code necessary starting here + $reader->setIgnoreNotImportedAnnotations(true); + $reader->setEnableParsePhpImports(false); + $reader = new \Doctrine\Common\Annotations\CachedReader( + new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache() + ); + +This is already done inside the ``$config->newDefaultAnnotationDriver``, so everything should automatically work if you are using this method. You can verify if everything still works by executing a console command such as schema-validate that loads all metadata into memory. + +# Update from 2.0-BETA3 to 2.0-BETA4 + +## XML Driver element demoted to attribute + +We changed how the XML Driver allows to define the change-tracking-policy. The working case is now: + + + +# Update from 2.0-BETA2 to 2.0-BETA3 + +## Serialization of Uninitialized Proxies + +As of Beta3 you can now serialize uninitialized proxies, an exception will only be thrown when +trying to access methods on the unserialized proxy as long as it has not been re-attached to the +EntityManager using `EntityManager#merge()`. See this example: + + $proxy = $em->getReference('User', 1); + + $serializedProxy = serialize($proxy); + $detachedProxy = unserialized($serializedProxy); + + echo $em->contains($detachedProxy); // FALSE + + try { + $detachedProxy->getId(); // uninitialized detached proxy + } catch(Exception $e) { + + } + $attachedProxy = $em->merge($detachedProxy); + echo $attackedProxy->getId(); // works! + +## Changed SQL implementation of Postgres and Oracle DateTime types + +The DBAL Type "datetime" included the Timezone Offset in both Postgres and Oracle. As of this version they are now +generated without Timezone (TIMESTAMP WITHOUT TIME ZONE instead of TIMESTAMP WITH TIME ZONE). +See [this comment to Ticket DBAL-22](http://www.doctrine-project.org/jira/browse/DBAL-22?focusedCommentId=13396&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_13396) +for more details as well as migration issues for PostgreSQL and Oracle. + +Both Postgres and Oracle will throw Exceptions during hydration of Objects with "DateTime" fields unless migration steps are taken! + +## Removed multi-dot/deep-path expressions in DQL + +The support for implicit joins in DQL through the multi-dot/Deep Path Expressions +was dropped. For example: + + SELECT u FROM User u WHERE u.group.name = ?1 + +See the "u.group.id" here is using multi dots (deep expression) to walk +through the graph of objects and properties. Internally the DQL parser +would rewrite these queries to: + + SELECT u FROM User u JOIN u.group g WHERE g.name = ?1 + +This explicit notation will be the only supported notation as of now. The internal +handling of multi-dots in the DQL Parser was very complex, error prone in edge cases +and required special treatment for several features we added. Additionally +it had edge cases that could not be solved without making the DQL Parser +even much more complex. For this reason we will drop the support for the +deep path expressions to increase maintainability and overall performance +of the DQL parsing process. This will benefit any DQL query being parsed, +even those not using deep path expressions. + +Note that the generated SQL of both notations is exactly the same! You +don't loose anything through this. + +## Default Allocation Size for Sequences + +The default allocation size for sequences has been changed from 10 to 1. This step was made +to not cause confusion with users and also because it is partly some kind of premature optimization. + +# Update from 2.0-BETA1 to 2.0-BETA2 + +There are no backwards incompatible changes in this release. + +# Upgrade from 2.0-ALPHA4 to 2.0-BETA1 + +## EntityRepository deprecates access to protected variables + +Instead of accessing protected variables for the EntityManager in +a custom EntityRepository it is now required to use the getter methods +for all the three instance variables: + +* `$this->_em` now accessible through `$this->getEntityManager()` +* `$this->_class` now accessible through `$this->getClassMetadata()` +* `$this->_entityName` now accessible through `$this->getEntityName()` + +Important: For Beta 2 the protected visibility of these three properties will be +changed to private! + +## Console migrated to Symfony Console + +The Doctrine CLI has been replaced by Symfony Console Configuration + +Instead of having to specify: + + [php] + $cliConfig = new CliConfiguration(); + $cliConfig->setAttribute('em', $entityManager); + +You now have to configure the script like: + + [php] + $helperSet = new \Symfony\Components\Console\Helper\HelperSet(array( + 'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()), + 'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em) + )); + +## Console: No need for Mapping Paths anymore + +In previous versions you had to specify the --from and --from-path options +to show where your mapping paths are from the console. However this information +is already known from the Mapping Driver configuration, so the requirement +for this options were dropped. + +Instead for each console command all the entities are loaded and to +restrict the operation to one or more sub-groups you can use the --filter flag. + +## AnnotationDriver is not a default mapping driver anymore + +In conjunction with the recent changes to Console we realized that the +annotations driver being a default metadata driver lead to lots of glue +code in the console components to detect where entities lie and how to load +them for batch updates like SchemaTool and other commands. However the +annotations driver being a default driver does not really help that much +anyways. + +Therefore we decided to break backwards compability in this issue and drop +the support for Annotations as Default Driver and require our users to +specify the driver explicitly (which allows us to ask for the path to all +entities). + +If you are using the annotations metadata driver as default driver, you +have to add the following lines to your bootstrap code: + + $driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities")); + $config->setMetadataDriverImpl($driverImpl); + +You have to specify the path to your entities as either string of a single +path or array of multiple paths +to your entities. This information will be used by all console commands to +access all entities. + +Xml and Yaml Drivers work as before! + + +## New inversedBy attribute + +It is now *mandatory* that the owning side of a bidirectional association specifies the +'inversedBy' attribute that points to the name of the field on the inverse side that completes +the association. Example: + + [php] + // BEFORE (ALPHA4 AND EARLIER) + class User + { + //... + /** @OneToOne(targetEntity="Address", mappedBy="user") */ + private $address; + //... + } + class Address + { + //... + /** @OneToOne(targetEntity="User") */ + private $user; + //... + } + + // SINCE BETA1 + // User class DOES NOT CHANGE + class Address + { + //... + /** @OneToOne(targetEntity="User", inversedBy="address") */ + private $user; + //... + } + +Thus, the inversedBy attribute is the counterpart to the mappedBy attribute. This change +was necessary to enable some simplifications and further performance improvements. We +apologize for the inconvenience. + +## Default Property for Field Mappings + +The "default" option for database column defaults has been removed. If desired, database column defaults can +be implemented by using the columnDefinition attribute of the @Column annotation (or the approriate XML and YAML equivalents). +Prefer PHP default values, if possible. + +## Selecting Partial Objects + +Querying for partial objects now has a new syntax. The old syntax to query for partial objects +now has a different meaning. This is best illustrated by an example. If you previously +had a DQL query like this: + + [sql] + SELECT u.id, u.name FROM User u + +Since BETA1, simple state field path expressions in the select clause are used to select +object fields as plain scalar values (something that was not possible before). +To achieve the same result as previously (that is, a partial object with only id and name populated) +you need to use the following, explicit syntax: + + [sql] + SELECT PARTIAL u.{id,name} FROM User u + +## XML Mapping Driver + +The 'inheritance-type' attribute changed to take last bit of ClassMetadata constant names, i.e. +NONE, SINGLE_TABLE, INHERITANCE_TYPE_JOINED + +## YAML Mapping Driver + +The way to specify lifecycle callbacks in YAML Mapping driver was changed to allow for multiple callbacks +per event. The Old syntax ways: + + [yaml] + lifecycleCallbacks: + doStuffOnPrePersist: prePersist + doStuffOnPostPersist: postPersist + +The new syntax is: + + [yaml] + lifecycleCallbacks: + prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ] + postPersist: [ doStuffOnPostPersist ] + +## PreUpdate Event Listeners + +Event Listeners listening to the 'preUpdate' event can only affect the primitive values of entity changesets +by using the API on the `PreUpdateEventArgs` instance passed to the preUpdate listener method. Any changes +to the state of the entitys properties won't affect the database UPDATE statement anymore. This gives drastic +performance benefits for the preUpdate event. + +## Collection API + +The Collection interface in the Common package has been updated with some missing methods +that were present only on the default implementation, ArrayCollection. Custom collection +implementations need to be updated to adhere to the updated interface. + +# Upgrade from 2.0-ALPHA3 to 2.0-ALPHA4 + +## CLI Controller changes + +CLI main object changed its name and namespace. Renamed from Doctrine\ORM\Tools\Cli to Doctrine\Common\Cli\CliController. +Doctrine\Common\Cli\CliController now only deals with namespaces. Ready to go, Core, Dbal and Orm are available and you can subscribe new tasks by retrieving the namespace and including new task. Example: + + [php] + $cli->getNamespace('Core')->addTask('my-example', '\MyProject\Tools\Cli\Tasks\MyExampleTask'); + + +## CLI Tasks documentation + +Tasks have implemented a new way to build documentation. Although it is still possible to define the help manually by extending the basicHelp and extendedHelp, they are now optional. +With new required method AbstractTask::buildDocumentation, its implementation defines the TaskDocumentation instance (accessible through AbstractTask::getDocumentation()), basicHelp and extendedHelp are now not necessary to be implemented. + +## Changes in Method Signatures + + * A bunch of Methods on both Doctrine\DBAL\Platforms\AbstractPlatform and Doctrine\DBAL\Schema\AbstractSchemaManager + have changed quite significantly by adopting the new Schema instance objects. + +## Renamed Methods + + * Doctrine\ORM\AbstractQuery::setExpireResultCache() -> expireResultCache() + * Doctrine\ORM\Query::setExpireQueryCache() -> expireQueryCache() + +## SchemaTool Changes + + * "doctrine schema-tool --drop" now always drops the complete database instead of + only those tables defined by the current database model. The previous method had + problems when foreign keys of orphaned tables pointed to tables that were schedulded + for deletion. + * Use "doctrine schema-tool --update" to get a save incremental update for your + database schema without deleting any unused tables, sequences or foreign keys. + * Use "doctrine schema-tool --complete-update" to do a full incremental update of + your schema. +# Upgrade from 2.0-ALPHA2 to 2.0-ALPHA3 + +This section details the changes made to Doctrine 2.0-ALPHA3 to make it easier for you +to upgrade your projects to use this version. + +## CLI Changes + +The $args variable used in the cli-config.php for configuring the Doctrine CLI has been renamed to $globalArguments. + +## Proxy class changes + +You are now required to make supply some minimalist configuration with regards to proxy objects. That involves 2 new configuration options. First, the directory where generated proxy classes should be placed needs to be specified. Secondly, you need to configure the namespace used for proxy classes. The following snippet shows an example: + + [php] + // step 1: configure directory for proxy classes + // $config instanceof Doctrine\ORM\Configuration + $config->setProxyDir('/path/to/myproject/lib/MyProject/Generated/Proxies'); + $config->setProxyNamespace('MyProject\Generated\Proxies'); + +Note that proxy classes behave exactly like any other classes when it comes to class loading. Therefore you need to make sure the proxy classes can be loaded by some class loader. If you place the generated proxy classes in a namespace and directory under your projects class files, like in the example above, it would be sufficient to register the MyProject namespace on a class loader. Since the proxy classes are contained in that namespace and adhere to the standards for class loading, no additional work is required. +Generating the proxy classes into a namespace within your class library is the recommended setup. + +Entities with initialized proxy objects can now be serialized and unserialized properly from within the same application. + +For more details refer to the Configuration section of the manual. + +## Removed allowPartialObjects configuration option + +The allowPartialObjects configuration option together with the `Configuration#getAllowPartialObjects` and `Configuration#setAllowPartialObjects` methods have been removed. +The new behavior is as if the option were set to FALSE all the time, basically disallowing partial objects globally. However, you can still use the `Query::HINT_FORCE_PARTIAL_LOAD` query hint to force a query to return partial objects for optimization purposes. + +## Renamed Methods + +* Doctrine\ORM\Configuration#getCacheDir() to getProxyDir() +* Doctrine\ORM\Configuration#setCacheDir($dir) to setProxyDir($dir) diff --git a/vendor/doctrine/orm/bin/doctrine b/vendor/doctrine/orm/bin/doctrine new file mode 100755 index 0000000..c359ca7 --- /dev/null +++ b/vendor/doctrine/orm/bin/doctrine @@ -0,0 +1,4 @@ +#!/usr/bin/env php +. + */ + +require_once 'Doctrine/Common/ClassLoader.php'; + +$classLoader = new \Doctrine\Common\ClassLoader('Doctrine'); +$classLoader->register(); + +$classLoader = new \Doctrine\Common\ClassLoader('Symfony'); +$classLoader->register(); + +$configFile = getcwd() . DIRECTORY_SEPARATOR . 'cli-config.php'; + +$helperSet = null; +if (file_exists($configFile)) { + if ( ! is_readable($configFile)) { + trigger_error( + 'Configuration file [' . $configFile . '] does not have read permission.', E_ERROR + ); + } + + require $configFile; + + foreach ($GLOBALS as $helperSetCandidate) { + if ($helperSetCandidate instanceof \Symfony\Component\Console\Helper\HelperSet) { + $helperSet = $helperSetCandidate; + break; + } + } +} + +$helperSet = ($helperSet) ?: new \Symfony\Component\Console\Helper\HelperSet(); + +\Doctrine\ORM\Tools\Console\ConsoleRunner::run($helperSet); diff --git a/vendor/doctrine/orm/bin/doctrine.bat b/vendor/doctrine/orm/bin/doctrine.bat new file mode 100644 index 0000000..a9e8cee --- /dev/null +++ b/vendor/doctrine/orm/bin/doctrine.bat @@ -0,0 +1,9 @@ +@echo off + +if "%PHPBIN%" == "" set PHPBIN=@php_bin@ +if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH +GOTO RUN +:USE_PEAR_PATH +set PHPBIN=%PHP_PEAR_PHP_BIN% +:RUN +"%PHPBIN%" "@bin_dir@\doctrine" %* diff --git a/vendor/doctrine/orm/bin/doctrine.php b/vendor/doctrine/orm/bin/doctrine.php new file mode 100755 index 0000000..81edf29 --- /dev/null +++ b/vendor/doctrine/orm/bin/doctrine.php @@ -0,0 +1,43 @@ +. + */ + +(@include_once __DIR__ . '/../vendor/autoload.php') || @include_once __DIR__ . '/../../../autoload.php'; +$configFile = getcwd() . DIRECTORY_SEPARATOR . 'cli-config.php'; + +$helperSet = null; +if (file_exists($configFile)) { + if ( ! is_readable($configFile)) { + trigger_error( + 'Configuration file [' . $configFile . '] does not have read permission.', E_ERROR + ); + } + + require $configFile; + + foreach ($GLOBALS as $helperSetCandidate) { + if ($helperSetCandidate instanceof \Symfony\Component\Console\Helper\HelperSet) { + $helperSet = $helperSetCandidate; + break; + } + } +} + +$helperSet = ($helperSet) ?: new \Symfony\Component\Console\Helper\HelperSet(); + +\Doctrine\ORM\Tools\Console\ConsoleRunner::run($helperSet); diff --git a/vendor/doctrine/orm/build.properties b/vendor/doctrine/orm/build.properties new file mode 100644 index 0000000..37c834c --- /dev/null +++ b/vendor/doctrine/orm/build.properties @@ -0,0 +1,11 @@ +# Project Name +project.name=DoctrineORM + +# Dependency minimum versions +dependencies.common=2.2.0beta1 +dependencies.dbal=2.2.0beta1 +dependencies.sfconsole=2.0.0 + +# Version class and file +project.version_class = Doctrine\ORM\Version +project.version_file = lib/Doctrine/ORM/Version.php diff --git a/vendor/doctrine/orm/build.properties.dev b/vendor/doctrine/orm/build.properties.dev new file mode 100644 index 0000000..20e91dc --- /dev/null +++ b/vendor/doctrine/orm/build.properties.dev @@ -0,0 +1,16 @@ +version=2.0.0BETA2 +dependencies.common=2.0.0BETA4 +dependencies.dbal=2.0.0BETA4 +stability=beta +build.dir=build +dist.dir=dist +report.dir=reports +log.archive.dir=logs +project.pirum_dir= +project.download_dir= +project.xsd_dir= +test.phpunit_configuration_file= +test.phpunit_generate_coverage=0 +test.pmd_reports=0 +test.pdepend_exec= +test.phpmd_exec= \ No newline at end of file diff --git a/vendor/doctrine/orm/build.xml b/vendor/doctrine/orm/build.xml new file mode 100644 index 0000000..890ed05 --- /dev/null +++ b/vendor/doctrine/orm/build.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DoctrineORM + Doctrine Object Relational Mapper + pear.doctrine-project.org + The Doctrine ORM package is the primary package containing the object relational mapper. + + + + + LGPL + + + - + + + + + + + + + script + Doctrine/Common/ + Doctrine/DBAL/ + Symfony/Component/Yaml/ + Symfony/Component/Console/ + + + + + + + + + + diff --git a/vendor/doctrine/orm/composer.json b/vendor/doctrine/orm/composer.json new file mode 100644 index 0000000..b22c305 --- /dev/null +++ b/vendor/doctrine/orm/composer.json @@ -0,0 +1,32 @@ +{ + "name": "doctrine/orm", + "type": "library","version":"2.3.0", + "description": "Object-Relational-Mapper for PHP", + "keywords": ["orm", "database"], + "homepage": "http://www.doctrine-project.org", + "license": "MIT", + "authors": [ + {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, + {"name": "Roman Borschel", "email": "roman@code-factory.org"}, + {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, + {"name": "Jonathan Wage", "email": "jonwage@gmail.com"} + ], + "require": { + "php": ">=5.3.2", + "ext-pdo": "*", + "doctrine/dbal": "2.3.*", + "symfony/console": "2.*" + }, + "suggest": { + "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + }, + "autoload": { + "psr-0": { "Doctrine\\ORM": "lib/" } + }, + "bin": ["bin/doctrine", "bin/doctrine.php"], + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + } +} diff --git a/vendor/doctrine/orm/doctrine-mapping.xsd b/vendor/doctrine/orm/doctrine-mapping.xsd new file mode 100644 index 0000000..e8b2e26 --- /dev/null +++ b/vendor/doctrine/orm/doctrine-mapping.xsd @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php b/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php new file mode 100644 index 0000000..d5759e6 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/AbstractQuery.php @@ -0,0 +1,825 @@ +. + */ + +namespace Doctrine\ORM; + +use Doctrine\Common\Util\ClassUtils; +use Doctrine\Common\Collections\ArrayCollection; + +use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Cache\QueryCacheProfile; + +use Doctrine\ORM\Query\QueryException; + +/** + * Base contract for ORM queries. Base class for Query and NativeQuery. + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Konsta Vesterinen + */ +abstract class AbstractQuery +{ + /* Hydration mode constants */ + /** + * Hydrates an object graph. This is the default behavior. + */ + const HYDRATE_OBJECT = 1; + /** + * Hydrates an array graph. + */ + const HYDRATE_ARRAY = 2; + /** + * Hydrates a flat, rectangular result set with scalar values. + */ + const HYDRATE_SCALAR = 3; + /** + * Hydrates a single scalar value. + */ + const HYDRATE_SINGLE_SCALAR = 4; + + /** + * Very simple object hydrator (optimized for performance). + */ + const HYDRATE_SIMPLEOBJECT = 5; + + /** + * @var \Doctrine\Common\Collections\ArrayCollection The parameter map of this query. + */ + protected $parameters; + + /** + * @var ResultSetMapping The user-specified ResultSetMapping to use. + */ + protected $_resultSetMapping; + + /** + * @var \Doctrine\ORM\EntityManager The entity manager used by this query object. + */ + protected $_em; + + /** + * @var array The map of query hints. + */ + protected $_hints = array(); + + /** + * @var integer The hydration mode. + */ + protected $_hydrationMode = self::HYDRATE_OBJECT; + + /** + * @param \Doctrine\DBAL\Cache\QueryCacheProfile + */ + protected $_queryCacheProfile; + + /** + * @var boolean Boolean value that indicates whether or not expire the result cache. + */ + protected $_expireResultCache = false; + + /** + * @param \Doctrine\DBAL\Cache\QueryCacheProfile + */ + protected $_hydrationCacheProfile; + + /** + * Initializes a new instance of a class derived from AbstractQuery. + * + * @param \Doctrine\ORM\EntityManager $entityManager + */ + public function __construct(EntityManager $em) + { + $this->_em = $em; + $this->parameters = new ArrayCollection(); + } + + /** + * Gets the SQL query that corresponds to this query object. + * The returned SQL syntax depends on the connection driver that is used + * by this query object at the time of this method call. + * + * @return string SQL query + */ + abstract public function getSQL(); + + /** + * Retrieves the associated EntityManager of this Query instance. + * + * @return \Doctrine\ORM\EntityManager + */ + public function getEntityManager() + { + return $this->_em; + } + + /** + * Frees the resources used by the query object. + * + * Resets Parameters, Parameter Types and Query Hints. + * + * @return void + */ + public function free() + { + $this->parameters = new ArrayCollection(); + + $this->_hints = array(); + } + + /** + * Get all defined parameters. + * + * @return \Doctrine\Common\Collections\ArrayCollection The defined query parameters. + */ + public function getParameters() + { + return $this->parameters; + } + + /** + * Gets a query parameter. + * + * @param mixed $key The key (index or name) of the bound parameter. + * + * @return mixed The value of the bound parameter. + */ + public function getParameter($key) + { + $filteredParameters = $this->parameters->filter( + function ($parameter) use ($key) + { + // Must not be identical because of string to integer conversion + return ($key == $parameter->getName()); + } + ); + + return count($filteredParameters) ? $filteredParameters->first() : null; + } + + /** + * Sets a collection of query parameters. + * + * @param \Doctrine\Common\Collections\ArrayCollection|array $parameters + * + * @return \Doctrine\ORM\AbstractQuery This query instance. + */ + public function setParameters($parameters) + { + // BC compatibility with 2.3- + if (is_array($parameters)) { + $parameterCollection = new ArrayCollection(); + + foreach ($parameters as $key => $value) { + $parameter = new Query\Parameter($key, $value); + + $parameterCollection->add($parameter); + } + + $parameters = $parameterCollection; + } + + $this->parameters = $parameters; + + return $this; + } + + /** + * Sets a query parameter. + * + * @param string|integer $key The parameter position or name. + * @param mixed $value The parameter value. + * @param string $type The parameter type. If specified, the given value will be run through + * the type conversion of this type. This is usually not needed for + * strings and numeric types. + * + * @return \Doctrine\ORM\AbstractQuery This query instance. + */ + public function setParameter($key, $value, $type = null) + { + $filteredParameters = $this->parameters->filter( + function ($parameter) use ($key) + { + // Must not be identical because of string to integer conversion + return ($key == $parameter->getName()); + } + ); + + if (count($filteredParameters)) { + $parameter = $filteredParameters->first(); + $parameter->setValue($value, $type); + + return $this; + } + + $parameter = new Query\Parameter($key, $value, $type); + + $this->parameters->add($parameter); + + return $this; + } + + /** + * Process an individual parameter value + * + * @param mixed $value + * @return array + */ + public function processParameterValue($value) + { + switch (true) { + case is_array($value): + foreach ($value as $key => $paramValue) { + $paramValue = $this->processParameterValue($paramValue); + $value[$key] = is_array($paramValue) ? $paramValue[key($paramValue)] : $paramValue; + } + + return $value; + + case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value)): + return $this->convertObjectParameterToScalarValue($value); + + default: + return $value; + } + } + + private function convertObjectParameterToScalarValue($value) + { + $class = $this->_em->getClassMetadata(get_class($value)); + + if ($class->isIdentifierComposite) { + throw new \InvalidArgumentException( + "Binding an entity with a composite primary key to a query is not supported. " . + "You should split the parameter into the explicit fields and bind them seperately." + ); + } + + $values = ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) + ? $this->_em->getUnitOfWork()->getEntityIdentifier($value) + : $class->getIdentifierValues($value); + + $value = $values[$class->getSingleIdentifierFieldName()]; + + if ( ! $value) { + throw new \InvalidArgumentException( + "Binding entities to query parameters only allowed for entities that have an identifier." + ); + } + + return $value; + } + + /** + * Sets the ResultSetMapping that should be used for hydration. + * + * @param ResultSetMapping $rsm + * @return \Doctrine\ORM\AbstractQuery + */ + public function setResultSetMapping(Query\ResultSetMapping $rsm) + { + $this->_resultSetMapping = $rsm; + + return $this; + } + + /** + * Set a cache profile for hydration caching. + * + * If no result cache driver is set in the QueryCacheProfile, the default + * result cache driver is used from the configuration. + * + * Important: Hydration caching does NOT register entities in the + * UnitOfWork when retrieved from the cache. Never use result cached + * entities for requests that also flush the EntityManager. If you want + * some form of caching with UnitOfWork registration you should use + * {@see AbstractQuery::setResultCacheProfile()}. + * + * @example + * $lifetime = 100; + * $resultKey = "abc"; + * $query->setHydrationCacheProfile(new QueryCacheProfile()); + * $query->setHydrationCacheProfile(new QueryCacheProfile($lifetime, $resultKey)); + * + * @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile + * @return \Doctrine\ORM\AbstractQuery + */ + public function setHydrationCacheProfile(QueryCacheProfile $profile = null) + { + if ( ! $profile->getResultCacheDriver()) { + $resultCacheDriver = $this->_em->getConfiguration()->getHydrationCacheImpl(); + $profile = $profile->setResultCacheDriver($resultCacheDriver); + } + + $this->_hydrationCacheProfile = $profile; + + return $this; + } + + /** + * @return \Doctrine\DBAL\Cache\QueryCacheProfile + */ + public function getHydrationCacheProfile() + { + return $this->_hydrationCacheProfile; + } + + /** + * Set a cache profile for the result cache. + * + * If no result cache driver is set in the QueryCacheProfile, the default + * result cache driver is used from the configuration. + * + * @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile + * @return \Doctrine\ORM\AbstractQuery + */ + public function setResultCacheProfile(QueryCacheProfile $profile = null) + { + if ( ! $profile->getResultCacheDriver()) { + $resultCacheDriver = $this->_em->getConfiguration()->getResultCacheImpl(); + $profile = $profile->setResultCacheDriver($resultCacheDriver); + } + + $this->_queryCacheProfile = $profile; + + return $this; + } + + /** + * Defines a cache driver to be used for caching result sets and implictly enables caching. + * + * @param \Doctrine\Common\Cache\Cache $driver Cache driver + * @return \Doctrine\ORM\AbstractQuery + */ + public function setResultCacheDriver($resultCacheDriver = null) + { + if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) { + throw ORMException::invalidResultCacheDriver(); + } + + $this->_queryCacheProfile = $this->_queryCacheProfile + ? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver) + : new QueryCacheProfile(0, null, $resultCacheDriver); + + return $this; + } + + /** + * Returns the cache driver used for caching result sets. + * + * @deprecated + * @return \Doctrine\Common\Cache\Cache Cache driver + */ + public function getResultCacheDriver() + { + if ($this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) { + return $this->_queryCacheProfile->getResultCacheDriver(); + } + + return $this->_em->getConfiguration()->getResultCacheImpl(); + } + + /** + * Set whether or not to cache the results of this query and if so, for + * how long and which ID to use for the cache entry. + * + * @param boolean $bool + * @param integer $lifetime + * @param string $resultCacheId + * @return \Doctrine\ORM\AbstractQuery This query instance. + */ + public function useResultCache($bool, $lifetime = null, $resultCacheId = null) + { + if ($bool) { + $this->setResultCacheLifetime($lifetime); + $this->setResultCacheId($resultCacheId); + + return $this; + } + + $this->_queryCacheProfile = null; + + return $this; + } + + /** + * Defines how long the result cache will be active before expire. + * + * @param integer $lifetime How long the cache entry is valid. + * @return \Doctrine\ORM\AbstractQuery This query instance. + */ + public function setResultCacheLifetime($lifetime) + { + $lifetime = ($lifetime !== null) ? (int) $lifetime : 0; + + $this->_queryCacheProfile = $this->_queryCacheProfile + ? $this->_queryCacheProfile->setLifetime($lifetime) + : new QueryCacheProfile($lifetime, null, $this->_em->getConfiguration()->getResultCacheImpl()); + + return $this; + } + + /** + * Retrieves the lifetime of resultset cache. + * + * @deprecated + * @return integer + */ + public function getResultCacheLifetime() + { + return $this->_queryCacheProfile ? $this->_queryCacheProfile->getLifetime() : 0; + } + + /** + * Defines if the result cache is active or not. + * + * @param boolean $expire Whether or not to force resultset cache expiration. + * @return \Doctrine\ORM\AbstractQuery This query instance. + */ + public function expireResultCache($expire = true) + { + $this->_expireResultCache = $expire; + + return $this; + } + + /** + * Retrieves if the resultset cache is active or not. + * + * @return boolean + */ + public function getExpireResultCache() + { + return $this->_expireResultCache; + } + + /** + * @return QueryCacheProfile + */ + public function getQueryCacheProfile() + { + return $this->_queryCacheProfile; + } + + /** + * Change the default fetch mode of an association for this query. + * + * $fetchMode can be one of ClassMetadata::FETCH_EAGER or ClassMetadata::FETCH_LAZY + * + * @param string $class + * @param string $assocName + * @param int $fetchMode + * @return AbstractQuery + */ + public function setFetchMode($class, $assocName, $fetchMode) + { + if ($fetchMode !== Mapping\ClassMetadata::FETCH_EAGER) { + $fetchMode = Mapping\ClassMetadata::FETCH_LAZY; + } + + $this->_hints['fetchMode'][$class][$assocName] = $fetchMode; + + return $this; + } + + /** + * Defines the processing mode to be used during hydration / result set transformation. + * + * @param integer $hydrationMode Doctrine processing mode to be used during hydration process. + * One of the Query::HYDRATE_* constants. + * @return \Doctrine\ORM\AbstractQuery This query instance. + */ + public function setHydrationMode($hydrationMode) + { + $this->_hydrationMode = $hydrationMode; + + return $this; + } + + /** + * Gets the hydration mode currently used by the query. + * + * @return integer + */ + public function getHydrationMode() + { + return $this->_hydrationMode; + } + + /** + * Gets the list of results for the query. + * + * Alias for execute(null, $hydrationMode = HYDRATE_OBJECT). + * + * @return array + */ + public function getResult($hydrationMode = self::HYDRATE_OBJECT) + { + return $this->execute(null, $hydrationMode); + } + + /** + * Gets the array of results for the query. + * + * Alias for execute(null, HYDRATE_ARRAY). + * + * @return array + */ + public function getArrayResult() + { + return $this->execute(null, self::HYDRATE_ARRAY); + } + + /** + * Gets the scalar results for the query. + * + * Alias for execute(null, HYDRATE_SCALAR). + * + * @return array + */ + public function getScalarResult() + { + return $this->execute(null, self::HYDRATE_SCALAR); + } + + /** + * Get exactly one result or null. + * + * @throws NonUniqueResultException + * @param int $hydrationMode + * @return mixed + */ + public function getOneOrNullResult($hydrationMode = null) + { + $result = $this->execute(null, $hydrationMode); + + if ($this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) { + return null; + } + + if ( ! is_array($result)) { + return $result; + } + + if (count($result) > 1) { + throw new NonUniqueResultException; + } + + return array_shift($result); + } + + /** + * Gets the single result of the query. + * + * Enforces the presence as well as the uniqueness of the result. + * + * If the result is not unique, a NonUniqueResultException is thrown. + * If there is no result, a NoResultException is thrown. + * + * @param integer $hydrationMode + * @return mixed + * @throws NonUniqueResultException If the query result is not unique. + * @throws NoResultException If the query returned no result. + */ + public function getSingleResult($hydrationMode = null) + { + $result = $this->execute(null, $hydrationMode); + + if ($this->_hydrationMode !== self::HYDRATE_SINGLE_SCALAR && ! $result) { + throw new NoResultException; + } + + if ( ! is_array($result)) { + return $result; + } + + if (count($result) > 1) { + throw new NonUniqueResultException; + } + + return array_shift($result); + } + + /** + * Gets the single scalar result of the query. + * + * Alias for getSingleResult(HYDRATE_SINGLE_SCALAR). + * + * @return mixed + * @throws QueryException If the query result is not unique. + */ + public function getSingleScalarResult() + { + return $this->getSingleResult(self::HYDRATE_SINGLE_SCALAR); + } + + /** + * Sets a query hint. If the hint name is not recognized, it is silently ignored. + * + * @param string $name The name of the hint. + * @param mixed $value The value of the hint. + * @return \Doctrine\ORM\AbstractQuery + */ + public function setHint($name, $value) + { + $this->_hints[$name] = $value; + + return $this; + } + + /** + * Gets the value of a query hint. If the hint name is not recognized, FALSE is returned. + * + * @param string $name The name of the hint. + * @return mixed The value of the hint or FALSE, if the hint name is not recognized. + */ + public function getHint($name) + { + return isset($this->_hints[$name]) ? $this->_hints[$name] : false; + } + + /** + * Return the key value map of query hints that are currently set. + * + * @return array + */ + public function getHints() + { + return $this->_hints; + } + + /** + * Executes the query and returns an IterableResult that can be used to incrementally + * iterate over the result. + * + * @param \Doctrine\Common\Collections\ArrayCollection|array $parameters The query parameters. + * @param integer $hydrationMode The hydration mode to use. + * @return \Doctrine\ORM\Internal\Hydration\IterableResult + */ + public function iterate($parameters = null, $hydrationMode = null) + { + if ($hydrationMode !== null) { + $this->setHydrationMode($hydrationMode); + } + + if ( ! empty($parameters)) { + $this->setParameters($parameters); + } + + $stmt = $this->_doExecute(); + + return $this->_em->newHydrator($this->_hydrationMode)->iterate( + $stmt, $this->_resultSetMapping, $this->_hints + ); + } + + /** + * Executes the query. + * + * @param \Doctrine\Common\Collections\ArrayCollection|array $parameters Query parameters. + * @param integer $hydrationMode Processing mode to be used during the hydration process. + * @return mixed + */ + public function execute($parameters = null, $hydrationMode = null) + { + if ($hydrationMode !== null) { + $this->setHydrationMode($hydrationMode); + } + + if ( ! empty($parameters)) { + $this->setParameters($parameters); + } + + $setCacheEntry = function() {}; + + if ($this->_hydrationCacheProfile !== null) { + list($cacheKey, $realCacheKey) = $this->getHydrationCacheId(); + + $queryCacheProfile = $this->getHydrationCacheProfile(); + $cache = $queryCacheProfile->getResultCacheDriver(); + $result = $cache->fetch($cacheKey); + + if (isset($result[$realCacheKey])) { + return $result[$realCacheKey]; + } + + if ( ! $result) { + $result = array(); + } + + $setCacheEntry = function($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) { + $result[$realCacheKey] = $data; + + $cache->save($cacheKey, $result, $queryCacheProfile->getLifetime()); + }; + } + + $stmt = $this->_doExecute(); + + if (is_numeric($stmt)) { + $setCacheEntry($stmt); + + return $stmt; + } + + $data = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll( + $stmt, $this->_resultSetMapping, $this->_hints + ); + + $setCacheEntry($data); + + return $data; + } + + /** + * Get the result cache id to use to store the result set cache entry. + * Will return the configured id if it exists otherwise a hash will be + * automatically generated for you. + * + * @return array ($key, $hash) + */ + protected function getHydrationCacheId() + { + $parameters = array(); + + foreach ($this->getParameters() as $parameter) { + $parameters[$parameter->getName()] = $this->processParameterValue($parameter->getValue()); + } + + $sql = $this->getSQL(); + $queryCacheProfile = $this->getHydrationCacheProfile(); + $hints = $this->getHints(); + $hints['hydrationMode'] = $this->getHydrationMode(); + + ksort($hints); + + return $queryCacheProfile->generateCacheKeys($sql, $parameters, $hints); + } + + /** + * Set the result cache id to use to store the result set cache entry. + * If this is not explicitly set by the developer then a hash is automatically + * generated for you. + * + * @param string $id + * @return \Doctrine\ORM\AbstractQuery This query instance. + */ + public function setResultCacheId($id) + { + $this->_queryCacheProfile = $this->_queryCacheProfile + ? $this->_queryCacheProfile->setCacheKey($id) + : new QueryCacheProfile(0, $id, $this->_em->getConfiguration()->getResultCacheImpl()); + + return $this; + } + + /** + * Get the result cache id to use to store the result set cache entry if set. + * + * @deprecated + * @return string + */ + public function getResultCacheId() + { + return $this->_queryCacheProfile ? $this->_queryCacheProfile->getCacheKey() : null; + } + + /** + * Executes the query and returns a the resulting Statement object. + * + * @return \Doctrine\DBAL\Driver\Statement The executed database statement that holds the results. + */ + abstract protected function _doExecute(); + + /** + * Cleanup Query resource when clone is called. + * + * @return void + */ + public function __clone() + { + $this->parameters = new ArrayCollection(); + + $this->_hints = array(); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Configuration.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Configuration.php new file mode 100644 index 0000000..a835488 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Configuration.php @@ -0,0 +1,683 @@ +. + */ + +namespace Doctrine\ORM; + +use Doctrine\Common\Cache\Cache, + Doctrine\Common\Cache\ArrayCache, + Doctrine\Common\Annotations\AnnotationRegistry, + Doctrine\Common\Annotations\AnnotationReader, + Doctrine\Common\Persistence\Mapping\Driver\MappingDriver, + Doctrine\ORM\Mapping\Driver\AnnotationDriver, + Doctrine\ORM\Mapping\QuoteStrategy, + Doctrine\ORM\Mapping\DefaultQuoteStrategy, + Doctrine\ORM\Mapping\NamingStrategy, + Doctrine\ORM\Mapping\DefaultNamingStrategy, + Doctrine\Common\Annotations\SimpleAnnotationReader, + Doctrine\Common\Annotations\CachedReader; + +/** + * Configuration container for all configuration options of Doctrine. + * It combines all configuration options from DBAL & ORM. + * + * @since 2.0 + * @internal When adding a new configuration option just write a getter/setter pair. + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Configuration extends \Doctrine\DBAL\Configuration +{ + /** + * Sets the directory where Doctrine generates any necessary proxy class files. + * + * @param string $dir + */ + public function setProxyDir($dir) + { + $this->_attributes['proxyDir'] = $dir; + } + + /** + * Gets the directory where Doctrine generates any necessary proxy class files. + * + * @return string + */ + public function getProxyDir() + { + return isset($this->_attributes['proxyDir']) + ? $this->_attributes['proxyDir'] + : null; + } + + /** + * Gets a boolean flag that indicates whether proxy classes should always be regenerated + * during each script execution. + * + * @return boolean + */ + public function getAutoGenerateProxyClasses() + { + return isset($this->_attributes['autoGenerateProxyClasses']) + ? $this->_attributes['autoGenerateProxyClasses'] + : true; + } + + /** + * Sets a boolean flag that indicates whether proxy classes should always be regenerated + * during each script execution. + * + * @param boolean $bool + */ + public function setAutoGenerateProxyClasses($bool) + { + $this->_attributes['autoGenerateProxyClasses'] = $bool; + } + + /** + * Gets the namespace where proxy classes reside. + * + * @return string + */ + public function getProxyNamespace() + { + return isset($this->_attributes['proxyNamespace']) + ? $this->_attributes['proxyNamespace'] + : null; + } + + /** + * Sets the namespace where proxy classes reside. + * + * @param string $ns + */ + public function setProxyNamespace($ns) + { + $this->_attributes['proxyNamespace'] = $ns; + } + + /** + * Sets the cache driver implementation that is used for metadata caching. + * + * @param MappingDriver $driverImpl + * @todo Force parameter to be a Closure to ensure lazy evaluation + * (as soon as a metadata cache is in effect, the driver never needs to initialize). + */ + public function setMetadataDriverImpl(MappingDriver $driverImpl) + { + $this->_attributes['metadataDriverImpl'] = $driverImpl; + } + + /** + * Add a new default annotation driver with a correctly configured annotation reader. If $useSimpleAnnotationReader + * is true, the notation `@Entity` will work, otherwise, the notation `@ORM\Entity` will be supported. + * + * @param array $paths + * @param bool $useSimpleAnnotationReader + * @return AnnotationDriver + */ + public function newDefaultAnnotationDriver($paths = array(), $useSimpleAnnotationReader = true) + { + AnnotationRegistry::registerFile(__DIR__ . '/Mapping/Driver/DoctrineAnnotations.php'); + + if ($useSimpleAnnotationReader) { + // Register the ORM Annotations in the AnnotationRegistry + $reader = new SimpleAnnotationReader(); + $reader->addNamespace('Doctrine\ORM\Mapping'); + $cachedReader = new CachedReader($reader, new ArrayCache()); + + return new AnnotationDriver($cachedReader, (array) $paths); + } + + return new AnnotationDriver( + new CachedReader(new AnnotationReader(), new ArrayCache()), + (array) $paths + ); + } + + /** + * Adds a namespace under a certain alias. + * + * @param string $alias + * @param string $namespace + */ + public function addEntityNamespace($alias, $namespace) + { + $this->_attributes['entityNamespaces'][$alias] = $namespace; + } + + /** + * Resolves a registered namespace alias to the full namespace. + * + * @param string $entityNamespaceAlias + * @throws ORMException + * @return string + */ + public function getEntityNamespace($entityNamespaceAlias) + { + if ( ! isset($this->_attributes['entityNamespaces'][$entityNamespaceAlias])) { + throw ORMException::unknownEntityNamespace($entityNamespaceAlias); + } + + return trim($this->_attributes['entityNamespaces'][$entityNamespaceAlias], '\\'); + } + + /** + * Set the entity alias map + * + * @param array $entityNamespaces + */ + public function setEntityNamespaces(array $entityNamespaces) + { + $this->_attributes['entityNamespaces'] = $entityNamespaces; + } + + /** + * Retrieves the list of registered entity namespace aliases. + * + * @return array + */ + public function getEntityNamespaces() + { + return $this->_attributes['entityNamespaces']; + } + + /** + * Gets the cache driver implementation that is used for the mapping metadata. + * + * @throws ORMException + * @return MappingDriver + */ + public function getMetadataDriverImpl() + { + return isset($this->_attributes['metadataDriverImpl']) + ? $this->_attributes['metadataDriverImpl'] + : null; + } + + /** + * Gets the cache driver implementation that is used for the query cache (SQL cache). + * + * @return \Doctrine\Common\Cache\Cache + */ + public function getQueryCacheImpl() + { + return isset($this->_attributes['queryCacheImpl']) + ? $this->_attributes['queryCacheImpl'] + : null; + } + + /** + * Sets the cache driver implementation that is used for the query cache (SQL cache). + * + * @param \Doctrine\Common\Cache\Cache $cacheImpl + */ + public function setQueryCacheImpl(Cache $cacheImpl) + { + $this->_attributes['queryCacheImpl'] = $cacheImpl; + } + + /** + * Gets the cache driver implementation that is used for the hydration cache (SQL cache). + * + * @return \Doctrine\Common\Cache\Cache + */ + public function getHydrationCacheImpl() + { + return isset($this->_attributes['hydrationCacheImpl']) + ? $this->_attributes['hydrationCacheImpl'] + : null; + } + + /** + * Sets the cache driver implementation that is used for the hydration cache (SQL cache). + * + * @param \Doctrine\Common\Cache\Cache $cacheImpl + */ + public function setHydrationCacheImpl(Cache $cacheImpl) + { + $this->_attributes['hydrationCacheImpl'] = $cacheImpl; + } + + /** + * Gets the cache driver implementation that is used for metadata caching. + * + * @return \Doctrine\Common\Cache\Cache + */ + public function getMetadataCacheImpl() + { + return isset($this->_attributes['metadataCacheImpl']) + ? $this->_attributes['metadataCacheImpl'] + : null; + } + + /** + * Sets the cache driver implementation that is used for metadata caching. + * + * @param \Doctrine\Common\Cache\Cache $cacheImpl + */ + public function setMetadataCacheImpl(Cache $cacheImpl) + { + $this->_attributes['metadataCacheImpl'] = $cacheImpl; + } + + /** + * Adds a named DQL query to the configuration. + * + * @param string $name The name of the query. + * @param string $dql The DQL query string. + */ + public function addNamedQuery($name, $dql) + { + $this->_attributes['namedQueries'][$name] = $dql; + } + + /** + * Gets a previously registered named DQL query. + * + * @param string $name The name of the query. + * @throws ORMException + * @return string The DQL query. + */ + public function getNamedQuery($name) + { + if ( ! isset($this->_attributes['namedQueries'][$name])) { + throw ORMException::namedQueryNotFound($name); + } + + return $this->_attributes['namedQueries'][$name]; + } + + /** + * Adds a named native query to the configuration. + * + * @param string $name The name of the query. + * @param string $sql The native SQL query string. + * @param Query\ResultSetMapping $rsm The ResultSetMapping used for the results of the SQL query. + */ + public function addNamedNativeQuery($name, $sql, Query\ResultSetMapping $rsm) + { + $this->_attributes['namedNativeQueries'][$name] = array($sql, $rsm); + } + + /** + * Gets the components of a previously registered named native query. + * + * @param string $name The name of the query. + * @throws ORMException + * @return array A tuple with the first element being the SQL string and the second + * element being the ResultSetMapping. + */ + public function getNamedNativeQuery($name) + { + if ( ! isset($this->_attributes['namedNativeQueries'][$name])) { + throw ORMException::namedNativeQueryNotFound($name); + } + + return $this->_attributes['namedNativeQueries'][$name]; + } + + /** + * Ensures that this Configuration instance contains settings that are + * suitable for a production environment. + * + * @throws ORMException If a configuration setting has a value that is not + * suitable for a production environment. + */ + public function ensureProductionSettings() + { + if ( ! $this->getQueryCacheImpl()) { + throw ORMException::queryCacheNotConfigured(); + } + + if ( ! $this->getMetadataCacheImpl()) { + throw ORMException::metadataCacheNotConfigured(); + } + + if ($this->getAutoGenerateProxyClasses()) { + throw ORMException::proxyClassesAlwaysRegenerating(); + } + } + + /** + * Registers a custom DQL function that produces a string value. + * Such a function can then be used in any DQL statement in any place where string + * functions are allowed. + * + * DQL function names are case-insensitive. + * + * @param string $name + * @param string $className + * @throws ORMException + */ + public function addCustomStringFunction($name, $className) + { + if (Query\Parser::isInternalFunction($name)) { + throw ORMException::overwriteInternalDQLFunctionNotAllowed($name); + } + + $this->_attributes['customStringFunctions'][strtolower($name)] = $className; + } + + /** + * Gets the implementation class name of a registered custom string DQL function. + * + * @param string $name + * @return string + */ + public function getCustomStringFunction($name) + { + $name = strtolower($name); + + return isset($this->_attributes['customStringFunctions'][$name]) + ? $this->_attributes['customStringFunctions'][$name] + : null; + } + + /** + * Sets a map of custom DQL string functions. + * + * Keys must be function names and values the FQCN of the implementing class. + * The function names will be case-insensitive in DQL. + * + * Any previously added string functions are discarded. + * + * @param array $functions The map of custom DQL string functions. + */ + public function setCustomStringFunctions(array $functions) + { + foreach ($functions as $name => $className) { + $this->addCustomStringFunction($name, $className); + } + } + + /** + * Registers a custom DQL function that produces a numeric value. + * Such a function can then be used in any DQL statement in any place where numeric + * functions are allowed. + * + * DQL function names are case-insensitive. + * + * @param string $name + * @param string $className + * @throws ORMException + */ + public function addCustomNumericFunction($name, $className) + { + if (Query\Parser::isInternalFunction($name)) { + throw ORMException::overwriteInternalDQLFunctionNotAllowed($name); + } + + $this->_attributes['customNumericFunctions'][strtolower($name)] = $className; + } + + /** + * Gets the implementation class name of a registered custom numeric DQL function. + * + * @param string $name + * @return string + */ + public function getCustomNumericFunction($name) + { + $name = strtolower($name); + + return isset($this->_attributes['customNumericFunctions'][$name]) + ? $this->_attributes['customNumericFunctions'][$name] + : null; + } + + /** + * Sets a map of custom DQL numeric functions. + * + * Keys must be function names and values the FQCN of the implementing class. + * The function names will be case-insensitive in DQL. + * + * Any previously added numeric functions are discarded. + * + * @param array $functions The map of custom DQL numeric functions. + */ + public function setCustomNumericFunctions(array $functions) + { + foreach ($functions as $name => $className) { + $this->addCustomNumericFunction($name, $className); + } + } + + /** + * Registers a custom DQL function that produces a date/time value. + * Such a function can then be used in any DQL statement in any place where date/time + * functions are allowed. + * + * DQL function names are case-insensitive. + * + * @param string $name + * @param string $className + * @throws ORMException + */ + public function addCustomDatetimeFunction($name, $className) + { + if (Query\Parser::isInternalFunction($name)) { + throw ORMException::overwriteInternalDQLFunctionNotAllowed($name); + } + + $this->_attributes['customDatetimeFunctions'][strtolower($name)] = $className; + } + + /** + * Gets the implementation class name of a registered custom date/time DQL function. + * + * @param string $name + * @return string + */ + public function getCustomDatetimeFunction($name) + { + $name = strtolower($name); + + return isset($this->_attributes['customDatetimeFunctions'][$name]) + ? $this->_attributes['customDatetimeFunctions'][$name] + : null; + } + + /** + * Sets a map of custom DQL date/time functions. + * + * Keys must be function names and values the FQCN of the implementing class. + * The function names will be case-insensitive in DQL. + * + * Any previously added date/time functions are discarded. + * + * @param array $functions The map of custom DQL date/time functions. + */ + public function setCustomDatetimeFunctions(array $functions) + { + foreach ($functions as $name => $className) { + $this->addCustomDatetimeFunction($name, $className); + } + } + + /** + * Set the custom hydrator modes in one pass. + * + * @param array An array of ($modeName => $hydrator) + */ + public function setCustomHydrationModes($modes) + { + $this->_attributes['customHydrationModes'] = array(); + + foreach ($modes as $modeName => $hydrator) { + $this->addCustomHydrationMode($modeName, $hydrator); + } + } + + /** + * Get the hydrator class for the given hydration mode name. + * + * @param string $modeName The hydration mode name. + * @return string $hydrator The hydrator class name. + */ + public function getCustomHydrationMode($modeName) + { + return isset($this->_attributes['customHydrationModes'][$modeName]) + ? $this->_attributes['customHydrationModes'][$modeName] + : null; + } + + /** + * Add a custom hydration mode. + * + * @param string $modeName The hydration mode name. + * @param string $hydrator The hydrator class name. + */ + public function addCustomHydrationMode($modeName, $hydrator) + { + $this->_attributes['customHydrationModes'][$modeName] = $hydrator; + } + + /** + * Set a class metadata factory. + * + * @param string $cmfName + */ + public function setClassMetadataFactoryName($cmfName) + { + $this->_attributes['classMetadataFactoryName'] = $cmfName; + } + + /** + * @return string + */ + public function getClassMetadataFactoryName() + { + if ( ! isset($this->_attributes['classMetadataFactoryName'])) { + $this->_attributes['classMetadataFactoryName'] = 'Doctrine\ORM\Mapping\ClassMetadataFactory'; + } + + return $this->_attributes['classMetadataFactoryName']; + } + + /** + * Add a filter to the list of possible filters. + * + * @param string $name The name of the filter. + * @param string $className The class name of the filter. + */ + public function addFilter($name, $className) + { + $this->_attributes['filters'][$name] = $className; + } + + /** + * Gets the class name for a given filter name. + * + * @param string $name The name of the filter. + * + * @return string The class name of the filter, or null of it is not + * defined. + */ + public function getFilterClassName($name) + { + return isset($this->_attributes['filters'][$name]) + ? $this->_attributes['filters'][$name] + : null; + } + + /** + * Set default repository class. + * + * @since 2.2 + * @param string $className + * @throws ORMException If not is a \Doctrine\Common\Persistence\ObjectRepository + */ + public function setDefaultRepositoryClassName($className) + { + $reflectionClass = new \ReflectionClass($className); + + if ( ! $reflectionClass->implementsInterface('Doctrine\Common\Persistence\ObjectRepository')) { + throw ORMException::invalidEntityRepository($className); + } + + $this->_attributes['defaultRepositoryClassName'] = $className; + } + + /** + * Get default repository class. + * + * @since 2.2 + * @return string + */ + public function getDefaultRepositoryClassName() + { + return isset($this->_attributes['defaultRepositoryClassName']) + ? $this->_attributes['defaultRepositoryClassName'] + : 'Doctrine\ORM\EntityRepository'; + } + + /** + * Set naming strategy. + * + * @since 2.3 + * @param NamingStrategy $namingStrategy + */ + public function setNamingStrategy(NamingStrategy $namingStrategy) + { + $this->_attributes['namingStrategy'] = $namingStrategy; + } + + /** + * Get naming strategy.. + * + * @since 2.3 + * @return NamingStrategy + */ + public function getNamingStrategy() + { + if ( ! isset($this->_attributes['namingStrategy'])) { + $this->_attributes['namingStrategy'] = new DefaultNamingStrategy(); + } + + return $this->_attributes['namingStrategy']; + } + + /** + * Set quote strategy. + * + * @since 2.3 + * @param Doctrine\ORM\Mapping\QuoteStrategy $quoteStrategy + */ + public function setQuoteStrategy(QuoteStrategy $quoteStrategy) + { + $this->_attributes['quoteStrategy'] = $quoteStrategy; + } + + /** + * Get quote strategy. + * + * @since 2.3 + * @return Doctrine\ORM\Mapping\QuoteStrategy + */ + public function getQuoteStrategy() + { + if ( ! isset($this->_attributes['quoteStrategy'])) { + $this->_attributes['quoteStrategy'] = new DefaultQuoteStrategy(); + } + + return $this->_attributes['quoteStrategy']; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php b/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php new file mode 100644 index 0000000..50e7382 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php @@ -0,0 +1,902 @@ +. + */ + +namespace Doctrine\ORM; + +use Exception, + Doctrine\Common\EventManager, + Doctrine\Common\Persistence\ObjectManager, + Doctrine\DBAL\Connection, + Doctrine\DBAL\LockMode, + Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\Mapping\ClassMetadataFactory, + Doctrine\ORM\Query\ResultSetMapping, + Doctrine\ORM\Proxy\ProxyFactory, + Doctrine\ORM\Query\FilterCollection; + +/** + * The EntityManager is the central access point to ORM functionality. + * + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EntityManager implements ObjectManager +{ + /** + * The used Configuration. + * + * @var \Doctrine\ORM\Configuration + */ + private $config; + + /** + * The database connection used by the EntityManager. + * + * @var \Doctrine\DBAL\Connection + */ + private $conn; + + /** + * The metadata factory, used to retrieve the ORM metadata of entity classes. + * + * @var \Doctrine\ORM\Mapping\ClassMetadataFactory + */ + private $metadataFactory; + + /** + * The EntityRepository instances. + * + * @var array + */ + private $repositories = array(); + + /** + * The UnitOfWork used to coordinate object-level transactions. + * + * @var \Doctrine\ORM\UnitOfWork + */ + private $unitOfWork; + + /** + * The event manager that is the central point of the event system. + * + * @var \Doctrine\Common\EventManager + */ + private $eventManager; + + /** + * The maintained (cached) hydrators. One instance per type. + * + * @var array + */ + private $hydrators = array(); + + /** + * The proxy factory used to create dynamic proxies. + * + * @var \Doctrine\ORM\Proxy\ProxyFactory + */ + private $proxyFactory; + + /** + * The expression builder instance used to generate query expressions. + * + * @var \Doctrine\ORM\Query\Expr + */ + private $expressionBuilder; + + /** + * Whether the EntityManager is closed or not. + * + * @var bool + */ + private $closed = false; + + /** + * Collection of query filters. + * + * @var Doctrine\ORM\Query\FilterCollection + */ + private $filterCollection; + + /** + * Creates a new EntityManager that operates on the given database connection + * and uses the given Configuration and EventManager implementations. + * + * @param \Doctrine\DBAL\Connection $conn + * @param \Doctrine\ORM\Configuration $config + * @param \Doctrine\Common\EventManager $eventManager + */ + protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager) + { + $this->conn = $conn; + $this->config = $config; + $this->eventManager = $eventManager; + + $metadataFactoryClassName = $config->getClassMetadataFactoryName(); + + $this->metadataFactory = new $metadataFactoryClassName; + $this->metadataFactory->setEntityManager($this); + $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl()); + + $this->unitOfWork = new UnitOfWork($this); + $this->proxyFactory = new ProxyFactory( + $this, + $config->getProxyDir(), + $config->getProxyNamespace(), + $config->getAutoGenerateProxyClasses() + ); + } + + /** + * Gets the database connection object used by the EntityManager. + * + * @return \Doctrine\DBAL\Connection + */ + public function getConnection() + { + return $this->conn; + } + + /** + * Gets the metadata factory used to gather the metadata of classes. + * + * @return \Doctrine\ORM\Mapping\ClassMetadataFactory + */ + public function getMetadataFactory() + { + return $this->metadataFactory; + } + + /** + * Gets an ExpressionBuilder used for object-oriented construction of query expressions. + * + * Example: + * + * + * $qb = $em->createQueryBuilder(); + * $expr = $em->getExpressionBuilder(); + * $qb->select('u')->from('User', 'u') + * ->where($expr->orX($expr->eq('u.id', 1), $expr->eq('u.id', 2))); + * + * + * @return \Doctrine\ORM\Query\Expr + */ + public function getExpressionBuilder() + { + if ($this->expressionBuilder === null) { + $this->expressionBuilder = new Query\Expr; + } + + return $this->expressionBuilder; + } + + /** + * Starts a transaction on the underlying database connection. + */ + public function beginTransaction() + { + $this->conn->beginTransaction(); + } + + /** + * Executes a function in a transaction. + * + * The function gets passed this EntityManager instance as an (optional) parameter. + * + * {@link flush} is invoked prior to transaction commit. + * + * If an exception occurs during execution of the function or flushing or transaction commit, + * the transaction is rolled back, the EntityManager closed and the exception re-thrown. + * + * @param callable $func The function to execute transactionally. + * @return mixed Returns the non-empty value returned from the closure or true instead + */ + public function transactional($func) + { + if (!is_callable($func)) { + throw new \InvalidArgumentException('Expected argument of type "callable", got "' . gettype($func) . '"'); + } + + $this->conn->beginTransaction(); + + try { + $return = call_user_func($func, $this); + + $this->flush(); + $this->conn->commit(); + + return $return ?: true; + } catch (Exception $e) { + $this->close(); + $this->conn->rollback(); + + throw $e; + } + } + + /** + * Commits a transaction on the underlying database connection. + */ + public function commit() + { + $this->conn->commit(); + } + + /** + * Performs a rollback on the underlying database connection. + */ + public function rollback() + { + $this->conn->rollback(); + } + + /** + * Returns the ORM metadata descriptor for a class. + * + * The class name must be the fully-qualified class name without a leading backslash + * (as it is returned by get_class($obj)) or an aliased class name. + * + * Examples: + * MyProject\Domain\User + * sales:PriceRequest + * + * @return \Doctrine\ORM\Mapping\ClassMetadata + * @internal Performance-sensitive method. + */ + public function getClassMetadata($className) + { + return $this->metadataFactory->getMetadataFor($className); + } + + /** + * Creates a new Query object. + * + * @param string $dql The DQL string. + * @return \Doctrine\ORM\Query + */ + public function createQuery($dql = "") + { + $query = new Query($this); + + if ( ! empty($dql)) { + $query->setDql($dql); + } + + return $query; + } + + /** + * Creates a Query from a named query. + * + * @param string $name + * @return \Doctrine\ORM\Query + */ + public function createNamedQuery($name) + { + return $this->createQuery($this->config->getNamedQuery($name)); + } + + /** + * Creates a native SQL query. + * + * @param string $sql + * @param ResultSetMapping $rsm The ResultSetMapping to use. + * @return NativeQuery + */ + public function createNativeQuery($sql, ResultSetMapping $rsm) + { + $query = new NativeQuery($this); + + $query->setSql($sql); + $query->setResultSetMapping($rsm); + + return $query; + } + + /** + * Creates a NativeQuery from a named native query. + * + * @param string $name + * @return \Doctrine\ORM\NativeQuery + */ + public function createNamedNativeQuery($name) + { + list($sql, $rsm) = $this->config->getNamedNativeQuery($name); + + return $this->createNativeQuery($sql, $rsm); + } + + /** + * Create a QueryBuilder instance + * + * @return QueryBuilder $qb + */ + public function createQueryBuilder() + { + return new QueryBuilder($this); + } + + /** + * Flushes all changes to objects that have been queued up to now to the database. + * This effectively synchronizes the in-memory state of managed objects with the + * database. + * + * If an entity is explicitly passed to this method only this entity and + * the cascade-persist semantics + scheduled inserts/removals are synchronized. + * + * @param object $entity + * @throws \Doctrine\ORM\OptimisticLockException If a version check on an entity that + * makes use of optimistic locking fails. + */ + public function flush($entity = null) + { + $this->errorIfClosed(); + + $this->unitOfWork->commit($entity); + } + + /** + * Finds an Entity by its identifier. + * + * @param string $entityName + * @param mixed $id + * @param integer $lockMode + * @param integer $lockVersion + * + * @return object + */ + public function find($entityName, $id, $lockMode = LockMode::NONE, $lockVersion = null) + { + $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\')); + + if ( ! is_array($id)) { + $id = array($class->identifier[0] => $id); + } + + $sortedId = array(); + + foreach ($class->identifier as $identifier) { + if ( ! isset($id[$identifier])) { + throw ORMException::missingIdentifierField($class->name, $identifier); + } + + $sortedId[$identifier] = $id[$identifier]; + } + + $unitOfWork = $this->getUnitOfWork(); + + // Check identity map first + if (($entity = $unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) { + if ( ! ($entity instanceof $class->name)) { + return null; + } + + switch ($lockMode) { + case LockMode::OPTIMISTIC: + $this->lock($entity, $lockMode, $lockVersion); + break; + + case LockMode::PESSIMISTIC_READ: + case LockMode::PESSIMISTIC_WRITE: + $persister = $unitOfWork->getEntityPersister($class->name); + $persister->refresh($sortedId, $entity, $lockMode); + break; + } + + return $entity; // Hit! + } + + $persister = $unitOfWork->getEntityPersister($class->name); + + switch ($lockMode) { + case LockMode::NONE: + return $persister->load($sortedId); + + case LockMode::OPTIMISTIC: + if ( ! $class->isVersioned) { + throw OptimisticLockException::notVersioned($class->name); + } + + $entity = $persister->load($sortedId); + + $unitOfWork->lock($entity, $lockMode, $lockVersion); + + return $entity; + + default: + if ( ! $this->getConnection()->isTransactionActive()) { + throw TransactionRequiredException::transactionRequired(); + } + + return $persister->load($sortedId, null, null, array(), $lockMode); + } + } + + /** + * Gets a reference to the entity identified by the given type and identifier + * without actually loading it, if the entity is not yet loaded. + * + * @param string $entityName The name of the entity type. + * @param mixed $id The entity identifier. + * @return object The entity reference. + */ + public function getReference($entityName, $id) + { + $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\')); + + if ( ! is_array($id)) { + $id = array($class->identifier[0] => $id); + } + + $sortedId = array(); + + foreach ($class->identifier as $identifier) { + if ( ! isset($id[$identifier])) { + throw ORMException::missingIdentifierField($class->name, $identifier); + } + + $sortedId[$identifier] = $id[$identifier]; + } + + // Check identity map first, if its already in there just return it. + if (($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) { + return ($entity instanceof $class->name) ? $entity : null; + } + + if ($class->subClasses) { + return $this->find($entityName, $sortedId); + } + + if ( ! is_array($sortedId)) { + $sortedId = array($class->identifier[0] => $sortedId); + } + + $entity = $this->proxyFactory->getProxy($class->name, $sortedId); + + $this->unitOfWork->registerManaged($entity, $sortedId, array()); + + return $entity; + } + + /** + * Gets a partial reference to the entity identified by the given type and identifier + * without actually loading it, if the entity is not yet loaded. + * + * The returned reference may be a partial object if the entity is not yet loaded/managed. + * If it is a partial object it will not initialize the rest of the entity state on access. + * Thus you can only ever safely access the identifier of an entity obtained through + * this method. + * + * The use-cases for partial references involve maintaining bidirectional associations + * without loading one side of the association or to update an entity without loading it. + * Note, however, that in the latter case the original (persistent) entity data will + * never be visible to the application (especially not event listeners) as it will + * never be loaded in the first place. + * + * @param string $entityName The name of the entity type. + * @param mixed $identifier The entity identifier. + * @return object The (partial) entity reference. + */ + public function getPartialReference($entityName, $identifier) + { + $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\')); + + // Check identity map first, if its already in there just return it. + if (($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) !== false) { + return ($entity instanceof $class->name) ? $entity : null; + } + + if ( ! is_array($identifier)) { + $identifier = array($class->identifier[0] => $identifier); + } + + $entity = $class->newInstance(); + + $class->setIdentifierValues($entity, $identifier); + + $this->unitOfWork->registerManaged($entity, $identifier, array()); + $this->unitOfWork->markReadOnly($entity); + + return $entity; + } + + /** + * Clears the EntityManager. All entities that are currently managed + * by this EntityManager become detached. + * + * @param string $entityName if given, only entities of this type will get detached + */ + public function clear($entityName = null) + { + $this->unitOfWork->clear($entityName); + } + + /** + * Closes the EntityManager. All entities that are currently managed + * by this EntityManager become detached. The EntityManager may no longer + * be used after it is closed. + */ + public function close() + { + $this->clear(); + + $this->closed = true; + } + + /** + * Tells the EntityManager to make an instance managed and persistent. + * + * The entity will be entered into the database at or before transaction + * commit or as a result of the flush operation. + * + * NOTE: The persist operation always considers entities that are not yet known to + * this EntityManager as NEW. Do not pass detached entities to the persist operation. + * + * @param object $object The instance to make managed and persistent. + */ + public function persist($entity) + { + if ( ! is_object($entity)) { + throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()' , $entity); + } + + $this->errorIfClosed(); + + $this->unitOfWork->persist($entity); + } + + /** + * Removes an entity instance. + * + * A removed entity will be removed from the database at or before transaction commit + * or as a result of the flush operation. + * + * @param object $entity The entity instance to remove. + */ + public function remove($entity) + { + if ( ! is_object($entity)) { + throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()' , $entity); + } + + $this->errorIfClosed(); + + $this->unitOfWork->remove($entity); + } + + /** + * Refreshes the persistent state of an entity from the database, + * overriding any local changes that have not yet been persisted. + * + * @param object $entity The entity to refresh. + */ + public function refresh($entity) + { + if ( ! is_object($entity)) { + throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()' , $entity); + } + + $this->errorIfClosed(); + + $this->unitOfWork->refresh($entity); + } + + /** + * Detaches an entity from the EntityManager, causing a managed entity to + * become detached. Unflushed changes made to the entity if any + * (including removal of the entity), will not be synchronized to the database. + * Entities which previously referenced the detached entity will continue to + * reference it. + * + * @param object $entity The entity to detach. + */ + public function detach($entity) + { + if ( ! is_object($entity)) { + throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()' , $entity); + } + + $this->unitOfWork->detach($entity); + } + + /** + * Merges the state of a detached entity into the persistence context + * of this EntityManager and returns the managed copy of the entity. + * The entity passed to merge will not become associated/managed with this EntityManager. + * + * @param object $entity The detached entity to merge into the persistence context. + * @return object The managed copy of the entity. + */ + public function merge($entity) + { + if ( ! is_object($entity)) { + throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()' , $entity); + } + + $this->errorIfClosed(); + + return $this->unitOfWork->merge($entity); + } + + /** + * Creates a copy of the given entity. Can create a shallow or a deep copy. + * + * @param object $entity The entity to copy. + * @return object The new entity. + * @todo Implementation need. This is necessary since $e2 = clone $e1; throws an E_FATAL when access anything on $e: + * Fatal error: Maximum function nesting level of '100' reached, aborting! + */ + public function copy($entity, $deep = false) + { + throw new \BadMethodCallException("Not implemented."); + } + + /** + * Acquire a lock on the given entity. + * + * @param object $entity + * @param int $lockMode + * @param int $lockVersion + * @throws OptimisticLockException + * @throws PessimisticLockException + */ + public function lock($entity, $lockMode, $lockVersion = null) + { + $this->unitOfWork->lock($entity, $lockMode, $lockVersion); + } + + /** + * Gets the repository for an entity class. + * + * @param string $entityName The name of the entity. + * @return EntityRepository The repository class. + */ + public function getRepository($entityName) + { + $entityName = ltrim($entityName, '\\'); + + if (isset($this->repositories[$entityName])) { + return $this->repositories[$entityName]; + } + + $metadata = $this->getClassMetadata($entityName); + $repositoryClassName = $metadata->customRepositoryClassName; + + if ($repositoryClassName === null) { + $repositoryClassName = $this->config->getDefaultRepositoryClassName(); + } + + $repository = new $repositoryClassName($this, $metadata); + + $this->repositories[$entityName] = $repository; + + return $repository; + } + + /** + * Determines whether an entity instance is managed in this EntityManager. + * + * @param object $entity + * @return boolean TRUE if this EntityManager currently manages the given entity, FALSE otherwise. + */ + public function contains($entity) + { + return $this->unitOfWork->isScheduledForInsert($entity) + || $this->unitOfWork->isInIdentityMap($entity) + && ! $this->unitOfWork->isScheduledForDelete($entity); + } + + /** + * Gets the EventManager used by the EntityManager. + * + * @return \Doctrine\Common\EventManager + */ + public function getEventManager() + { + return $this->eventManager; + } + + /** + * Gets the Configuration used by the EntityManager. + * + * @return \Doctrine\ORM\Configuration + */ + public function getConfiguration() + { + return $this->config; + } + + /** + * Throws an exception if the EntityManager is closed or currently not active. + * + * @throws ORMException If the EntityManager is closed. + */ + private function errorIfClosed() + { + if ($this->closed) { + throw ORMException::entityManagerClosed(); + } + } + + /** + * Check if the Entity manager is open or closed. + * + * @return bool + */ + public function isOpen() + { + return (!$this->closed); + } + + /** + * Gets the UnitOfWork used by the EntityManager to coordinate operations. + * + * @return \Doctrine\ORM\UnitOfWork + */ + public function getUnitOfWork() + { + return $this->unitOfWork; + } + + /** + * Gets a hydrator for the given hydration mode. + * + * This method caches the hydrator instances which is used for all queries that don't + * selectively iterate over the result. + * + * @param int $hydrationMode + * @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator + */ + public function getHydrator($hydrationMode) + { + if ( ! isset($this->hydrators[$hydrationMode])) { + $this->hydrators[$hydrationMode] = $this->newHydrator($hydrationMode); + } + + return $this->hydrators[$hydrationMode]; + } + + /** + * Create a new instance for the given hydration mode. + * + * @param int $hydrationMode + * @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator + */ + public function newHydrator($hydrationMode) + { + switch ($hydrationMode) { + case Query::HYDRATE_OBJECT: + return new Internal\Hydration\ObjectHydrator($this); + + case Query::HYDRATE_ARRAY: + return new Internal\Hydration\ArrayHydrator($this); + + case Query::HYDRATE_SCALAR: + return new Internal\Hydration\ScalarHydrator($this); + + case Query::HYDRATE_SINGLE_SCALAR: + return new Internal\Hydration\SingleScalarHydrator($this); + + case Query::HYDRATE_SIMPLEOBJECT: + return new Internal\Hydration\SimpleObjectHydrator($this); + + default: + if (($class = $this->config->getCustomHydrationMode($hydrationMode)) !== null) { + return new $class($this); + } + } + + throw ORMException::invalidHydrationMode($hydrationMode); + } + + /** + * Gets the proxy factory used by the EntityManager to create entity proxies. + * + * @return ProxyFactory + */ + public function getProxyFactory() + { + return $this->proxyFactory; + } + + /** + * Helper method to initialize a lazy loading proxy or persistent collection. + * + * This method is a no-op for other objects + * + * @param object $obj + */ + public function initializeObject($obj) + { + $this->unitOfWork->initializeObject($obj); + } + + /** + * Factory method to create EntityManager instances. + * + * @param mixed $conn An array with the connection parameters or an existing + * Connection instance. + * @param Configuration $config The Configuration instance to use. + * @param EventManager $eventManager The EventManager instance to use. + * @return EntityManager The created EntityManager. + */ + public static function create($conn, Configuration $config, EventManager $eventManager = null) + { + if ( ! $config->getMetadataDriverImpl()) { + throw ORMException::missingMappingDriverImpl(); + } + + switch (true) { + case (is_array($conn)): + $conn = \Doctrine\DBAL\DriverManager::getConnection( + $conn, $config, ($eventManager ?: new EventManager()) + ); + break; + + case ($conn instanceof Connection): + if ($eventManager !== null && $conn->getEventManager() !== $eventManager) { + throw ORMException::mismatchedEventManager(); + } + break; + + default: + throw new \InvalidArgumentException("Invalid argument: " . $conn); + } + + return new EntityManager($conn, $config, $conn->getEventManager()); + } + + /** + * Gets the enabled filters. + * + * @return FilterCollection The active filter collection. + */ + public function getFilters() + { + if (null === $this->filterCollection) { + $this->filterCollection = new FilterCollection($this); + } + + return $this->filterCollection; + } + + /** + * Checks whether the state of the filter collection is clean. + * + * @return boolean True, if the filter collection is clean. + */ + public function isFiltersStateClean() + { + return null === $this->filterCollection || $this->filterCollection->isClean(); + } + + /** + * Checks whether the Entity Manager has filters. + * + * @return True, if the EM has a filter collection. + */ + public function hasFilters() + { + return null !== $this->filterCollection; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/EntityNotFoundException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/EntityNotFoundException.php new file mode 100644 index 0000000..087c65d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/EntityNotFoundException.php @@ -0,0 +1,34 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Exception thrown when a Proxy fails to retrieve an Entity result. + * + * @author robo + * @since 2.0 + */ +class EntityNotFoundException extends ORMException +{ + public function __construct() + { + parent::__construct('Entity was not found.'); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php b/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php new file mode 100644 index 0000000..6956ada --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php @@ -0,0 +1,276 @@ +. + */ + +namespace Doctrine\ORM; + +use Doctrine\DBAL\LockMode; +use Doctrine\Common\Persistence\ObjectRepository; + +use Doctrine\Common\Collections\Selectable; +use Doctrine\Common\Collections\Criteria; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\ExpressionBuilder; + +/** + * An EntityRepository serves as a repository for entities with generic as well as + * business specific methods for retrieving entities. + * + * This class is designed for inheritance and users can subclass this class to + * write their own repositories with business-specific methods to locate entities. + * + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EntityRepository implements ObjectRepository, Selectable +{ + /** + * @var string + */ + protected $_entityName; + + /** + * @var EntityManager + */ + protected $_em; + + /** + * @var \Doctrine\ORM\Mapping\ClassMetadata + */ + protected $_class; + + /** + * Initializes a new EntityRepository. + * + * @param EntityManager $em The EntityManager to use. + * @param ClassMetadata $classMetadata The class descriptor. + */ + public function __construct($em, Mapping\ClassMetadata $class) + { + $this->_entityName = $class->name; + $this->_em = $em; + $this->_class = $class; + } + + /** + * Create a new QueryBuilder instance that is prepopulated for this entity name + * + * @param string $alias + * @return QueryBuilder $qb + */ + public function createQueryBuilder($alias) + { + return $this->_em->createQueryBuilder() + ->select($alias) + ->from($this->_entityName, $alias); + } + + /** + * Create a new Query instance based on a predefined metadata named query. + * + * @param string $queryName + * @return Query + */ + public function createNamedQuery($queryName) + { + return $this->_em->createQuery($this->_class->getNamedQuery($queryName)); + } + + /** + * Creates a native SQL query. + * + * @param string $queryName + * @return NativeQuery + */ + public function createNativeNamedQuery($queryName) + { + $queryMapping = $this->_class->getNamedNativeQuery($queryName); + $rsm = new Query\ResultSetMappingBuilder($this->_em); + $rsm->addNamedNativeQueryMapping($this->_class, $queryMapping); + + return $this->_em->createNativeQuery($queryMapping['query'], $rsm); + } + + /** + * Clears the repository, causing all managed entities to become detached. + */ + public function clear() + { + $this->_em->clear($this->_class->rootEntityName); + } + + /** + * Finds an entity by its primary key / identifier. + * + * @param mixed $id The identifier. + * @param integer $lockMode + * @param integer $lockVersion + * + * @return object The entity. + */ + public function find($id, $lockMode = LockMode::NONE, $lockVersion = null) + { + return $this->_em->find($this->_entityName, $id, $lockMode, $lockVersion); + } + + /** + * Finds all entities in the repository. + * + * @return array The entities. + */ + public function findAll() + { + return $this->findBy(array()); + } + + /** + * Finds entities by a set of criteria. + * + * @param array $criteria + * @param array|null $orderBy + * @param int|null $limit + * @param int|null $offset + * @return array The objects. + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + { + $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName); + + return $persister->loadAll($criteria, $orderBy, $limit, $offset); + } + + /** + * Finds a single entity by a set of criteria. + * + * @param array $criteria + * @return object + */ + public function findOneBy(array $criteria) + { + $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName); + + return $persister->load($criteria, null, null, array(), 0, 1); + } + + /** + * Adds support for magic finders. + * + * @return array|object The found entity/entities. + * @throws BadMethodCallException If the method called is an invalid find* method + * or no find* method at all and therefore an invalid + * method call. + */ + public function __call($method, $arguments) + { + switch (true) { + case (0 === strpos($method, 'findBy')): + $by = substr($method, 6); + $method = 'findBy'; + break; + + case (0 === strpos($method, 'findOneBy')): + $by = substr($method, 9); + $method = 'findOneBy'; + break; + + default: + throw new \BadMethodCallException( + "Undefined method '$method'. The method name must start with ". + "either findBy or findOneBy!" + ); + } + + if (empty($arguments)) { + throw ORMException::findByRequiresParameter($method . $by); + } + + $fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by)); + + if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) { + switch (count($arguments)) { + case 1: + return $this->$method(array($fieldName => $arguments[0])); + + case 2: + return $this->$method(array($fieldName => $arguments[0]), $arguments[1]); + + case 3: + return $this->$method(array($fieldName => $arguments[0]), $arguments[1], $arguments[2]); + + case 4; + return $this->$method(array($fieldName => $arguments[0]), $arguments[1], $arguments[2], $arguments[3]); + + default: + // Do nothing + } + } + + throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by); + } + + /** + * @return string + */ + protected function getEntityName() + { + return $this->_entityName; + } + + /** + * @return string + */ + public function getClassName() + { + return $this->getEntityName(); + } + + /** + * @return EntityManager + */ + protected function getEntityManager() + { + return $this->_em; + } + + /** + * @return Mapping\ClassMetadata + */ + protected function getClassMetadata() + { + return $this->_class; + } + + /** + * Select all elements from a selectable that match the expression and + * return a new collection containing these elements. + * + * @param \Doctrine\Common\Collections\Criteria $criteria + * + * @return \Doctrine\Common\Collections\Collection + */ + public function matching(Criteria $criteria) + { + $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName); + + return new ArrayCollection($persister->loadCriteria($criteria)); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Event/LifecycleEventArgs.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/LifecycleEventArgs.php new file mode 100644 index 0000000..4346054 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/LifecycleEventArgs.php @@ -0,0 +1,77 @@ +. +*/ + +namespace Doctrine\ORM\Event; + +use Doctrine\Common\EventArgs; +use Doctrine\ORM\EntityManager; + +/** + * Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions + * of entities. + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class LifecycleEventArgs extends EventArgs +{ + /** + * @var \Doctrine\ORM\EntityManager + */ + private $em; + + /** + * @var object + */ + private $entity; + + /** + * Constructor + * + * @param object $entity + * @param \Doctrine\ORM\EntityManager $em + */ + public function __construct($entity, EntityManager $em) + { + $this->entity = $entity; + $this->em = $em; + } + + /** + * Retrieve associated Entity. + * + * @return object + */ + public function getEntity() + { + return $this->entity; + } + + /** + * Retrieve associated EntityManager. + * + * @return \Doctrine\ORM\EntityManager + */ + public function getEntityManager() + { + return $this->em; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php new file mode 100644 index 0000000..4c2cb07 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php @@ -0,0 +1,76 @@ +. + */ + +namespace Doctrine\ORM\Event; + +use Doctrine\Common\EventArgs; +use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\EntityManager; + +/** + * Class that holds event arguments for a loadMetadata event. + * + * @author Jonathan H. Wage + * @since 2.0 + */ +class LoadClassMetadataEventArgs extends EventArgs +{ + /** + * @var \Doctrine\ORM\Mapping\ClassMetadata + */ + private $classMetadata; + + /** + * @var \Doctrine\ORM\EntityManager + */ + private $em; + + /** + * Constructor. + * + * @param \Doctrine\ORM\Mapping\ClassMetadataInfo $classMetadata + * @param \Doctrine\ORM\EntityManager $em + */ + public function __construct(ClassMetadataInfo $classMetadata, EntityManager $em) + { + $this->classMetadata = $classMetadata; + $this->em = $em; + } + + /** + * Retrieve associated ClassMetadata. + * + * @return \Doctrine\ORM\Mapping\ClassMetadataInfo + */ + public function getClassMetadata() + { + return $this->classMetadata; + } + + /** + * Retrieve associated EntityManager. + * + * @return \Doctrine\ORM\EntityManager + */ + public function getEntityManager() + { + return $this->em; + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Event/OnClearEventArgs.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/OnClearEventArgs.php new file mode 100644 index 0000000..309994f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/OnClearEventArgs.php @@ -0,0 +1,84 @@ +. + */ + +namespace Doctrine\ORM\Event; + +/** + * Provides event arguments for the onClear event. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class OnClearEventArgs extends \Doctrine\Common\EventArgs +{ + /** + * @var \Doctrine\ORM\EntityManager + */ + private $em; + + /** + * @var string + */ + private $entityClass; + + /** + * Constructor. + * + * @param \Doctrine\ORM\EntityManager $em + * @param string $entityClass Optional entity class + */ + public function __construct($em, $entityClass = null) + { + $this->em = $em; + $this->entityClass = $entityClass; + } + + /** + * Retrieve associated EntityManager. + * + * @return \Doctrine\ORM\EntityManager + */ + public function getEntityManager() + { + return $this->em; + } + + /** + * Name of the entity class that is cleared, or empty if all are cleared. + * + * @return string + */ + public function getEntityClass() + { + return $this->entityClass; + } + + /** + * Check if event clears all entities. + * + * @return bool + */ + public function clearsAllEntities() + { + return ($this->entityClass === null); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Event/OnFlushEventArgs.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/OnFlushEventArgs.php new file mode 100644 index 0000000..1e18d2a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/OnFlushEventArgs.php @@ -0,0 +1,84 @@ +. + */ + +namespace Doctrine\ORM\Event; + +use Doctrine\ORM\EntityManager; + +/** + * Provides event arguments for the preFlush event. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class OnFlushEventArgs extends \Doctrine\Common\EventArgs +{ + /** + * @var Doctirne\ORM\EntityManager + */ + private $em; + + //private $entitiesToPersist = array(); + //private $entitiesToRemove = array(); + + /** + * Constructor. + * + * @param \Doctrine\ORM\EntityManager $em + */ + public function __construct(EntityManager $em) + { + $this->em = $em; + } + + /** + * Retrieve associated EntityManager. + * + * @return \Doctrine\ORM\EntityManager + */ + public function getEntityManager() + { + return $this->em; + } + + /* + public function addEntityToPersist($entity) + { + + } + + public function addEntityToRemove($entity) + { + + } + + public function addEntityToUpdate($entity) + { + + } + + public function getEntitiesToPersist() + { + return $this->_entitiesToPersist; + } + */ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Event/PostFlushEventArgs.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/PostFlushEventArgs.php new file mode 100644 index 0000000..5f9735c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/PostFlushEventArgs.php @@ -0,0 +1,58 @@ +. + */ +namespace Doctrine\ORM\Event; + +use Doctrine\ORM\EntityManager; +use Doctrine\Common\EventArgs; + +/** + * Provides event arguments for the postFlush event. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Daniel Freudenberger + */ +class PostFlushEventArgs extends EventArgs +{ + /** + * @var \Doctrine\ORM\EntityManager + */ + private $em; + + /** + * Constructor. + * + * @param \Doctrine\ORM\EntityManager $em + */ + public function __construct(EntityManager $em) + { + $this->em = $em; + } + + /** + * Retrieve associated EntityManager. + * + * @return \Doctrine\ORM\EntityManager + */ + public function getEntityManager() + { + return $this->em; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Event/PreFlushEventArgs.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/PreFlushEventArgs.php new file mode 100644 index 0000000..82f2b7e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/PreFlushEventArgs.php @@ -0,0 +1,50 @@ +. + */ + +namespace Doctrine\ORM\Event; + +/** + * Provides event arguments for the preFlush event. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class PreFlushEventArgs extends \Doctrine\Common\EventArgs +{ + /** + * @var EntityManager + */ + private $_em; + + public function __construct($em) + { + $this->_em = $em; + } + + /** + * @return EntityManager + */ + public function getEntityManager() + { + return $this->_em; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php new file mode 100644 index 0000000..188417e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php @@ -0,0 +1,129 @@ +. + */ + +namespace Doctrine\ORM\Event; + +use Doctrine\Common\EventArgs, + Doctrine\ORM\EntityManager; + +/** + * Class that holds event arguments for a preInsert/preUpdate event. + * + * @author Guilherme Blanco + * @author Roman Borschel + * @author Benjamin Eberlei + * @since 2.0 + */ +class PreUpdateEventArgs extends LifecycleEventArgs +{ + /** + * @var array + */ + private $entityChangeSet; + + /** + * Constructor. + * + * @param object $entity + * @param \Doctrine\ORM\EntityManager $em + * @param array $changeSet + */ + public function __construct($entity, EntityManager $em, array &$changeSet) + { + parent::__construct($entity, $em); + + $this->entityChangeSet = &$changeSet; + } + + /** + * Retrieve entity changeset. + * + * @return array + */ + public function getEntityChangeSet() + { + return $this->entityChangeSet; + } + + /** + * Check if field has a changeset. + * + * @return boolean + */ + public function hasChangedField($field) + { + return isset($this->entityChangeSet[$field]); + } + + /** + * Get the old value of the changeset of the changed field. + * + * @param string $field + * @return mixed + */ + public function getOldValue($field) + { + $this->assertValidField($field); + + return $this->entityChangeSet[$field][0]; + } + + /** + * Get the new value of the changeset of the changed field. + * + * @param string $field + * @return mixed + */ + public function getNewValue($field) + { + $this->assertValidField($field); + + return $this->entityChangeSet[$field][1]; + } + + /** + * Set the new value of this field. + * + * @param string $field + * @param mixed $value + */ + public function setNewValue($field, $value) + { + $this->assertValidField($field); + + $this->entityChangeSet[$field][1] = $value; + } + + /** + * Assert the field exists in changeset. + * + * @param string $field + */ + private function assertValidField($field) + { + if ( ! isset($this->entityChangeSet[$field])) { + throw new \InvalidArgumentException(sprintf( + 'Field "%s" is not a valid field of the entity "%s" in PreUpdateEventArgs.', + $field, + get_class($this->getEntity()) + )); + } + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Events.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Events.php new file mode 100644 index 0000000..812a43e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Events.php @@ -0,0 +1,146 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Container for all ORM events. + * + * This class cannot be instantiated. + * + * @author Roman Borschel + * @since 2.0 + */ +final class Events +{ + private function __construct() {} + /** + * The preRemove event occurs for a given entity before the respective + * EntityManager remove operation for that entity is executed. + * + * This is an entity lifecycle event. + * + * @var string + */ + const preRemove = 'preRemove'; + /** + * The postRemove event occurs for an entity after the entity has + * been deleted. It will be invoked after the database delete operations. + * + * This is an entity lifecycle event. + * + * @var string + */ + const postRemove = 'postRemove'; + /** + * The prePersist event occurs for a given entity before the respective + * EntityManager persist operation for that entity is executed. + * + * This is an entity lifecycle event. + * + * @var string + */ + const prePersist = 'prePersist'; + /** + * The postPersist event occurs for an entity after the entity has + * been made persistent. It will be invoked after the database insert operations. + * Generated primary key values are available in the postPersist event. + * + * This is an entity lifecycle event. + * + * @var string + */ + const postPersist = 'postPersist'; + /** + * The preUpdate event occurs before the database update operations to + * entity data. + * + * This is an entity lifecycle event. + * + * @var string + */ + const preUpdate = 'preUpdate'; + /** + * The postUpdate event occurs after the database update operations to + * entity data. + * + * This is an entity lifecycle event. + * + * @var string + */ + const postUpdate = 'postUpdate'; + /** + * The postLoad event occurs for an entity after the entity has been loaded + * into the current EntityManager from the database or after the refresh operation + * has been applied to it. + * + * Note that the postLoad event occurs for an entity before any associations have been + * initialized. Therefore it is not safe to access associations in a postLoad callback + * or event handler. + * + * This is an entity lifecycle event. + * + * @var string + */ + const postLoad = 'postLoad'; + /** + * The loadClassMetadata event occurs after the mapping metadata for a class + * has been loaded from a mapping source (annotations/xml/yaml). + * + * @var string + */ + const loadClassMetadata = 'loadClassMetadata'; + + /** + * The preFlush event occurs when the EntityManager#flush() operation is invoked, + * but before any changes to managed entites have been calculated. This event is + * always raised right after EntityManager#flush() call. + */ + const preFlush = 'preFlush'; + + /** + * The onFlush event occurs when the EntityManager#flush() operation is invoked, + * after any changes to managed entities have been determined but before any + * actual database operations are executed. The event is only raised if there is + * actually something to do for the underlying UnitOfWork. If nothing needs to be done, + * the onFlush event is not raised. + * + * @var string + */ + const onFlush = 'onFlush'; + + /** + * The postFlush event occurs when the EntityManager#flush() operation is invoked and + * after all actual database operations are executed successfully. The event is only raised if there is + * actually something to do for the underlying UnitOfWork. If nothing needs to be done, + * the postFlush event is not raised. The event won't be raised if an error occurs during the + * flush operation. + * + * @var string + */ + const postFlush = 'postFlush'; + + /** + * The onClear event occurs when the EntityManager#clear() operation is invoked, + * after all references to entities have been removed from the unit of work. + * + * @var string + */ + const onClear = 'onClear'; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Id/AbstractIdGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/AbstractIdGenerator.php new file mode 100644 index 0000000..ef98caf --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/AbstractIdGenerator.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\ORM\Id; + +use Doctrine\ORM\EntityManager; + +abstract class AbstractIdGenerator +{ + /** + * Generates an identifier for an entity. + * + * @param \Doctrine\ORM\Entity $entity + * @return mixed + */ + abstract public function generate(EntityManager $em, $entity); + + /** + * Gets whether this generator is a post-insert generator which means that + * {@link generate()} must be called after the entity has been inserted + * into the database. + * + * By default, this method returns FALSE. Generators that have this requirement + * must override this method and return TRUE. + * + * @return boolean + */ + public function isPostInsertGenerator() + { + return false; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Id/AssignedGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/AssignedGenerator.php new file mode 100644 index 0000000..0597c3b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/AssignedGenerator.php @@ -0,0 +1,70 @@ +. + */ + +namespace Doctrine\ORM\Id; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\ORMException; + +/** + * Special generator for application-assigned identifiers (doesnt really generate anything). + * + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class AssignedGenerator extends AbstractIdGenerator +{ + /** + * Returns the identifier assigned to the given entity. + * + * @param object $entity + * @return mixed + * @override + */ + public function generate(EntityManager $em, $entity) + { + $class = $em->getClassMetadata(get_class($entity)); + $idFields = $class->getIdentifierFieldNames(); + $identifier = array(); + + foreach ($idFields as $idField) { + $value = $class->reflFields[$idField]->getValue($entity); + + if ( ! isset($value)) { + throw ORMException::entityMissingAssignedIdForField($entity, $idField); + } + + if (isset($class->associationMappings[$idField])) { + if ( ! $em->getUnitOfWork()->isInIdentityMap($value)) { + throw ORMException::entityMissingForeignAssignedId($entity, $value); + } + + // NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced. + $value = current($em->getUnitOfWork()->getEntityIdentifier($value)); + } + + $identifier[$idField] = $value; + } + + return $identifier; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Id/IdentityGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/IdentityGenerator.php new file mode 100644 index 0000000..ff2cd01 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/IdentityGenerator.php @@ -0,0 +1,59 @@ +. + */ + +namespace Doctrine\ORM\Id; + +use Doctrine\ORM\EntityManager; + +/** + * Id generator that obtains IDs from special "identity" columns. These are columns + * that automatically get a database-generated, auto-incremented identifier on INSERT. + * This generator obtains the last insert id after such an insert. + */ +class IdentityGenerator extends AbstractIdGenerator +{ + /** @var string The name of the sequence to pass to lastInsertId(), if any. */ + private $_seqName; + + /** + * @param string $seqName The name of the sequence to pass to lastInsertId() + * to obtain the last generated identifier within the current + * database session/connection, if any. + */ + public function __construct($seqName = null) + { + $this->_seqName = $seqName; + } + + /** + * {@inheritdoc} + */ + public function generate(EntityManager $em, $entity) + { + return (int)$em->getConnection()->lastInsertId($this->_seqName); + } + + /** + * {@inheritdoc} + */ + public function isPostInsertGenerator() + { + return true; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Id/SequenceGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/SequenceGenerator.php new file mode 100644 index 0000000..5b5d831 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/SequenceGenerator.php @@ -0,0 +1,106 @@ +. + */ + +namespace Doctrine\ORM\Id; + +use Serializable, Doctrine\ORM\EntityManager; + +/** + * Represents an ID generator that uses a database sequence. + * + * @since 2.0 + * @author Roman Borschel + */ +class SequenceGenerator extends AbstractIdGenerator implements Serializable +{ + private $_allocationSize; + private $_sequenceName; + private $_nextValue = 0; + private $_maxValue = null; + + /** + * Initializes a new sequence generator. + * + * @param \Doctrine\ORM\EntityManager $em The EntityManager to use. + * @param string $sequenceName The name of the sequence. + * @param integer $allocationSize The allocation size of the sequence. + */ + public function __construct($sequenceName, $allocationSize) + { + $this->_sequenceName = $sequenceName; + $this->_allocationSize = $allocationSize; + } + + /** + * Generates an ID for the given entity. + * + * @param object $entity + * @return integer|float The generated value. + * @override + */ + public function generate(EntityManager $em, $entity) + { + if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) { + // Allocate new values + $conn = $em->getConnection(); + $sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName); + + $this->_nextValue = (int)$conn->fetchColumn($sql); + $this->_maxValue = $this->_nextValue + $this->_allocationSize; + } + + return $this->_nextValue++; + } + + /** + * Gets the maximum value of the currently allocated bag of values. + * + * @return integer|float + */ + public function getCurrentMaxValue() + { + return $this->_maxValue; + } + + /** + * Gets the next value that will be returned by generate(). + * + * @return integer|float + */ + public function getNextValue() + { + return $this->_nextValue; + } + + public function serialize() + { + return serialize(array( + 'allocationSize' => $this->_allocationSize, + 'sequenceName' => $this->_sequenceName + )); + } + + public function unserialize($serialized) + { + $array = unserialize($serialized); + + $this->_sequenceName = $array['sequenceName']; + $this->_allocationSize = $array['allocationSize']; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Id/TableGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/TableGenerator.php new file mode 100644 index 0000000..7e84b0a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/TableGenerator.php @@ -0,0 +1,81 @@ +. + */ + +namespace Doctrine\ORM\Id; + +use Doctrine\ORM\EntityManager; + +/** + * Id generator that uses a single-row database table and a hi/lo algorithm. + * + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +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++; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Id/UuidGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/UuidGenerator.php new file mode 100644 index 0000000..3978f1b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Id/UuidGenerator.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\ORM\Id; + +use Serializable, Doctrine\ORM\EntityManager; + +/** + * Represents an ID generator that uses the database UUID expression + * + * @since 2.3 + * @author Maarten de Keizer + */ +class UuidGenerator extends AbstractIdGenerator +{ + + /** + * Generates an ID for the given entity. + * + * @param Doctrine\ORM\EntityManager $em The EntityManager to user + * @param object $entity + * @return string The generated value. + * @override + */ + public function generate(EntityManager $em, $entity) + { + $conn = $em->getConnection(); + $sql = 'SELECT ' . $conn->getDatabasePlatform()->getGuidExpression(); + return $conn->query($sql)->fetchColumn(0); + } + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/CommitOrderCalculator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/CommitOrderCalculator.php new file mode 100644 index 0000000..a4ae5f3 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/CommitOrderCalculator.php @@ -0,0 +1,118 @@ +. + */ + +namespace Doctrine\ORM\Internal; + +/** + * The CommitOrderCalculator is used by the UnitOfWork to sort out the + * correct order in which changes to entities need to be persisted. + * + * @since 2.0 + * @author Roman Borschel + * @author Guilherme Blanco + */ +class CommitOrderCalculator +{ + const NOT_VISITED = 1; + const IN_PROGRESS = 2; + const VISITED = 3; + + private $_nodeStates = array(); + private $_classes = array(); // The nodes to sort + private $_relatedClasses = array(); + private $_sorted = array(); + + /** + * Clears the current graph. + * + * @return void + */ + public function clear() + { + $this->_classes = + $this->_relatedClasses = array(); + } + + /** + * Gets a valid commit order for all current nodes. + * + * Uses a depth-first search (DFS) to traverse the graph. + * The desired topological sorting is the reverse postorder of these searches. + * + * @return array The list of ordered classes. + */ + public function getCommitOrder() + { + // Check whether we need to do anything. 0 or 1 node is easy. + $nodeCount = count($this->_classes); + + if ($nodeCount <= 1) { + return ($nodeCount == 1) ? array_values($this->_classes) : array(); + } + + // Init + foreach ($this->_classes as $node) { + $this->_nodeStates[$node->name] = self::NOT_VISITED; + } + + // Go + foreach ($this->_classes as $node) { + if ($this->_nodeStates[$node->name] == self::NOT_VISITED) { + $this->_visitNode($node); + } + } + + $sorted = array_reverse($this->_sorted); + + $this->_sorted = $this->_nodeStates = array(); + + return $sorted; + } + + private function _visitNode($node) + { + $this->_nodeStates[$node->name] = self::IN_PROGRESS; + + if (isset($this->_relatedClasses[$node->name])) { + foreach ($this->_relatedClasses[$node->name] as $relatedNode) { + if ($this->_nodeStates[$relatedNode->name] == self::NOT_VISITED) { + $this->_visitNode($relatedNode); + } + } + } + + $this->_nodeStates[$node->name] = self::VISITED; + $this->_sorted[] = $node; + } + + public function addDependency($fromClass, $toClass) + { + $this->_relatedClasses[$fromClass->name][] = $toClass; + } + + public function hasClass($className) + { + return isset($this->_classes[$className]); + } + + public function addClass($class) + { + $this->_classes[$class->name] = $class; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php new file mode 100644 index 0000000..a5eae8b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -0,0 +1,390 @@ +. + */ + +namespace Doctrine\ORM\Internal\Hydration; + +use PDO, + Doctrine\DBAL\Connection, + Doctrine\DBAL\Types\Type, + Doctrine\ORM\EntityManager, + Doctrine\ORM\Events, + Doctrine\ORM\Mapping\ClassMetadata; + +/** + * Base class for all hydrators. A hydrator is a class that provides some form + * of transformation of an SQL result set into another structure. + * + * @since 2.0 + * @author Konsta Vesterinen + * @author Roman Borschel + * @author Guilherme Blanco + */ +abstract class AbstractHydrator +{ + /** @var \Doctrine\ORM\Query\ResultSetMapping The ResultSetMapping. */ + protected $_rsm; + + /** @var EntityManager The EntityManager instance. */ + protected $_em; + + /** @var \Doctrine\DBAL\Platforms\AbstractPlatform The dbms Platform instance */ + protected $_platform; + + /** @var \Doctrine\ORM\UnitOfWork The UnitOfWork of the associated EntityManager. */ + protected $_uow; + + /** @var array The cache used during row-by-row hydration. */ + protected $_cache = array(); + + /** @var \Doctrine\DBAL\Driver\Statement The statement that provides the data to hydrate. */ + protected $_stmt; + + /** @var array The query hints. */ + protected $_hints; + + /** + * Initializes a new instance of a class derived from AbstractHydrator. + * + * @param \Doctrine\ORM\EntityManager $em The EntityManager to use. + */ + public function __construct(EntityManager $em) + { + $this->_em = $em; + $this->_platform = $em->getConnection()->getDatabasePlatform(); + $this->_uow = $em->getUnitOfWork(); + } + + /** + * Initiates a row-by-row hydration. + * + * @param object $stmt + * @param object $resultSetMapping + * + * @return IterableResult + */ + public function iterate($stmt, $resultSetMapping, array $hints = array()) + { + $this->_stmt = $stmt; + $this->_rsm = $resultSetMapping; + $this->_hints = $hints; + + $evm = $this->_em->getEventManager(); + $evm->addEventListener(array(Events::onClear), $this); + + $this->prepare(); + + return new IterableResult($this); + } + + /** + * Hydrates all rows returned by the passed statement instance at once. + * + * @param object $stmt + * @param object $resultSetMapping + * @param array $hints + * @return mixed + */ + public function hydrateAll($stmt, $resultSetMapping, array $hints = array()) + { + $this->_stmt = $stmt; + $this->_rsm = $resultSetMapping; + $this->_hints = $hints; + + $this->prepare(); + + $result = $this->hydrateAllData(); + + $this->cleanup(); + + return $result; + } + + /** + * Hydrates a single row returned by the current statement instance during + * row-by-row hydration with {@link iterate()}. + * + * @return mixed + */ + public function hydrateRow() + { + $row = $this->_stmt->fetch(PDO::FETCH_ASSOC); + + if ( ! $row) { + $this->cleanup(); + + return false; + } + + $result = array(); + + $this->hydrateRowData($row, $this->_cache, $result); + + return $result; + } + + /** + * Excutes one-time preparation tasks, once each time hydration is started + * through {@link hydrateAll} or {@link iterate()}. + */ + protected function prepare() + {} + + /** + * Excutes one-time cleanup tasks at the end of a hydration that was initiated + * through {@link hydrateAll} or {@link iterate()}. + */ + protected function cleanup() + { + $this->_rsm = null; + + $this->_stmt->closeCursor(); + $this->_stmt = null; + } + + /** + * Hydrates a single row from the current statement instance. + * + * Template method. + * + * @param array $data The row data. + * @param array $cache The cache to use. + * @param mixed $result The result to fill. + */ + protected function hydrateRowData(array $data, array &$cache, array &$result) + { + throw new HydrationException("hydrateRowData() not implemented by this hydrator."); + } + + /** + * Hydrates all rows from the current statement instance at once. + */ + abstract protected function hydrateAllData(); + + /** + * Processes a row of the result set. + * + * Used for identity-based hydration (HYDRATE_OBJECT and HYDRATE_ARRAY). + * Puts the elements of a result row into a new array, grouped by the dql alias + * they belong to. The column names in the result set are mapped to their + * field names during this procedure as well as any necessary conversions on + * the values applied. Scalar values are kept in a specfic key 'scalars'. + * + * @param array $data SQL Result Row + * @param array &$cache Cache for column to field result information + * @param array &$id Dql-Alias => ID-Hash + * @param array &$nonemptyComponents Does this DQL-Alias has at least one non NULL value? + * + * @return array An array with all the fields (name => value) of the data row, + * grouped by their component alias. + */ + protected function gatherRowData(array $data, array &$cache, array &$id, array &$nonemptyComponents) + { + $rowData = array(); + + foreach ($data as $key => $value) { + // Parse each column name only once. Cache the results. + if ( ! isset($cache[$key])) { + switch (true) { + // NOTE: Most of the times it's a field mapping, so keep it first!!! + case (isset($this->_rsm->fieldMappings[$key])): + $fieldName = $this->_rsm->fieldMappings[$key]; + $classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]); + + $cache[$key]['fieldName'] = $fieldName; + $cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']); + $cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName); + $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; + break; + + case (isset($this->_rsm->scalarMappings[$key])): + $cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key]; + $cache[$key]['type'] = Type::getType($this->_rsm->typeMappings[$key]); + $cache[$key]['isScalar'] = true; + break; + + case (isset($this->_rsm->metaMappings[$key])): + // Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns). + $fieldName = $this->_rsm->metaMappings[$key]; + $classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$this->_rsm->columnOwnerMap[$key]]); + + $cache[$key]['isMetaColumn'] = true; + $cache[$key]['fieldName'] = $fieldName; + $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; + $cache[$key]['isIdentifier'] = isset($this->_rsm->isIdentifierColumn[$cache[$key]['dqlAlias']][$key]); + break; + + default: + // this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2 + // maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping. + continue 2; + } + } + + if (isset($cache[$key]['isScalar'])) { + $value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform); + + $rowData['scalars'][$cache[$key]['fieldName']] = $value; + + continue; + } + + $dqlAlias = $cache[$key]['dqlAlias']; + + if ($cache[$key]['isIdentifier']) { + $id[$dqlAlias] .= '|' . $value; + } + + if (isset($cache[$key]['isMetaColumn'])) { + if ( ! isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) && $value !== null) { + $rowData[$dqlAlias][$cache[$key]['fieldName']] = $value; + if ($cache[$key]['isIdentifier']) { + $nonemptyComponents[$dqlAlias] = true; + } + } + + continue; + } + + // in an inheritance hierarchy the same field could be defined several times. + // We overwrite this value so long we dont have a non-null value, that value we keep. + // Per definition it cannot be that a field is defined several times and has several values. + if (isset($rowData[$dqlAlias][$cache[$key]['fieldName']]) && $value === null) { + continue; + } + + $rowData[$dqlAlias][$cache[$key]['fieldName']] = $cache[$key]['type']->convertToPHPValue($value, $this->_platform); + + if ( ! isset($nonemptyComponents[$dqlAlias]) && $value !== null) { + $nonemptyComponents[$dqlAlias] = true; + } + } + + return $rowData; + } + + /** + * Processes a row of the result set. + * + * Used for HYDRATE_SCALAR. This is a variant of _gatherRowData() that + * simply converts column names to field names and properly converts the + * values according to their types. The resulting row has the same number + * of elements as before. + * + * @param array $data + * @param array $cache + * + * @return array The processed row. + */ + protected function gatherScalarRowData(&$data, &$cache) + { + $rowData = array(); + + foreach ($data as $key => $value) { + // Parse each column name only once. Cache the results. + if ( ! isset($cache[$key])) { + switch (true) { + // NOTE: During scalar hydration, most of the times it's a scalar mapping, keep it first!!! + case (isset($this->_rsm->scalarMappings[$key])): + $cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key]; + $cache[$key]['isScalar'] = true; + break; + + case (isset($this->_rsm->fieldMappings[$key])): + $fieldName = $this->_rsm->fieldMappings[$key]; + $classMetadata = $this->_em->getClassMetadata($this->_rsm->declaringClasses[$key]); + + $cache[$key]['fieldName'] = $fieldName; + $cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']); + $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; + break; + + case (isset($this->_rsm->metaMappings[$key])): + // Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns). + $cache[$key]['isMetaColumn'] = true; + $cache[$key]['fieldName'] = $this->_rsm->metaMappings[$key]; + $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; + break; + + default: + // this column is a left over, maybe from a LIMIT query hack for example in Oracle or DB2 + // maybe from an additional column that has not been defined in a NativeQuery ResultSetMapping. + continue 2; + } + } + + $fieldName = $cache[$key]['fieldName']; + + switch (true) { + case (isset($cache[$key]['isScalar'])): + $rowData[$fieldName] = $value; + break; + + case (isset($cache[$key]['isMetaColumn'])): + $rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value; + break; + + default: + $value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform); + + $rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value; + } + } + + return $rowData; + } + + /** + * Register entity as managed in UnitOfWork. + * + * @param \Doctrine\ORM\Mapping\ClassMetadata $class + * @param object $entity + * @param array $data + * + * @todo The "$id" generation is the same of UnitOfWork#createEntity. Remove this duplication somehow + */ + protected function registerManaged(ClassMetadata $class, $entity, array $data) + { + if ($class->isIdentifierComposite) { + $id = array(); + foreach ($class->identifier as $fieldName) { + if (isset($class->associationMappings[$fieldName])) { + $id[$fieldName] = $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]; + } else { + $id[$fieldName] = $data[$fieldName]; + } + } + } else { + if (isset($class->associationMappings[$class->identifier[0]])) { + $id = array($class->identifier[0] => $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']]); + } else { + $id = array($class->identifier[0] => $data[$class->identifier[0]]); + } + } + + $this->_em->getUnitOfWork()->registerManaged($entity, $id, $data); + } + + /** + * When executed in a hydrate() loop we have to clear internal state to + * decrease memory consumption. + */ + public function onClear($eventArgs) + { + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php new file mode 100644 index 0000000..8f7178e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php @@ -0,0 +1,289 @@ +. + */ + +namespace Doctrine\ORM\Internal\Hydration; + +use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata; + +/** + * The ArrayHydrator produces a nested array "graph" that is often (not always) + * interchangeable with the corresponding object graph for read-only access. + * + * @since 2.0 + * @author Roman Borschel + * @author Guilherme Blanco + */ +class ArrayHydrator extends AbstractHydrator +{ + private $_ce = array(); + private $_rootAliases = array(); + private $_isSimpleQuery = false; + private $_identifierMap = array(); + private $_resultPointers = array(); + private $_idTemplate = array(); + private $_resultCounter = 0; + + /** + * {@inheritdoc} + */ + protected function prepare() + { + $this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1; + $this->_identifierMap = array(); + $this->_resultPointers = array(); + $this->_idTemplate = array(); + $this->_resultCounter = 0; + + foreach ($this->_rsm->aliasMap as $dqlAlias => $className) { + $this->_identifierMap[$dqlAlias] = array(); + $this->_resultPointers[$dqlAlias] = array(); + $this->_idTemplate[$dqlAlias] = ''; + } + } + + /** + * {@inheritdoc} + */ + protected function hydrateAllData() + { + $result = array(); + $cache = array(); + + while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { + $this->hydrateRowData($data, $cache, $result); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + protected function hydrateRowData(array $row, array &$cache, array &$result) + { + // 1) Initialize + $id = $this->_idTemplate; // initialize the id-memory + $nonemptyComponents = array(); + $rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents); + + // Extract scalar values. They're appended at the end. + if (isset($rowData['scalars'])) { + $scalars = $rowData['scalars']; + + unset($rowData['scalars']); + + if (empty($rowData)) { + ++$this->_resultCounter; + } + } + + // 2) Now hydrate the data found in the current row. + foreach ($rowData as $dqlAlias => $data) { + $index = false; + + if (isset($this->_rsm->parentAliasMap[$dqlAlias])) { + // It's a joined result + + $parent = $this->_rsm->parentAliasMap[$dqlAlias]; + $path = $parent . '.' . $dqlAlias; + + // missing parent data, skipping as RIGHT JOIN hydration is not supported. + if ( ! isset($nonemptyComponents[$parent]) ) { + continue; + } + + // Get a reference to the right element in the result tree. + // This element will get the associated element attached. + if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) { + $first = reset($this->_resultPointers); + // TODO: Exception if $key === null ? + $baseElement =& $this->_resultPointers[$parent][key($first)]; + } else if (isset($this->_resultPointers[$parent])) { + $baseElement =& $this->_resultPointers[$parent]; + } else { + unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 + continue; + } + + $relationAlias = $this->_rsm->relationMap[$dqlAlias]; + $relation = $this->getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias]; + + // Check the type of the relation (many or single-valued) + if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) { + $oneToOne = false; + + if (isset($nonemptyComponents[$dqlAlias])) { + if ( ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = array(); + } + + $indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]); + $index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false; + $indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false; + + if ( ! $indexExists || ! $indexIsValid) { + $element = $data; + if (isset($this->_rsm->indexByMap[$dqlAlias])) { + $baseElement[$relationAlias][$row[$this->_rsm->indexByMap[$dqlAlias]]] = $element; + } else { + $baseElement[$relationAlias][] = $element; + } + + end($baseElement[$relationAlias]); + + $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = key($baseElement[$relationAlias]); + } + } else if ( ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = array(); + } + } else { + $oneToOne = true; + + if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = null; + } else if ( ! isset($baseElement[$relationAlias])) { + $baseElement[$relationAlias] = $data; + } + } + + $coll =& $baseElement[$relationAlias]; + + if ($coll !== null) { + $this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne); + } + + } else { + // It's a root result element + + $this->_rootAliases[$dqlAlias] = true; // Mark as root + $entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0; + + // if this row has a NULL value for the root result id then make it a null result. + if ( ! isset($nonemptyComponents[$dqlAlias]) ) { + if ($this->_rsm->isMixed) { + $result[] = array($entityKey => null); + } else { + $result[] = null; + } + $resultKey = $this->_resultCounter; + ++$this->_resultCounter; + continue; + } + + // Check for an existing element + if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { + $element = $rowData[$dqlAlias]; + if ($this->_rsm->isMixed) { + $element = array($entityKey => $element); + } + + if (isset($this->_rsm->indexByMap[$dqlAlias])) { + $resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]]; + $result[$resultKey] = $element; + } else { + $resultKey = $this->_resultCounter; + $result[] = $element; + ++$this->_resultCounter; + } + + $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey; + } else { + $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; + $resultKey = $index; + /*if ($this->_rsm->isMixed) { + $result[] =& $result[$index]; + ++$this->_resultCounter; + }*/ + } + $this->updateResultPointer($result, $index, $dqlAlias, false); + } + } + + // Append scalar values to mixed result sets + if (isset($scalars)) { + if ( ! isset($resultKey) ) { + // this only ever happens when no object is fetched (scalar result only) + if (isset($this->_rsm->indexByMap['scalars'])) { + $resultKey = $row[$this->_rsm->indexByMap['scalars']]; + } else { + $resultKey = $this->_resultCounter - 1; + } + } + + foreach ($scalars as $name => $value) { + $result[$resultKey][$name] = $value; + } + } + } + + /** + * Updates the result pointer for an Entity. The result pointers point to the + * last seen instance of each Entity type. This is used for graph construction. + * + * @param array $coll The element. + * @param boolean|integer $index Index of the element in the collection. + * @param string $dqlAlias + * @param boolean $oneToOne Whether it is a single-valued association or not. + */ + private function updateResultPointer(array &$coll, $index, $dqlAlias, $oneToOne) + { + if ($coll === null) { + unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 + + return; + } + + if ($index !== false) { + $this->_resultPointers[$dqlAlias] =& $coll[$index]; + + return; + } + + if ( ! $coll) { + return; + } + + if ($oneToOne) { + $this->_resultPointers[$dqlAlias] =& $coll; + + return; + } + + end($coll); + $this->_resultPointers[$dqlAlias] =& $coll[key($coll)]; + + return; + } + + /** + * Retrieve ClassMetadata associated to entity class name. + * + * @param string $className + * + * @return \Doctrine\ORM\Mapping\ClassMetadata + */ + private function getClassMetadata($className) + { + if ( ! isset($this->_ce[$className])) { + $this->_ce[$className] = $this->_em->getClassMetadata($className); + } + + return $this->_ce[$className]; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/HydrationException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/HydrationException.php new file mode 100644 index 0000000..2acc332 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/HydrationException.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\ORM\Internal\Hydration; + +/** + * Represents a result structure that can be iterated over, hydrating row-by-row + * during the iteration. An IterableResult is obtained by AbstractHydrator#iterate(). + * + * @author robo + * @since 2.0 + */ +class IterableResult implements \Iterator +{ + /** + * @var \Doctrine\ORM\Internal\Hydration\AbstractHydrator + */ + private $_hydrator; + + /** + * @var boolean + */ + private $_rewinded = false; + + /** + * @var integer + */ + private $_key = -1; + + /** + * @var object + */ + private $_current = null; + + /** + * @param \Doctrine\ORM\Internal\Hydration\AbstractHydrator $hydrator + */ + public function __construct($hydrator) + { + $this->_hydrator = $hydrator; + } + + public function rewind() + { + if ($this->_rewinded == true) { + throw new HydrationException("Can only iterate a Result once."); + } else { + $this->_current = $this->next(); + $this->_rewinded = true; + } + } + + /** + * Gets the next set of results. + * + * @return array + */ + public function next() + { + $this->_current = $this->_hydrator->hydrateRow(); + $this->_key++; + return $this->_current; + } + + /** + * @return mixed + */ + public function current() + { + return $this->_current; + } + + /** + * @return int + */ + public function key() + { + return $this->_key; + } + + /** + * @return bool + */ + public function valid() + { + return ($this->_current!=false); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php new file mode 100644 index 0000000..3f48f86 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php @@ -0,0 +1,551 @@ +. + */ + +namespace Doctrine\ORM\Internal\Hydration; + +use PDO, + Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\PersistentCollection, + Doctrine\ORM\Query, + Doctrine\ORM\Event\LifecycleEventArgs, + Doctrine\ORM\Events, + Doctrine\Common\Collections\ArrayCollection, + Doctrine\Common\Collections\Collection, + Doctrine\ORM\Proxy\Proxy; + +/** + * The ObjectHydrator constructs an object graph out of an SQL result set. + * + * @since 2.0 + * @author Roman Borschel + * @author Guilherme Blanco + * + * @internal Highly performance-sensitive code. + */ +class ObjectHydrator extends AbstractHydrator +{ + /* Local ClassMetadata cache to avoid going to the EntityManager all the time. + * This local cache is maintained between hydration runs and not cleared. + */ + private $_ce = array(); + + /* The following parts are reinitialized on every hydration run. */ + + private $_identifierMap; + private $_resultPointers; + private $_idTemplate; + private $_resultCounter; + private $_rootAliases = array(); + private $_initializedCollections = array(); + private $_existingCollections = array(); + + + /** @override */ + protected function prepare() + { + $this->_identifierMap = + $this->_resultPointers = + $this->_idTemplate = array(); + + $this->_resultCounter = 0; + + if ( ! isset($this->_hints['deferEagerLoad'])) { + $this->_hints['deferEagerLoad'] = true; + } + + foreach ($this->_rsm->aliasMap as $dqlAlias => $className) { + $this->_identifierMap[$dqlAlias] = array(); + $this->_idTemplate[$dqlAlias] = ''; + + if ( ! isset($this->_ce[$className])) { + $this->_ce[$className] = $this->_em->getClassMetadata($className); + } + + // Remember which associations are "fetch joined", so that we know where to inject + // collection stubs or proxies and where not. + if ( ! isset($this->_rsm->relationMap[$dqlAlias])) { + continue; + } + + if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) { + throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]); + } + + $sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]]; + $sourceClass = $this->_getClassMetadata($sourceClassName); + $assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]]; + + $this->_hints['fetched'][$this->_rsm->parentAliasMap[$dqlAlias]][$assoc['fieldName']] = true; + + if ($assoc['type'] === ClassMetadata::MANY_TO_MANY) { + continue; + } + + // Mark any non-collection opposite sides as fetched, too. + if ($assoc['mappedBy']) { + $this->_hints['fetched'][$dqlAlias][$assoc['mappedBy']] = true; + + continue; + } + + // handle fetch-joined owning side bi-directional one-to-one associations + if ($assoc['inversedBy']) { + $class = $this->_ce[$className]; + $inverseAssoc = $class->associationMappings[$assoc['inversedBy']]; + + if ( ! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) { + continue; + } + + $this->_hints['fetched'][$dqlAlias][$inverseAssoc['fieldName']] = true; + } + } + } + + /** + * {@inheritdoc} + */ + protected function cleanup() + { + $eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true; + + parent::cleanup(); + + $this->_identifierMap = + $this->_initializedCollections = + $this->_existingCollections = + $this->_resultPointers = array(); + + if ($eagerLoad) { + $this->_em->getUnitOfWork()->triggerEagerLoads(); + } + } + + /** + * {@inheritdoc} + */ + protected function hydrateAllData() + { + $result = array(); + $cache = array(); + + while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { + $this->hydrateRowData($row, $cache, $result); + } + + // Take snapshots from all newly initialized collections + foreach ($this->_initializedCollections as $coll) { + $coll->takeSnapshot(); + } + + return $result; + } + + /** + * Initializes a related collection. + * + * @param object $entity The entity to which the collection belongs. + * @param ClassMetadata $class + * @param string $fieldName The name of the field on the entity that holds the collection. + * @param string $parentDqlAlias Alias of the parent fetch joining this collection. + */ + private function _initRelatedCollection($entity, $class, $fieldName, $parentDqlAlias) + { + $oid = spl_object_hash($entity); + $relation = $class->associationMappings[$fieldName]; + $value = $class->reflFields[$fieldName]->getValue($entity); + + if ($value === null) { + $value = new ArrayCollection; + } + + if ( ! $value instanceof PersistentCollection) { + $value = new PersistentCollection( + $this->_em, $this->_ce[$relation['targetEntity']], $value + ); + $value->setOwner($entity, $relation); + + $class->reflFields[$fieldName]->setValue($entity, $value); + $this->_uow->setOriginalEntityProperty($oid, $fieldName, $value); + + $this->_initializedCollections[$oid . $fieldName] = $value; + } else if ( + isset($this->_hints[Query::HINT_REFRESH]) || + isset($this->_hints['fetched'][$parentDqlAlias][$fieldName]) && + ! $value->isInitialized() + ) { + // Is already PersistentCollection, but either REFRESH or FETCH-JOIN and UNINITIALIZED! + $value->setDirty(false); + $value->setInitialized(true); + $value->unwrap()->clear(); + + $this->_initializedCollections[$oid . $fieldName] = $value; + } else { + // Is already PersistentCollection, and DON'T REFRESH or FETCH-JOIN! + $this->_existingCollections[$oid . $fieldName] = $value; + } + + return $value; + } + + /** + * Gets an entity instance. + * + * @param array $data The instance data. + * @param string $dqlAlias The DQL alias of the entity's class. + * @return object The entity. + */ + private function _getEntity(array $data, $dqlAlias) + { + $className = $this->_rsm->aliasMap[$dqlAlias]; + + if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) { + + if ( ! isset($this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]])) { + throw HydrationException::missingDiscriminatorMetaMappingColumn($className, $this->_rsm->discriminatorColumns[$dqlAlias], $dqlAlias); + } + + $discrColumn = $this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]]; + + if ( ! isset($data[$discrColumn])) { + throw HydrationException::missingDiscriminatorColumn($className, $discrColumn, $dqlAlias); + } + + if ($data[$discrColumn] === "") { + throw HydrationException::emptyDiscriminatorValue($dqlAlias); + } + + $className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]]; + + unset($data[$discrColumn]); + } + + if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->_rootAliases[$dqlAlias])) { + $this->registerManaged($this->_ce[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data); + } + + $this->_hints['fetchAlias'] = $dqlAlias; + + return $this->_uow->createEntity($className, $data, $this->_hints); + } + + /** + * @param string $className + * @param array $data + * @return mixed + */ + private function _getEntityFromIdentityMap($className, array $data) + { + // TODO: Abstract this code and UnitOfWork::createEntity() equivalent? + $class = $this->_ce[$className]; + + /* @var $class ClassMetadata */ + if ($class->isIdentifierComposite) { + $idHash = ''; + foreach ($class->identifier as $fieldName) { + if (isset($class->associationMappings[$fieldName])) { + $idHash .= $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']] . ' '; + } else { + $idHash .= $data[$fieldName] . ' '; + } + } + return $this->_uow->tryGetByIdHash(rtrim($idHash), $class->rootEntityName); + } else if (isset($class->associationMappings[$class->identifier[0]])) { + return $this->_uow->tryGetByIdHash($data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']], $class->rootEntityName); + } else { + return $this->_uow->tryGetByIdHash($data[$class->identifier[0]], $class->rootEntityName); + } + } + + /** + * Gets a ClassMetadata instance from the local cache. + * If the instance is not yet in the local cache, it is loaded into the + * local cache. + * + * @param string $className The name of the class. + * @return ClassMetadata + */ + private function _getClassMetadata($className) + { + if ( ! isset($this->_ce[$className])) { + $this->_ce[$className] = $this->_em->getClassMetadata($className); + } + + return $this->_ce[$className]; + } + + /** + * Hydrates a single row in an SQL result set. + * + * @internal + * First, the data of the row is split into chunks where each chunk contains data + * that belongs to a particular component/class. Afterwards, all these chunks + * are processed, one after the other. For each chunk of class data only one of the + * following code paths is executed: + * + * Path A: The data chunk belongs to a joined/associated object and the association + * is collection-valued. + * Path B: The data chunk belongs to a joined/associated object and the association + * is single-valued. + * Path C: The data chunk belongs to a root result element/object that appears in the topmost + * level of the hydrated result. A typical example are the objects of the type + * specified by the FROM clause in a DQL query. + * + * @param array $row The data of the row to process. + * @param array $cache The cache to use. + * @param array $result The result array to fill. + */ + protected function hydrateRowData(array $row, array &$cache, array &$result) + { + // Initialize + $id = $this->_idTemplate; // initialize the id-memory + $nonemptyComponents = array(); + // Split the row data into chunks of class data. + $rowData = $this->gatherRowData($row, $cache, $id, $nonemptyComponents); + + // Extract scalar values. They're appended at the end. + if (isset($rowData['scalars'])) { + $scalars = $rowData['scalars']; + + unset($rowData['scalars']); + + if (empty($rowData)) { + ++$this->_resultCounter; + } + } + + // Hydrate the data chunks + foreach ($rowData as $dqlAlias => $data) { + $entityName = $this->_rsm->aliasMap[$dqlAlias]; + + if (isset($this->_rsm->parentAliasMap[$dqlAlias])) { + // It's a joined result + + $parentAlias = $this->_rsm->parentAliasMap[$dqlAlias]; + // we need the $path to save into the identifier map which entities were already + // seen for this parent-child relationship + $path = $parentAlias . '.' . $dqlAlias; + + // We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs + if ( ! isset($nonemptyComponents[$parentAlias])) { + // TODO: Add special case code where we hydrate the right join objects into identity map at least + continue; + } + + // Get a reference to the parent object to which the joined element belongs. + if ($this->_rsm->isMixed && isset($this->_rootAliases[$parentAlias])) { + $first = reset($this->_resultPointers); + $parentObject = $first[key($first)]; + } else if (isset($this->_resultPointers[$parentAlias])) { + $parentObject = $this->_resultPointers[$parentAlias]; + } else { + // Parent object of relation not found, so skip it. + continue; + } + + $parentClass = $this->_ce[$this->_rsm->aliasMap[$parentAlias]]; + $oid = spl_object_hash($parentObject); + $relationField = $this->_rsm->relationMap[$dqlAlias]; + $relation = $parentClass->associationMappings[$relationField]; + $reflField = $parentClass->reflFields[$relationField]; + + // Check the type of the relation (many or single-valued) + if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) { + $reflFieldValue = $reflField->getValue($parentObject); + // PATH A: Collection-valued association + if (isset($nonemptyComponents[$dqlAlias])) { + $collKey = $oid . $relationField; + if (isset($this->_initializedCollections[$collKey])) { + $reflFieldValue = $this->_initializedCollections[$collKey]; + } else if ( ! isset($this->_existingCollections[$collKey])) { + $reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias); + } + + $indexExists = isset($this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]]); + $index = $indexExists ? $this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] : false; + $indexIsValid = $index !== false ? isset($reflFieldValue[$index]) : false; + + if ( ! $indexExists || ! $indexIsValid) { + if (isset($this->_existingCollections[$collKey])) { + // Collection exists, only look for the element in the identity map. + if ($element = $this->_getEntityFromIdentityMap($entityName, $data)) { + $this->_resultPointers[$dqlAlias] = $element; + } else { + unset($this->_resultPointers[$dqlAlias]); + } + } else { + $element = $this->_getEntity($data, $dqlAlias); + + if (isset($this->_rsm->indexByMap[$dqlAlias])) { + $indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]]; + $reflFieldValue->hydrateSet($indexValue, $element); + $this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue; + } else { + $reflFieldValue->hydrateAdd($element); + $reflFieldValue->last(); + $this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $reflFieldValue->key(); + } + // Update result pointer + $this->_resultPointers[$dqlAlias] = $element; + } + } else { + // Update result pointer + $this->_resultPointers[$dqlAlias] = $reflFieldValue[$index]; + } + } else if ( ! $reflFieldValue) { + $reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias); + } else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) { + $reflFieldValue->setInitialized(true); + } + + } else { + // PATH B: Single-valued association + $reflFieldValue = $reflField->getValue($parentObject); + if ( ! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && !$reflFieldValue->__isInitialized__)) { + // we only need to take action if this value is null, + // we refresh the entity or its an unitialized proxy. + if (isset($nonemptyComponents[$dqlAlias])) { + $element = $this->_getEntity($data, $dqlAlias); + $reflField->setValue($parentObject, $element); + $this->_uow->setOriginalEntityProperty($oid, $relationField, $element); + $targetClass = $this->_ce[$relation['targetEntity']]; + + if ($relation['isOwningSide']) { + //TODO: Just check hints['fetched'] here? + // If there is an inverse mapping on the target class its bidirectional + if ($relation['inversedBy']) { + $inverseAssoc = $targetClass->associationMappings[$relation['inversedBy']]; + if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) { + $targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($element, $parentObject); + $this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc['fieldName'], $parentObject); + } + } else if ($parentClass === $targetClass && $relation['mappedBy']) { + // Special case: bi-directional self-referencing one-one on the same class + $targetClass->reflFields[$relationField]->setValue($element, $parentObject); + } + } else { + // For sure bidirectional, as there is no inverse side in unidirectional mappings + $targetClass->reflFields[$relation['mappedBy']]->setValue($element, $parentObject); + $this->_uow->setOriginalEntityProperty(spl_object_hash($element), $relation['mappedBy'], $parentObject); + } + // Update result pointer + $this->_resultPointers[$dqlAlias] = $element; + } else { + $this->_uow->setOriginalEntityProperty($oid, $relationField, null); + $reflField->setValue($parentObject, null); + } + // else leave $reflFieldValue null for single-valued associations + } else { + // Update result pointer + $this->_resultPointers[$dqlAlias] = $reflFieldValue; + } + } + } else { + // PATH C: Its a root result element + $this->_rootAliases[$dqlAlias] = true; // Mark as root alias + $entityKey = $this->_rsm->entityMappings[$dqlAlias] ?: 0; + + // if this row has a NULL value for the root result id then make it a null result. + if ( ! isset($nonemptyComponents[$dqlAlias]) ) { + if ($this->_rsm->isMixed) { + $result[] = array($entityKey => null); + } else { + $result[] = null; + } + $resultKey = $this->_resultCounter; + ++$this->_resultCounter; + continue; + } + + // check for existing result from the iterations before + if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { + $element = $this->_getEntity($rowData[$dqlAlias], $dqlAlias); + if ($this->_rsm->isMixed) { + $element = array($entityKey => $element); + } + + if (isset($this->_rsm->indexByMap[$dqlAlias])) { + $resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]]; + + if (isset($this->_hints['collection'])) { + $this->_hints['collection']->hydrateSet($resultKey, $element); + } + + $result[$resultKey] = $element; + } else { + $resultKey = $this->_resultCounter; + ++$this->_resultCounter; + + if (isset($this->_hints['collection'])) { + $this->_hints['collection']->hydrateAdd($element); + } + + $result[] = $element; + } + + $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey; + + // Update result pointer + $this->_resultPointers[$dqlAlias] = $element; + + } else { + // Update result pointer + $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; + $this->_resultPointers[$dqlAlias] = $result[$index]; + $resultKey = $index; + /*if ($this->_rsm->isMixed) { + $result[] = $result[$index]; + ++$this->_resultCounter; + }*/ + } + } + } + + // Append scalar values to mixed result sets + if (isset($scalars)) { + if ( ! isset($resultKey) ) { + if (isset($this->_rsm->indexByMap['scalars'])) { + $resultKey = $row[$this->_rsm->indexByMap['scalars']]; + } else { + $resultKey = $this->_resultCounter - 1; + } + } + + foreach ($scalars as $name => $value) { + $result[$resultKey][$name] = $value; + } + } + } + + /** + * When executed in a hydrate() loop we may have to clear internal state to + * decrease memory consumption. + */ + public function onClear($eventArgs) + { + parent::onClear($eventArgs); + + $aliases = array_keys($this->_identifierMap); + $this->_identifierMap = array(); + + foreach ($aliases as $alias) { + $this->_identifierMap[$alias] = array(); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ScalarHydrator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ScalarHydrator.php new file mode 100644 index 0000000..23b0abe --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ScalarHydrator.php @@ -0,0 +1,55 @@ +. + */ + +namespace Doctrine\ORM\Internal\Hydration; + +/** + * Hydrator that produces flat, rectangular results of scalar data. + * The created result is almost the same as a regular SQL result set, except + * that column names are mapped to field names and data type conversions take place. + * + * @since 2.0 + * @author Roman Borschel + * @author Guilherme Blanco + */ +class ScalarHydrator extends AbstractHydrator +{ + /** + * {@inheritdoc} + */ + protected function hydrateAllData() + { + $result = array(); + $cache = array(); + + while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) { + $this->hydrateRowData($data, $cache, $result); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + protected function hydrateRowData(array $data, array &$cache, array &$result) + { + $result[] = $this->gatherScalarRowData($data, $cache); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php new file mode 100644 index 0000000..8f8ed4b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php @@ -0,0 +1,187 @@ +. + */ + +namespace Doctrine\ORM\Internal\Hydration; + +use \PDO, + Doctrine\DBAL\Types\Type, + Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\Event\LifecycleEventArgs, + Doctrine\ORM\Events, + Doctrine\ORM\Query; + +class SimpleObjectHydrator extends AbstractHydrator +{ + /** + * @var ClassMetadata + */ + private $class; + + /** + * @var array + */ + private $declaringClasses = array(); + + /** + * {@inheritdoc} + */ + protected function hydrateAllData() + { + $result = array(); + $cache = array(); + + while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { + $this->hydrateRowData($row, $cache, $result); + } + + $this->_em->getUnitOfWork()->triggerEagerLoads(); + + return $result; + } + + /** + * {@inheritdoc} + */ + protected function prepare() + { + if (count($this->_rsm->aliasMap) !== 1) { + throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result."); + } + + if ($this->_rsm->scalarMappings) { + throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings."); + } + + $this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap)); + + // We only need to add declaring classes if we have inheritance. + if ($this->class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_NONE) { + return; + } + + foreach ($this->_rsm->declaringClasses as $column => $class) { + $this->declaringClasses[$column] = $this->_em->getClassMetadata($class); + } + } + + /** + * {@inheritdoc} + */ + protected function hydrateRowData(array $sqlResult, array &$cache, array &$result) + { + $entityName = $this->class->name; + $data = array(); + + // We need to find the correct entity class name if we have inheritance in resultset + if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { + $discrColumnName = $this->_platform->getSQLResultCasing($this->class->discriminatorColumn['name']); + + if ( ! isset($sqlResult[$discrColumnName])) { + throw HydrationException::missingDiscriminatorColumn($entityName, $discrColumnName, key($this->_rsm->aliasMap)); + } + + if ($sqlResult[$discrColumnName] === '') { + throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap)); + } + + $entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]]; + + unset($sqlResult[$discrColumnName]); + } + + foreach ($sqlResult as $column => $value) { + // Hydrate column information if not yet present + if ( ! isset($cache[$column])) { + if (($info = $this->hydrateColumnInfo($entityName, $column)) === null) { + continue; + } + + $cache[$column] = $info; + } + + // Convert field to a valid PHP value + if (isset($cache[$column]['field'])) { + $type = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type']); + $value = $type->convertToPHPValue($value, $this->_platform); + } + + // Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator) + if (isset($cache[$column]) && ( ! isset($data[$cache[$column]['name']]) || $value !== null)) { + $data[$cache[$column]['name']] = $value; + } + } + + if (isset($this->_hints[Query::HINT_REFRESH_ENTITY])) { + $this->registerManaged($this->class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data); + } + + $uow = $this->_em->getUnitOfWork(); + $entity = $uow->createEntity($entityName, $data, $this->_hints); + + $result[] = $entity; + } + + /** + * Retrieve column information form ResultSetMapping. + * + * @param string $entityName + * @param string $column + * + * @return array + */ + protected function hydrateColumnInfo($entityName, $column) + { + switch (true) { + case (isset($this->_rsm->fieldMappings[$column])): + $class = isset($this->declaringClasses[$column]) + ? $this->declaringClasses[$column] + : $this->class; + + // If class is not part of the inheritance, ignore + if ( ! ($class->name === $entityName || is_subclass_of($entityName, $class->name))) { + return null; + } + + return array( + 'class' => $class, + 'name' => $this->_rsm->fieldMappings[$column], + 'field' => true, + ); + + case (isset($this->_rsm->relationMap[$column])): + $class = isset($this->_rsm->relationMap[$column]) + ? $this->_rsm->relationMap[$column] + : $this->class; + + // If class is not self referencing, ignore + if ( ! ($class === $entityName || is_subclass_of($entityName, $class))) { + return null; + } + + // TODO: Decide what to do with associations. It seems original code is incomplete. + // One solution is to load the association, but it might require extra efforts. + return array('name' => $column); + + default: + return array( + 'name' => $this->_rsm->metaMappings[$column] + ); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php new file mode 100644 index 0000000..a23c4ce --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\ORM\Internal\Hydration; + +use Doctrine\DBAL\Connection, + Doctrine\ORM\NoResultException, + Doctrine\ORM\NonUniqueResultException; + +/** + * Hydrator that hydrates a single scalar value from the result set. + * + * @since 2.0 + * @author Roman Borschel + * @author Guilherme Blanco + */ +class SingleScalarHydrator extends AbstractHydrator +{ + /** + * {@inheritdoc} + */ + protected function hydrateAllData() + { + $data = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC); + $numRows = count($data); + + if ($numRows === 0) { + throw new NoResultException(); + } + + if ($numRows > 1 || count($data[key($data)]) > 1) { + throw new NonUniqueResultException(); + } + + $cache = array(); + $result = $this->gatherScalarRowData($data[key($data)], $cache); + + return array_shift($result); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Annotation.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Annotation.php new file mode 100644 index 0000000..19374ff --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Annotation.php @@ -0,0 +1,24 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +interface Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AssociationOverride.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AssociationOverride.php new file mode 100644 index 0000000..8776be6 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AssociationOverride.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * This annotation is used to override association mapping of property for an entity relationship. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("ANNOTATION") + */ +final class AssociationOverride implements Annotation +{ + + /** + * The name of the relationship property whose mapping is being overridden + * + * @var string + */ + public $name; + + /** + * The join column that is being mapped to the persistent attribute. + * + * @var array<\Doctrine\ORM\Mapping\JoinColumn> + */ + public $joinColumns; + + + /** + * The join table that maps the relationship. + * + * @var \Doctrine\ORM\Mapping\JoinTable + */ + public $joinTable; + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AssociationOverrides.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AssociationOverrides.php new file mode 100644 index 0000000..b0a0c13 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AssociationOverrides.php @@ -0,0 +1,41 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * This annotation is used to override association mappings of relationship properties. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("CLASS") + */ +final class AssociationOverrides implements Annotation +{ + + /** + * Mapping overrides of relationship properties + * + * @var array<\Doctrine\ORM\Mapping\AssociationOverride> + */ + public $value; + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AttributeOverride.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AttributeOverride.php new file mode 100644 index 0000000..ef9e6dd --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AttributeOverride.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * This annotation is used to override the mapping of a entity property. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("ANNOTATION") + */ +final class AttributeOverride implements Annotation +{ + + /** + * The name of the property whose mapping is being overridden. + * + * @var string + */ + public $name; + + /** + * The column definition. + * + * @var \Doctrine\ORM\Mapping\Column + */ + public $column; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AttributeOverrides.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AttributeOverrides.php new file mode 100644 index 0000000..41f680d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/AttributeOverrides.php @@ -0,0 +1,41 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * This annotation is used to override the mapping of a entity property. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("CLASS") + */ +final class AttributeOverrides implements Annotation +{ + + /** + * One or more field or property mapping overrides. + * + * @var array<\Doctrine\ORM\Mapping\AttributeOverride> + */ + public $value; + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php new file mode 100644 index 0000000..d540774 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php @@ -0,0 +1,167 @@ +. + */ + + +namespace Doctrine\ORM\Mapping\Builder; + +use Doctrine\ORM\Mapping\ClassMetadata; + +class AssociationBuilder +{ + /** + * @var ClassMetadataBuilder + */ + protected $builder; + + /** + * @var array + */ + protected $mapping; + + /** + * @var array + */ + protected $joinColumns; + + /** + * + * @var int + */ + protected $type; + + /** + * @param ClassMetadataBuilder $builder + * @param array $mapping + */ + public function __construct(ClassMetadataBuilder $builder, array $mapping, $type) + { + $this->builder = $builder; + $this->mapping = $mapping; + $this->type = $type; + } + + public function mappedBy($fieldName) + { + $this->mapping['mappedBy'] = $fieldName; + return $this; + } + + public function inversedBy($fieldName) + { + $this->mapping['inversedBy'] = $fieldName; + return $this; + } + + public function cascadeAll() + { + $this->mapping['cascade'] = array("ALL"); + return $this; + } + + public function cascadePersist() + { + $this->mapping['cascade'][] = "persist"; + return $this; + } + + public function cascadeRemove() + { + $this->mapping['cascade'][] = "remove"; + return $this; + } + + public function cascadeMerge() + { + $this->mapping['cascade'][] = "merge"; + return $this; + } + + public function cascadeDetach() + { + $this->mapping['cascade'][] = "detach"; + return $this; + } + + public function cascadeRefresh() + { + $this->mapping['cascade'][] = "refresh"; + return $this; + } + + public function fetchExtraLazy() + { + $this->mapping['fetch'] = ClassMetadata::FETCH_EXTRA_LAZY; + return $this; + } + + public function fetchEager() + { + $this->mapping['fetch'] = ClassMetadata::FETCH_EAGER; + return $this; + } + + public function fetchLazy() + { + $this->mapping['fetch'] = ClassMetadata::FETCH_LAZY; + return $this; + } + + /** + * Add Join Columns + * + * @param string $columnName + * @param string $referencedColumnName + * @param bool $nullable + * @param bool $unique + * @param string $onDelete + * @param string $columnDef + */ + public function addJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null) + { + $this->joinColumns[] = array( + 'name' => $columnName, + 'referencedColumnName' => $referencedColumnName, + 'nullable' => $nullable, + 'unique' => $unique, + 'onDelete' => $onDelete, + 'columnDefinition' => $columnDef, + ); + return $this; + } + + /** + * @return ClassMetadataBuilder + */ + public function build() + { + $mapping = $this->mapping; + if ($this->joinColumns) { + $mapping['joinColumns'] = $this->joinColumns; + } + $cm = $this->builder->getClassMetadata(); + if ($this->type == ClassMetadata::MANY_TO_ONE) { + $cm->mapManyToOne($mapping); + } else if ($this->type == ClassMetadata::ONE_TO_ONE) { + $cm->mapOneToOne($mapping); + } else { + throw new \InvalidArgumentException("Type should be a ToOne Assocation here"); + } + return $this->builder; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php new file mode 100644 index 0000000..fb7bbc4 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php @@ -0,0 +1,470 @@ +. + */ + +namespace Doctrine\ORM\Mapping\Builder; + +use Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\Mapping\ClassMetadataInfo; + +/** + * Builder Object for ClassMetadata + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Benjamin Eberlei + * @author Guilherme Blanco + */ +class ClassMetadataBuilder +{ + /** + * @var \Doctrine\ORM\Mapping\ClassMetadataInfo + */ + private $cm; + + /** + * @param \Doctrine\ORM\Mapping\ClassMetadataInfo $cm + */ + public function __construct(ClassMetadataInfo $cm) + { + $this->cm = $cm; + } + + /** + * @return ClassMetadata + */ + public function getClassMetadata() + { + return $this->cm; + } + + /** + * Mark the class as mapped superclass. + * + * @return ClassMetadataBuilder + */ + public function setMappedSuperClass() + { + $this->cm->isMappedSuperclass = true; + + return $this; + } + + /** + * Set custom Repository class name + * + * @param string $repositoryClassName + * @return ClassMetadataBuilder + */ + public function setCustomRepositoryClass($repositoryClassName) + { + $this->cm->setCustomRepositoryClass($repositoryClassName); + + return $this; + } + + /** + * Mark class read only + * + * @return ClassMetadataBuilder + */ + public function setReadOnly() + { + $this->cm->markReadOnly(); + + return $this; + } + + /** + * Set the table name + * + * @param string $name + * @return ClassMetadataBuilder + */ + public function setTable($name) + { + $this->cm->setPrimaryTable(array('name' => $name)); + + return $this; + } + + /** + * Add Index + * + * @param array $columns + * @param string $name + * @return ClassMetadataBuilder + */ + public function addIndex(array $columns, $name) + { + if (!isset($this->cm->table['indexes'])) { + $this->cm->table['indexes'] = array(); + } + + $this->cm->table['indexes'][$name] = array('columns' => $columns); + + return $this; + } + + /** + * Add Unique Constraint + * + * @param array $columns + * @param string $name + * @return ClassMetadataBuilder + */ + public function addUniqueConstraint(array $columns, $name) + { + if ( ! isset($this->cm->table['uniqueConstraints'])) { + $this->cm->table['uniqueConstraints'] = array(); + } + + $this->cm->table['uniqueConstraints'][$name] = array('columns' => $columns); + + return $this; + } + + /** + * Add named query + * + * @param string $name + * @param string $dqlQuery + * @return ClassMetadataBuilder + */ + public function addNamedQuery($name, $dqlQuery) + { + $this->cm->addNamedQuery(array( + 'name' => $name, + 'query' => $dqlQuery, + )); + + return $this; + } + + /** + * Set class as root of a joined table inheritance hierachy. + * + * @return ClassMetadataBuilder + */ + public function setJoinedTableInheritance() + { + $this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_JOINED); + + return $this; + } + + /** + * Set class as root of a single table inheritance hierachy. + * + * @return ClassMetadataBuilder + */ + public function setSingleTableInheritance() + { + $this->cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE); + + return $this; + } + + /** + * Set the discriminator column details. + * + * @param string $name + * @param string $type + */ + public function setDiscriminatorColumn($name, $type = 'string', $length = 255) + { + $this->cm->setDiscriminatorColumn(array( + 'name' => $name, + 'type' => $type, + 'length' => $length, + )); + + return $this; + } + + /** + * Add a subclass to this inheritance hierachy. + * + * @param string $name + * @param string $class + * @return ClassMetadataBuilder + */ + public function addDiscriminatorMapClass($name, $class) + { + $this->cm->addDiscriminatorMapClass($name, $class); + + return $this; + } + + /** + * Set deferred explicit change tracking policy. + * + * @return ClassMetadataBuilder + */ + public function setChangeTrackingPolicyDeferredExplicit() + { + $this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT); + + return $this; + } + + /** + * Set notify change tracking policy. + * + * @return ClassMetadataBuilder + */ + public function setChangeTrackingPolicyNotify() + { + $this->cm->setChangeTrackingPolicy(ClassMetadata::CHANGETRACKING_NOTIFY); + + return $this; + } + + /** + * Add lifecycle event + * + * @param string $methodName + * @param string $event + * @return ClassMetadataBuilder + */ + public function addLifecycleEvent($methodName, $event) + { + $this->cm->addLifecycleCallback($methodName, $event); + + return $this; + } + + /** + * Add Field + * + * @param string $name + * @param string $type + * @param array $mapping + */ + public function addField($name, $type, array $mapping = array()) + { + $mapping['fieldName'] = $name; + $mapping['type'] = $type; + + $this->cm->mapField($mapping); + + return $this; + } + + /** + * Create a field builder. + * + * @param string $name + * @param string $type + * @return FieldBuilder + */ + public function createField($name, $type) + { + return new FieldBuilder( + $this, + array( + 'fieldName' => $name, + 'type' => $type + ) + ); + } + + /** + * Add a simple many to one association, optionally with the inversed by field. + * + * @param string $name + * @param string $targetEntity + * @param string|null $inversedBy + * @return ClassMetadataBuilder + */ + public function addManyToOne($name, $targetEntity, $inversedBy = null) + { + $builder = $this->createManyToOne($name, $targetEntity); + + if ($inversedBy) { + $builder->inversedBy($inversedBy); + } + + return $builder->build(); + } + + /** + * Create a ManyToOne Assocation Builder. + * + * Note: This method does not add the association, you have to call build() on the AssociationBuilder. + * + * @param string $name + * @param string $targetEntity + * @return AssociationBuilder + */ + public function createManyToOne($name, $targetEntity) + { + return new AssociationBuilder( + $this, + array( + 'fieldName' => $name, + 'targetEntity' => $targetEntity + ), + ClassMetadata::MANY_TO_ONE + ); + } + + /** + * Create OneToOne Assocation Builder + * + * @param string $name + * @param string $targetEntity + * @return AssociationBuilder + */ + public function createOneToOne($name, $targetEntity) + { + return new AssociationBuilder( + $this, + array( + 'fieldName' => $name, + 'targetEntity' => $targetEntity + ), + ClassMetadata::ONE_TO_ONE + ); + } + + /** + * Add simple inverse one-to-one assocation. + * + * @param string $name + * @param string $targetEntity + * @param string $mappedBy + * @return ClassMetadataBuilder + */ + public function addInverseOneToOne($name, $targetEntity, $mappedBy) + { + $builder = $this->createOneToOne($name, $targetEntity); + $builder->mappedBy($mappedBy); + + return $builder->build(); + } + + /** + * Add simple owning one-to-one assocation. + * + * @param string $name + * @param string $targetEntity + * @param string $inversedBy + * @return ClassMetadataBuilder + */ + public function addOwningOneToOne($name, $targetEntity, $inversedBy = null) + { + $builder = $this->createOneToOne($name, $targetEntity); + + if ($inversedBy) { + $builder->inversedBy($inversedBy); + } + + return $builder->build(); + } + + /** + * Create ManyToMany Assocation Builder + * + * @param string $name + * @param string $targetEntity + * @return ManyToManyAssociationBuilder + */ + public function createManyToMany($name, $targetEntity) + { + return new ManyToManyAssociationBuilder( + $this, + array( + 'fieldName' => $name, + 'targetEntity' => $targetEntity + ), + ClassMetadata::MANY_TO_MANY + ); + } + + /** + * Add a simple owning many to many assocation. + * + * @param string $name + * @param string $targetEntity + * @param string|null $inversedBy + * @return ClassMetadataBuilder + */ + public function addOwningManyToMany($name, $targetEntity, $inversedBy = null) + { + $builder = $this->createManyToMany($name, $targetEntity); + + if ($inversedBy) { + $builder->inversedBy($inversedBy); + } + + return $builder->build(); + } + + /** + * Add a simple inverse many to many assocation. + * + * @param string $name + * @param string $targetEntity + * @param string $mappedBy + * @return ClassMetadataBuilder + */ + public function addInverseManyToMany($name, $targetEntity, $mappedBy) + { + $builder = $this->createManyToMany($name, $targetEntity); + $builder->mappedBy($mappedBy); + + return $builder->build(); + } + + /** + * Create a one to many assocation builder + * + * @param string $name + * @param string $targetEntity + * @return OneToManyAssociationBuilder + */ + public function createOneToMany($name, $targetEntity) + { + return new OneToManyAssociationBuilder( + $this, + array( + 'fieldName' => $name, + 'targetEntity' => $targetEntity + ), + ClassMetadata::ONE_TO_MANY + ); + } + + /** + * Add simple OneToMany assocation. + * + * @param string $name + * @param string $targetEntity + * @param string $mappedBy + * @return ClassMetadataBuilder + */ + public function addOneToMany($name, $targetEntity, $mappedBy) + { + $builder = $this->createOneToMany($name, $targetEntity); + $builder->mappedBy($mappedBy); + + return $builder->build(); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php new file mode 100644 index 0000000..49dd54c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php @@ -0,0 +1,223 @@ +. + */ + + +namespace Doctrine\ORM\Mapping\Builder; + +/** + * Field Builder + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.2 + * @author Benjamin Eberlei + */ +class FieldBuilder +{ + /** + * @var ClassMetadataBuilder + */ + private $builder; + /** + * @var array + */ + private $mapping; + /** + * @var bool + */ + private $version; + + /** + * @var string + */ + private $generatedValue; + + /** + * @var array + */ + private $sequenceDef; + + /** + * + * @param ClassMetadataBuilder $builder + * @param array $mapping + */ + public function __construct(ClassMetadataBuilder $builder, array $mapping) + { + $this->builder = $builder; + $this->mapping = $mapping; + } + + /** + * Set length. + * + * @param int $length + * @return FieldBuilder + */ + public function length($length) + { + $this->mapping['length'] = $length; + return $this; + } + + /** + * Set nullable + * + * @param bool + * @return FieldBuilder + */ + public function nullable($flag = true) + { + $this->mapping['nullable'] = (bool)$flag; + return $this; + } + + /** + * Set Unique + * + * @param bool + * @return FieldBuilder + */ + public function unique($flag = true) + { + $this->mapping['unique'] = (bool)$flag; + return $this; + } + + /** + * Set column name + * + * @param string $name + * @return FieldBuilder + */ + public function columnName($name) + { + $this->mapping['columnName'] = $name; + return $this; + } + + /** + * Set Precision + * + * @param int $p + * @return FieldBuilder + */ + public function precision($p) + { + $this->mapping['precision'] = $p; + return $this; + } + + /** + * Set scale. + * + * @param int $s + * @return FieldBuilder + */ + public function scale($s) + { + $this->mapping['scale'] = $s; + return $this; + } + + /** + * Set field as primary key. + * + * @return FieldBuilder + */ + public function isPrimaryKey() + { + $this->mapping['id'] = true; + return $this; + } + + /** + * @param int $strategy + * @return FieldBuilder + */ + public function generatedValue($strategy = 'AUTO') + { + $this->generatedValue = $strategy; + return $this; + } + + /** + * Set field versioned + * + * @return FieldBuilder + */ + public function isVersionField() + { + $this->version = true; + return $this; + } + + /** + * Set Sequence Generator + * + * @param string $sequenceName + * @param int $allocationSize + * @param int $initialValue + * @return FieldBuilder + */ + public function setSequenceGenerator($sequenceName, $allocationSize = 1, $initialValue = 1) + { + $this->sequenceDef = array( + 'sequenceName' => $sequenceName, + 'allocationSize' => $allocationSize, + 'initialValue' => $initialValue, + ); + return $this; + } + + /** + * Set column definition. + * + * @param string $def + * @return FieldBuilder + */ + public function columnDefinition($def) + { + $this->mapping['columnDefinition'] = $def; + return $this; + } + + /** + * Finalize this field and attach it to the ClassMetadata. + * + * Without this call a FieldBuilder has no effect on the ClassMetadata. + * + * @return ClassMetadataBuilder + */ + public function build() + { + $cm = $this->builder->getClassMetadata(); + if ($this->generatedValue) { + $cm->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $this->generatedValue)); + } + if ($this->version) { + $cm->setVersionMapping($this->mapping); + } + $cm->mapField($this->mapping); + if ($this->sequenceDef) { + $cm->setSequenceGeneratorDefinition($this->sequenceDef); + } + return $this->builder; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/ManyToManyAssociationBuilder.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/ManyToManyAssociationBuilder.php new file mode 100644 index 0000000..17edeea --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/ManyToManyAssociationBuilder.php @@ -0,0 +1,86 @@ +. + */ + + +namespace Doctrine\ORM\Mapping\Builder; + +/** + * ManyToMany Association Builder + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + */ +class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder +{ + private $joinTableName; + + private $inverseJoinColumns = array(); + + public function setJoinTable($name) + { + $this->joinTableName = $name; + return $this; + } + + /** + * Add Inverse Join Columns + * + * @param string $columnName + * @param string $referencedColumnName + * @param bool $nullable + * @param bool $unique + * @param string $onDelete + * @param string $columnDef + */ + public function addInverseJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null) + { + $this->inverseJoinColumns[] = array( + 'name' => $columnName, + 'referencedColumnName' => $referencedColumnName, + 'nullable' => $nullable, + 'unique' => $unique, + 'onDelete' => $onDelete, + 'columnDefinition' => $columnDef, + ); + return $this; + } + + /** + * @return ClassMetadataBuilder + */ + public function build() + { + $mapping = $this->mapping; + $mapping['joinTable'] = array(); + if ($this->joinColumns) { + $mapping['joinTable']['joinColumns'] = $this->joinColumns; + } + if ($this->inverseJoinColumns) { + $mapping['joinTable']['inverseJoinColumns'] = $this->inverseJoinColumns; + } + if ($this->joinTableName) { + $mapping['joinTable']['name'] = $this->joinTableName; + } + $cm = $this->builder->getClassMetadata(); + $cm->mapManyToMany($mapping); + return $this->builder; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/OneToManyAssociationBuilder.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/OneToManyAssociationBuilder.php new file mode 100644 index 0000000..6f22fe2 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Builder/OneToManyAssociationBuilder.php @@ -0,0 +1,62 @@ +. + */ + + +namespace Doctrine\ORM\Mapping\Builder; + +/** + * OneToMany Association Builder + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @author Benjamin Eberlei + */ +class OneToManyAssociationBuilder extends AssociationBuilder +{ + /** + * @param array $fieldNames + * @return OneToManyAssociationBuilder + */ + public function setOrderBy(array $fieldNames) + { + $this->mapping['orderBy'] = $fieldNames; + return $this; + } + + public function setIndexBy($fieldName) + { + $this->mapping['indexBy'] = $fieldName; + return $this; + } + + /** + * @return ClassMetadataBuilder + */ + public function build() + { + $mapping = $this->mapping; + if ($this->joinColumns) { + $mapping['joinColumns'] = $this->joinColumns; + } + $cm = $this->builder->getClassMetadata(); + $cm->mapOneToMany($mapping); + return $this->builder; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php new file mode 100644 index 0000000..bab34a6 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class ChangeTrackingPolicy implements Annotation +{ + /** @var string */ + public $value; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadata.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadata.php new file mode 100644 index 0000000..a57f1e1 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadata.php @@ -0,0 +1,29 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * {@inheritDoc} + * + * @todo remove or rename ClassMetadataInfo to ClassMetadata + */ +class ClassMetadata extends ClassMetadataInfo +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php new file mode 100644 index 0000000..f79eda8 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -0,0 +1,537 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +use ReflectionException, + Doctrine\ORM\ORMException, + Doctrine\ORM\EntityManager, + Doctrine\DBAL\Platforms, + Doctrine\ORM\Events, + Doctrine\Common\Persistence\Mapping\ReflectionService, + Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface, + Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory, + Doctrine\ORM\Id\IdentityGenerator, + Doctrine\ORM\Event\LoadClassMetadataEventArgs; + +/** + * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the + * metadata mapping information of a class which describes how a class should be mapped + * to a relational database. + * + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ClassMetadataFactory extends AbstractClassMetadataFactory +{ + /** + * @var EntityManager + */ + private $em; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $targetPlatform; + + /** + * @var \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver + */ + private $driver; + + /** + * @var \Doctrine\Common\EventManager + */ + private $evm; + + /** + * @param EntityManager $em + */ + public function setEntityManager(EntityManager $em) + { + $this->em = $em; + } + + /** + * {@inheritDoc}. + */ + protected function initialize() + { + $this->driver = $this->em->getConfiguration()->getMetadataDriverImpl(); + $this->targetPlatform = $this->em->getConnection()->getDatabasePlatform(); + $this->evm = $this->em->getEventManager(); + $this->initialized = true; + } + + /** + * {@inheritDoc} + */ + protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) + { + /* @var $class ClassMetadata */ + /* @var $parent ClassMetadata */ + if ($parent) { + $class->setInheritanceType($parent->inheritanceType); + $class->setDiscriminatorColumn($parent->discriminatorColumn); + $class->setIdGeneratorType($parent->generatorType); + $this->addInheritedFields($class, $parent); + $this->addInheritedRelations($class, $parent); + $class->setIdentifier($parent->identifier); + $class->setVersioned($parent->isVersioned); + $class->setVersionField($parent->versionField); + $class->setDiscriminatorMap($parent->discriminatorMap); + $class->setLifecycleCallbacks($parent->lifecycleCallbacks); + $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); + + if ($parent->isMappedSuperclass) { + $class->setCustomRepositoryClass($parent->customRepositoryClassName); + } + } + + // Invoke driver + try { + $this->driver->loadMetadataForClass($class->getName(), $class); + } catch (ReflectionException $e) { + throw MappingException::reflectionFailure($class->getName(), $e); + } + + // If this class has a parent the id generator strategy is inherited. + // However this is only true if the hierarchy of parents contains the root entity, + // if it consists of mapped superclasses these don't necessarily include the id field. + if ($parent && $rootEntityFound) { + if ($parent->isIdGeneratorSequence()) { + $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition); + } else if ($parent->isIdGeneratorTable()) { + $class->tableGeneratorDefinition = $parent->tableGeneratorDefinition; + } + + if ($parent->generatorType) { + $class->setIdGeneratorType($parent->generatorType); + } + + if ($parent->idGenerator) { + $class->setIdGenerator($parent->idGenerator); + } + } else { + $this->completeIdGeneratorMapping($class); + } + + if ($parent && $parent->isInheritanceTypeSingleTable()) { + $class->setPrimaryTable($parent->table); + } + + if ($parent && $parent->containsForeignIdentifier) { + $class->containsForeignIdentifier = true; + } + + if ($parent && !empty($parent->namedQueries)) { + $this->addInheritedNamedQueries($class, $parent); + } + + if ($parent && !empty($parent->namedNativeQueries)) { + $this->addInheritedNamedNativeQueries($class, $parent); + } + + if ($parent && !empty($parent->sqlResultSetMappings)) { + $this->addInheritedSqlResultSetMappings($class, $parent); + } + + $class->setParentClasses($nonSuperclassParents); + + if ( $class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) { + $this->addDefaultDiscriminatorMap($class); + } + + if ($this->evm->hasListeners(Events::loadClassMetadata)) { + $eventArgs = new LoadClassMetadataEventArgs($class, $this->em); + $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); + } + + $this->wakeupReflection($class, $this->getReflectionService()); + $this->validateRuntimeMetadata($class, $parent); + } + + /** + * Validate runtime metadata is correctly defined. + * + * @param ClassMetadata $class + * @param $parent + * @throws MappingException + */ + protected function validateRuntimeMetadata($class, $parent) + { + if ( ! $class->reflClass ) { + // only validate if there is a reflection class instance + return; + } + + $class->validateIdentifier(); + $class->validateAssocations(); + $class->validateLifecycleCallbacks($this->getReflectionService()); + + // verify inheritance + if ( ! $class->isMappedSuperclass && !$class->isInheritanceTypeNone()) { + if ( ! $parent) { + if (count($class->discriminatorMap) == 0) { + throw MappingException::missingDiscriminatorMap($class->name); + } + if ( ! $class->discriminatorColumn) { + throw MappingException::missingDiscriminatorColumn($class->name); + } + } else if ($parent && !$class->reflClass->isAbstract() && !in_array($class->name, array_values($class->discriminatorMap))) { + // enforce discriminator map for all entities of an inheritance hierarchy, otherwise problems will occur. + throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name, $class->rootEntityName); + } + } else if ($class->isMappedSuperclass && $class->name == $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) { + // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy + throw MappingException::noInheritanceOnMappedSuperClass($class->name); + } + } + + /** + * {@inheritDoc} + */ + protected function newClassMetadataInstance($className) + { + return new ClassMetadata($className, $this->em->getConfiguration()->getNamingStrategy()); + } + + /** + * Adds a default discriminator map if no one is given + * + * If an entity is of any inheritance type and does not contain a + * discriminator map, then the map is generated automatically. This process + * is expensive computation wise. + * + * The automatically generated discriminator map contains the lowercase short name of + * each class as key. + * + * @param \Doctrine\ORM\Mapping\ClassMetadata $class + * @throws MappingException + */ + private function addDefaultDiscriminatorMap(ClassMetadata $class) + { + $allClasses = $this->driver->getAllClassNames(); + $fqcn = $class->getName(); + $map = array($this->getShortName($class->name) => $fqcn); + + $duplicates = array(); + foreach ($allClasses as $subClassCandidate) { + if (is_subclass_of($subClassCandidate, $fqcn)) { + $shortName = $this->getShortName($subClassCandidate); + + if (isset($map[$shortName])) { + $duplicates[] = $shortName; + } + + $map[$shortName] = $subClassCandidate; + } + } + + if ($duplicates) { + throw MappingException::duplicateDiscriminatorEntry($class->name, $duplicates, $map); + } + + $class->setDiscriminatorMap($map); + } + + /** + * Get the lower-case short name of a class. + * + * @param string $className + * @return string + */ + private function getShortName($className) + { + if (strpos($className, "\\") === false) { + return strtolower($className); + } + + $parts = explode("\\", $className); + return strtolower(end($parts)); + } + + /** + * Adds inherited fields to the subclass mapping. + * + * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass + * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass + */ + private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass) + { + foreach ($parentClass->fieldMappings as $mapping) { + if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) { + $mapping['inherited'] = $parentClass->name; + } + if ( ! isset($mapping['declared'])) { + $mapping['declared'] = $parentClass->name; + } + $subClass->addInheritedFieldMapping($mapping); + } + foreach ($parentClass->reflFields as $name => $field) { + $subClass->reflFields[$name] = $field; + } + } + + /** + * Adds inherited association mappings to the subclass mapping. + * + * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass + * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass + * @throws MappingException + */ + private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass) + { + foreach ($parentClass->associationMappings as $field => $mapping) { + if ($parentClass->isMappedSuperclass) { + if ($mapping['type'] & ClassMetadata::TO_MANY && !$mapping['isOwningSide']) { + throw MappingException::illegalToManyAssocationOnMappedSuperclass($parentClass->name, $field); + } + $mapping['sourceEntity'] = $subClass->name; + } + + //$subclassMapping = $mapping; + if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) { + $mapping['inherited'] = $parentClass->name; + } + if ( ! isset($mapping['declared'])) { + $mapping['declared'] = $parentClass->name; + } + $subClass->addInheritedAssociationMapping($mapping); + } + } + + /** + * Adds inherited named queries to the subclass mapping. + * + * @since 2.2 + * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass + * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass + */ + private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass) + { + foreach ($parentClass->namedQueries as $name => $query) { + if ( ! isset ($subClass->namedQueries[$name])) { + $subClass->addNamedQuery(array( + 'name' => $query['name'], + 'query' => $query['query'] + )); + } + } + } + + /** + * Adds inherited named native queries to the subclass mapping. + * + * @since 2.3 + * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass + * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass + */ + private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass) + { + foreach ($parentClass->namedNativeQueries as $name => $query) { + if ( ! isset ($subClass->namedNativeQueries[$name])) { + $subClass->addNamedNativeQuery(array( + 'name' => $query['name'], + 'query' => $query['query'], + 'isSelfClass' => $query['isSelfClass'], + 'resultSetMapping' => $query['resultSetMapping'], + 'resultClass' => $query['isSelfClass'] ? $subClass->name : $query['resultClass'], + )); + } + } + } + + /** + * Adds inherited sql result set mappings to the subclass mapping. + * + * @since 2.3 + * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass + * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass + */ + private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass) + { + foreach ($parentClass->sqlResultSetMappings as $name => $mapping) { + if ( ! isset ($subClass->sqlResultSetMappings[$name])) { + $entities = array(); + foreach ($mapping['entities'] as $entity) { + $entities[] = array( + 'fields' => $entity['fields'], + 'isSelfClass' => $entity['isSelfClass'], + 'discriminatorColumn' => $entity['discriminatorColumn'], + 'entityClass' => $entity['isSelfClass'] ? $subClass->name : $entity['entityClass'], + ); + } + + $subClass->addSqlResultSetMapping(array( + 'name' => $mapping['name'], + 'columns' => $mapping['columns'], + 'entities' => $entities, + )); + } + } + } + + /** + * Completes the ID generator mapping. If "auto" is specified we choose the generator + * most appropriate for the targeted database platform. + * + * @param ClassMetadataInfo $class + * @throws ORMException + */ + private function completeIdGeneratorMapping(ClassMetadataInfo $class) + { + $idGenType = $class->generatorType; + if ($idGenType == ClassMetadata::GENERATOR_TYPE_AUTO) { + if ($this->targetPlatform->prefersSequences()) { + $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_SEQUENCE); + } else if ($this->targetPlatform->prefersIdentityColumns()) { + $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY); + } else { + $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_TABLE); + } + } + + // Create & assign an appropriate ID generator instance + switch ($class->generatorType) { + case ClassMetadata::GENERATOR_TYPE_IDENTITY: + // For PostgreSQL IDENTITY (SERIAL) we need a sequence name. It defaults to + // __seq in PostgreSQL for SERIAL columns. + // Not pretty but necessary and the simplest solution that currently works. + $sequenceName = null; + + if ($this->targetPlatform instanceof Platforms\PostgreSQLPlatform) { + $fieldName = $class->getSingleIdentifierFieldName(); + $columnName = $class->getSingleIdentifierColumnName(); + $quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); + $sequenceName = $class->getTableName() . '_' . $columnName . '_seq'; + $definition = array( + 'sequenceName' => $this->targetPlatform->fixSchemaElementName($sequenceName) + ); + + if ($quoted) { + $definition['quoted'] = true; + } + + $sequenceName = $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->targetPlatform); + } + + $class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($sequenceName)); + break; + + case ClassMetadata::GENERATOR_TYPE_SEQUENCE: + // If there is no sequence definition yet, create a default definition + $definition = $class->sequenceGeneratorDefinition; + + if ( ! $definition) { + $fieldName = $class->getSingleIdentifierFieldName(); + $columnName = $class->getSingleIdentifierColumnName(); + $quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); + $sequenceName = $class->getTableName() . '_' . $columnName . '_seq'; + $definition = array( + 'sequenceName' => $this->targetPlatform->fixSchemaElementName($sequenceName), + 'allocationSize' => 1, + 'initialValue' => 1, + ); + + if ($quoted) { + $definition['quoted'] = true; + } + + $class->setSequenceGeneratorDefinition($definition); + } + + $sequenceGenerator = new \Doctrine\ORM\Id\SequenceGenerator( + $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->targetPlatform), + $definition['allocationSize'] + ); + $class->setIdGenerator($sequenceGenerator); + break; + + case ClassMetadata::GENERATOR_TYPE_NONE: + $class->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator()); + break; + + case ClassMetadata::GENERATOR_TYPE_UUID: + $class->setIdGenerator(new \Doctrine\ORM\Id\UuidGenerator()); + break; + + case ClassMetadata::GENERATOR_TYPE_TABLE: + throw new ORMException("TableGenerator not yet implemented."); + break; + + case ClassMetadata::GENERATOR_TYPE_CUSTOM: + $definition = $class->customGeneratorDefinition; + if ( ! class_exists($definition['class'])) { + throw new ORMException("Can't instantiate custom generator : " . + $definition['class']); + } + $class->setIdGenerator(new $definition['class']); + break; + + default: + throw new ORMException("Unknown generator type: " . $class->generatorType); + } + } + + /** + * {@inheritDoc} + */ + protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService) + { + /* @var $class ClassMetadata */ + $class->wakeupReflection($reflService); + } + + /** + * {@inheritDoc} + */ + protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService) + { + /* @var $class ClassMetadata */ + $class->initializeReflection($reflService); + } + + /** + * {@inheritDoc} + */ + protected function getFqcnFromAlias($namespaceAlias, $simpleClassName) + { + return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName; + } + + /** + * {@inheritDoc} + */ + protected function getDriver() + { + return $this->driver; + } + + /** + * {@inheritDoc} + */ + protected function isEntity(ClassMetadataInterface $class) + { + return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php new file mode 100644 index 0000000..0c3cac5 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -0,0 +1,2814 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +use BadMethodCallException; +use InvalidArgumentException; +use RuntimeException; +use Doctrine\DBAL\Types\Type; +use ReflectionClass; +use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\Common\ClassLoader; + +/** + * A ClassMetadata instance holds all the object-relational mapping metadata + * of an entity and it's associations. + * + * Once populated, ClassMetadata instances are usually cached in a serialized form. + * + * IMPORTANT NOTE: + * + * The fields of this class are only public for 2 reasons: + * 1) To allow fast READ access. + * 2) To drastically reduce the size of a serialized instance (private/protected members + * get the whole class name, namespace inclusive, prepended to every property in + * the serialized representation). + * + * @author Roman Borschel + * @author Jonathan H. Wage + * @since 2.0 + */ +class ClassMetadataInfo implements ClassMetadata +{ + /* The inheritance mapping types */ + /** + * NONE means the class does not participate in an inheritance hierarchy + * and therefore does not need an inheritance mapping type. + */ + const INHERITANCE_TYPE_NONE = 1; + + /** + * JOINED means the class will be persisted according to the rules of + * Class Table Inheritance. + */ + const INHERITANCE_TYPE_JOINED = 2; + + /** + * SINGLE_TABLE means the class will be persisted according to the rules of + * Single Table Inheritance. + */ + const INHERITANCE_TYPE_SINGLE_TABLE = 3; + + /** + * TABLE_PER_CLASS means the class will be persisted according to the rules + * of Concrete Table Inheritance. + */ + const INHERITANCE_TYPE_TABLE_PER_CLASS = 4; + + /* The Id generator types. */ + /** + * AUTO means the generator type will depend on what the used platform prefers. + * Offers full portability. + */ + const GENERATOR_TYPE_AUTO = 1; + + /** + * SEQUENCE means a separate sequence object will be used. Platforms that do + * not have native sequence support may emulate it. Full portability is currently + * not guaranteed. + */ + const GENERATOR_TYPE_SEQUENCE = 2; + + /** + * TABLE means a separate table is used for id generation. + * Offers full portability. + */ + const GENERATOR_TYPE_TABLE = 3; + + /** + * IDENTITY means an identity column is used for id generation. The database + * will fill in the id column on insertion. Platforms that do not support + * native identity columns may emulate them. Full portability is currently + * not guaranteed. + */ + const GENERATOR_TYPE_IDENTITY = 4; + + /** + * NONE means the class does not have a generated id. That means the class + * must have a natural, manually assigned id. + */ + const GENERATOR_TYPE_NONE = 5; + + /** + * UUID means that a UUID/GUID expression is used for id generation. Full + * portability is currently not guaranteed. + */ + const GENERATOR_TYPE_UUID = 6; + /** + * CUSTOM means that customer will use own ID generator that supposedly work + */ + const GENERATOR_TYPE_CUSTOM = 7; + /** + * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time + * by doing a property-by-property comparison with the original data. This will + * be done for all entities that are in MANAGED state at commit-time. + * + * This is the default change tracking policy. + */ + const CHANGETRACKING_DEFERRED_IMPLICIT = 1; + + /** + * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time + * by doing a property-by-property comparison with the original data. This will + * be done only for entities that were explicitly saved (through persist() or a cascade). + */ + const CHANGETRACKING_DEFERRED_EXPLICIT = 2; + + /** + * NOTIFY means that Doctrine relies on the entities sending out notifications + * when their properties change. Such entity classes must implement + * the NotifyPropertyChanged interface. + */ + const CHANGETRACKING_NOTIFY = 3; + + /** + * Specifies that an association is to be fetched when it is first accessed. + */ + const FETCH_LAZY = 2; + + /** + * Specifies that an association is to be fetched when the owner of the + * association is fetched. + */ + const FETCH_EAGER = 3; + + /** + * Specifies that an association is to be fetched lazy (on first access) and that + * commands such as Collection#count, Collection#slice are issued directly against + * the database if the collection is not yet initialized. + */ + const FETCH_EXTRA_LAZY = 4; + + /** + * Identifies a one-to-one association. + */ + const ONE_TO_ONE = 1; + + /** + * Identifies a many-to-one association. + */ + const MANY_TO_ONE = 2; + + /** + * Identifies a one-to-many association. + */ + const ONE_TO_MANY = 4; + + /** + * Identifies a many-to-many association. + */ + const MANY_TO_MANY = 8; + + /** + * Combined bitmask for to-one (single-valued) associations. + */ + const TO_ONE = 3; + + /** + * Combined bitmask for to-many (collection-valued) associations. + */ + const TO_MANY = 12; + + /** + * READ-ONLY: The name of the entity class. + */ + public $name; + + /** + * READ-ONLY: The namespace the entity class is contained in. + * + * @var string + * @todo Not really needed. Usage could be localized. + */ + public $namespace; + + /** + * READ-ONLY: The name of the entity class that is at the root of the mapped entity inheritance + * hierarchy. If the entity is not part of a mapped inheritance hierarchy this is the same + * as {@link $entityName}. + * + * @var string + */ + public $rootEntityName; + + /** + * READ-ONLY: The definition of custom generator. Only used for CUSTOM + * generator type + * + * The definition has the following structure: + * + * array( + * 'class' => 'ClassName', + * ) + * + * + * @var array + * @todo Merge with tableGeneratorDefinition into generic generatorDefinition + */ + public $customGeneratorDefinition; + + /** + * The name of the custom repository class used for the entity class. + * (Optional). + * + * @var string + */ + public $customRepositoryClassName; + + /** + * READ-ONLY: Whether this class describes the mapping of a mapped superclass. + * + * @var boolean + */ + public $isMappedSuperclass = false; + + /** + * READ-ONLY: The names of the parent classes (ancestors). + * + * @var array + */ + public $parentClasses = array(); + + /** + * READ-ONLY: The names of all subclasses (descendants). + * + * @var array + */ + public $subClasses = array(); + + /** + * READ-ONLY: The named queries allowed to be called directly from Repository. + * + * @var array + */ + public $namedQueries = array(); + + /** + * READ-ONLY: The named native queries allowed to be called directly from Repository. + * + * A native SQL named query definition has the following structure: + *
+     * array(
+     *     'name'               => ,
+     *     'query'              => ,
+     *     'resultClass'        => ,
+     *     'resultSetMapping'   => 
+     * )
+     * 
+ */ + public $namedNativeQueries = array(); + + /** + * READ-ONLY: The mappings of the results of native SQL queries. + * + * A native result mapping definition has the following structure: + *
+     * array(
+     *     'name'               => ,
+     *     'entities'           => array(),
+     *     'columns'            => array()
+     * )
+     * 
+ */ + public $sqlResultSetMappings = array(); + + /** + * READ-ONLY: The field names of all fields that are part of the identifier/primary key + * of the mapped entity class. + * + * @var array + */ + public $identifier = array(); + + /** + * READ-ONLY: The inheritance mapping type used by the class. + * + * @var integer + */ + public $inheritanceType = self::INHERITANCE_TYPE_NONE; + + /** + * READ-ONLY: The Id generator type used by the class. + * + * @var string + */ + public $generatorType = self::GENERATOR_TYPE_NONE; + + /** + * READ-ONLY: The field mappings of the class. + * Keys are field names and values are mapping definitions. + * + * The mapping definition array has the following values: + * + * - fieldName (string) + * The name of the field in the Entity. + * + * - type (string) + * The type name of the mapped field. Can be one of Doctrine's mapping types + * or a custom mapping type. + * + * - columnName (string, optional) + * The column name. Optional. Defaults to the field name. + * + * - length (integer, optional) + * The database length of the column. Optional. Default value taken from + * the type. + * + * - id (boolean, optional) + * Marks the field as the primary key of the entity. Multiple fields of an + * entity can have the id attribute, forming a composite key. + * + * - nullable (boolean, optional) + * Whether the column is nullable. Defaults to FALSE. + * + * - columnDefinition (string, optional, schema-only) + * The SQL fragment that is used when generating the DDL for the column. + * + * - precision (integer, optional, schema-only) + * The precision of a decimal column. Only valid if the column type is decimal. + * + * - scale (integer, optional, schema-only) + * The scale of a decimal column. Only valid if the column type is decimal. + * + [* - 'unique'] (string, optional, schema-only) + * Whether a unique constraint should be generated for the column. + * + * @var array + */ + public $fieldMappings = array(); + + /** + * READ-ONLY: An array of field names. Used to look up field names from column names. + * Keys are column names and values are field names. + * This is the reverse lookup map of $_columnNames. + * + * @var array + */ + public $fieldNames = array(); + + /** + * READ-ONLY: A map of field names to column names. Keys are field names and values column names. + * Used to look up column names from field names. + * This is the reverse lookup map of $_fieldNames. + * + * @var array + * @todo We could get rid of this array by just using $fieldMappings[$fieldName]['columnName']. + */ + public $columnNames = array(); + + /** + * READ-ONLY: The discriminator value of this class. + * + * This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies + * where a discriminator column is used. + * + * @var mixed + * @see discriminatorColumn + */ + public $discriminatorValue; + + /** + * READ-ONLY: The discriminator map of all mapped classes in the hierarchy. + * + * This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies + * where a discriminator column is used. + * + * @var mixed + * @see discriminatorColumn + */ + public $discriminatorMap = array(); + + /** + * READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE + * inheritance mappings. + * + * @var array + */ + public $discriminatorColumn; + + /** + * READ-ONLY: The primary table definition. The definition is an array with the + * following entries: + * + * name => + * schema => + * indexes => array + * uniqueConstraints => array + * + * @var array + */ + public $table; + + /** + * READ-ONLY: The registered lifecycle callbacks for entities of this class. + * + * @var array + */ + public $lifecycleCallbacks = array(); + + /** + * READ-ONLY: The association mappings of this class. + * + * The mapping definition array supports the following keys: + * + * - fieldName (string) + * The name of the field in the entity the association is mapped to. + * + * - targetEntity (string) + * The class name of the target entity. If it is fully-qualified it is used as is. + * If it is a simple, unqualified class name the namespace is assumed to be the same + * as the namespace of the source entity. + * + * - mappedBy (string, required for bidirectional associations) + * The name of the field that completes the bidirectional association on the owning side. + * This key must be specified on the inverse side of a bidirectional association. + * + * - inversedBy (string, required for bidirectional associations) + * The name of the field that completes the bidirectional association on the inverse side. + * This key must be specified on the owning side of a bidirectional association. + * + * - cascade (array, optional) + * The names of persistence operations to cascade on the association. The set of possible + * values are: "persist", "remove", "detach", "merge", "refresh", "all" (implies all others). + * + * - orderBy (array, one-to-many/many-to-many only) + * A map of field names (of the target entity) to sorting directions (ASC/DESC). + * Example: array('priority' => 'desc') + * + * - fetch (integer, optional) + * The fetching strategy to use for the association, usually defaults to FETCH_LAZY. + * Possible values are: ClassMetadata::FETCH_EAGER, ClassMetadata::FETCH_LAZY. + * + * - joinTable (array, optional, many-to-many only) + * Specification of the join table and its join columns (foreign keys). + * Only valid for many-to-many mappings. Note that one-to-many associations can be mapped + * through a join table by simply mapping the association as many-to-many with a unique + * constraint on the join table. + * + * - indexBy (string, optional, to-many only) + * Specification of a field on target-entity that is used to index the collection by. + * This field HAS to be either the primary key or a unique column. Otherwise the collection + * does not contain all the entities that are actually related. + * + * A join table definition has the following structure: + *
+     * array(
+     *     'name' => ,
+     *      'joinColumns' => array(),
+     *      'inverseJoinColumns' => array()
+     * )
+     * 
+ * + * + * @var array + */ + public $associationMappings = array(); + + /** + * READ-ONLY: Flag indicating whether the identifier/primary key of the class is composite. + * + * @var boolean + */ + public $isIdentifierComposite = false; + + /** + * READ-ONLY: Flag indicating wheather the identifier/primary key contains at least one foreign key association. + * + * This flag is necessary because some code blocks require special treatment of this cases. + * + * @var boolean + */ + public $containsForeignIdentifier = false; + + /** + * READ-ONLY: The ID generator used for generating IDs for this class. + * + * @var \Doctrine\ORM\Id\AbstractIdGenerator + * @todo Remove! + */ + public $idGenerator; + + /** + * READ-ONLY: The definition of the sequence generator of this class. Only used for the + * SEQUENCE generation strategy. + * + * The definition has the following structure: + * + * array( + * 'sequenceName' => 'name', + * 'allocationSize' => 20, + * 'initialValue' => 1 + * ) + * + * + * @var array + * @todo Merge with tableGeneratorDefinition into generic generatorDefinition + */ + public $sequenceGeneratorDefinition; + + /** + * READ-ONLY: The definition of the table generator of this class. Only used for the + * TABLE generation strategy. + * + * @var array + * @todo Merge with tableGeneratorDefinition into generic generatorDefinition + */ + public $tableGeneratorDefinition; + + /** + * READ-ONLY: The policy used for change-tracking on entities of this class. + * + * @var integer + */ + public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT; + + /** + * READ-ONLY: A flag for whether or not instances of this class are to be versioned + * with optimistic locking. + * + * @var boolean $isVersioned + */ + public $isVersioned; + + /** + * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any). + * + * @var mixed $versionField + */ + public $versionField; + + /** + * The ReflectionClass instance of the mapped class. + * + * @var ReflectionClass + */ + public $reflClass; + + /** + * Is this entity marked as "read-only"? + * + * That means it is never considered for change-tracking in the UnitOfWork. It is a very helpful performance + * optimization for entities that are immutable, either in your domain or through the relation database + * (coming from a view, or a history table for example). + * + * @var bool + */ + public $isReadOnly = false; + + /** + * NamingStrategy determining the default column and table names + * + * @var \Doctrine\ORM\Mapping\NamingStrategy + */ + protected $namingStrategy; + + /** + * The ReflectionProperty instances of the mapped class. + * + * @var array + */ + public $reflFields = array(); + + /** + * The prototype from which new instances of the mapped class are created. + * + * @var object + */ + private $_prototype; + + /** + * Initializes a new ClassMetadata instance that will hold the object-relational mapping + * metadata of the class with the given name. + * + * @param string $entityName The name of the entity class the new instance is used for. + * @param NamingStrategy $namingStrategy + */ + public function __construct($entityName, NamingStrategy $namingStrategy = null) + { + $this->name = $entityName; + $this->rootEntityName = $entityName; + $this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy(); + } + + /** + * Gets the ReflectionPropertys of the mapped class. + * + * @return array An array of ReflectionProperty instances. + */ + public function getReflectionProperties() + { + return $this->reflFields; + } + + /** + * Gets a ReflectionProperty for a specific field of the mapped class. + * + * @param string $name + * @return \ReflectionProperty + */ + public function getReflectionProperty($name) + { + return $this->reflFields[$name]; + } + + /** + * Gets the ReflectionProperty for the single identifier field. + * + * @return \ReflectionProperty + * @throws BadMethodCallException If the class has a composite identifier. + */ + public function getSingleIdReflectionProperty() + { + if ($this->isIdentifierComposite) { + throw new BadMethodCallException("Class " . $this->name . " has a composite identifier."); + } + return $this->reflFields[$this->identifier[0]]; + } + + /** + * Extracts the identifier values of an entity of this class. + * + * For composite identifiers, the identifier values are returned as an array + * with the same order as the field order in {@link identifier}. + * + * @param object $entity + * @return array + */ + public function getIdentifierValues($entity) + { + if ($this->isIdentifierComposite) { + $id = array(); + + foreach ($this->identifier as $idField) { + $value = $this->reflFields[$idField]->getValue($entity); + + if ($value !== null) { + $id[$idField] = $value; + } + } + + return $id; + } + + $value = $this->reflFields[$this->identifier[0]]->getValue($entity); + + if ($value !== null) { + return array($this->identifier[0] => $value); + } + + return array(); + } + + /** + * Populates the entity identifier of an entity. + * + * @param object $entity + * @param mixed $id + * @todo Rename to assignIdentifier() + */ + public function setIdentifierValues($entity, array $id) + { + foreach ($id as $idField => $idValue) { + $this->reflFields[$idField]->setValue($entity, $idValue); + } + } + + /** + * Sets the specified field to the specified value on the given entity. + * + * @param object $entity + * @param string $field + * @param mixed $value + */ + public function setFieldValue($entity, $field, $value) + { + $this->reflFields[$field]->setValue($entity, $value); + } + + /** + * Gets the specified field's value off the given entity. + * + * @param object $entity + * @param string $field + */ + public function getFieldValue($entity, $field) + { + return $this->reflFields[$field]->getValue($entity); + } + + /** + * Creates a string representation of this instance. + * + * @return string The string representation of this instance. + * @todo Construct meaningful string representation. + */ + public function __toString() + { + return __CLASS__ . '@' . spl_object_hash($this); + } + + /** + * Determines which fields get serialized. + * + * It is only serialized what is necessary for best unserialization performance. + * That means any metadata properties that are not set or empty or simply have + * their default value are NOT serialized. + * + * Parts that are also NOT serialized because they can not be properly unserialized: + * - reflClass (ReflectionClass) + * - reflFields (ReflectionProperty array) + * + * @return array The names of all the fields that should be serialized. + */ + public function __sleep() + { + // This metadata is always serialized/cached. + $serialized = array( + 'associationMappings', + 'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName'] + 'fieldMappings', + 'fieldNames', + 'identifier', + 'isIdentifierComposite', // TODO: REMOVE + 'name', + 'namespace', // TODO: REMOVE + 'table', + 'rootEntityName', + 'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime. + ); + + // The rest of the metadata is only serialized if necessary. + if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) { + $serialized[] = 'changeTrackingPolicy'; + } + + if ($this->customRepositoryClassName) { + $serialized[] = 'customRepositoryClassName'; + } + + if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) { + $serialized[] = 'inheritanceType'; + $serialized[] = 'discriminatorColumn'; + $serialized[] = 'discriminatorValue'; + $serialized[] = 'discriminatorMap'; + $serialized[] = 'parentClasses'; + $serialized[] = 'subClasses'; + } + + if ($this->generatorType != self::GENERATOR_TYPE_NONE) { + $serialized[] = 'generatorType'; + if ($this->generatorType == self::GENERATOR_TYPE_SEQUENCE) { + $serialized[] = 'sequenceGeneratorDefinition'; + } + } + + if ($this->isMappedSuperclass) { + $serialized[] = 'isMappedSuperclass'; + } + + if ($this->containsForeignIdentifier) { + $serialized[] = 'containsForeignIdentifier'; + } + + if ($this->isVersioned) { + $serialized[] = 'isVersioned'; + $serialized[] = 'versionField'; + } + + if ($this->lifecycleCallbacks) { + $serialized[] = 'lifecycleCallbacks'; + } + + if ($this->namedQueries) { + $serialized[] = 'namedQueries'; + } + + if ($this->namedNativeQueries) { + $serialized[] = 'namedNativeQueries'; + } + + if ($this->sqlResultSetMappings) { + $serialized[] = 'sqlResultSetMappings'; + } + + if ($this->isReadOnly) { + $serialized[] = 'isReadOnly'; + } + + if ($this->customGeneratorDefinition) { + $serialized[] = "customGeneratorDefinition"; + } + + return $serialized; + } + + /** + * Creates a new instance of the mapped class, without invoking the constructor. + * + * @return object + */ + public function newInstance() + { + if ($this->_prototype === null) { + $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name)); + } + + return clone $this->_prototype; + } + /** + * Restores some state that can not be serialized/unserialized. + * + * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService + * @return void + */ + public function wakeupReflection($reflService) + { + // Restore ReflectionClass and properties + $this->reflClass = $reflService->getClass($this->name); + + foreach ($this->fieldMappings as $field => $mapping) { + $this->reflFields[$field] = isset($mapping['declared']) + ? $reflService->getAccessibleProperty($mapping['declared'], $field) + : $reflService->getAccessibleProperty($this->name, $field); + } + + foreach ($this->associationMappings as $field => $mapping) { + $this->reflFields[$field] = isset($mapping['declared']) + ? $reflService->getAccessibleProperty($mapping['declared'], $field) + : $reflService->getAccessibleProperty($this->name, $field); + } + } + + /** + * Initializes a new ClassMetadata instance that will hold the object-relational mapping + * metadata of the class with the given name. + * + * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService The reflection service. + */ + public function initializeReflection($reflService) + { + $this->reflClass = $reflService->getClass($this->name); + $this->namespace = $reflService->getClassNamespace($this->name); + + if ($this->reflClass) { + $this->name = $this->rootEntityName = $this->reflClass->getName(); + } + + $this->table['name'] = $this->namingStrategy->classToTableName($this->name); + } + + /** + * Validate Identifier + * + * @throws MappingException + * @return void + */ + public function validateIdentifier() + { + // Verify & complete identifier mapping + if ( ! $this->identifier && ! $this->isMappedSuperclass) { + throw MappingException::identifierRequired($this->name); + } + + if ($this->usesIdGenerator() && $this->isIdentifierComposite) { + throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->name); + } + } + + /** + * Validate association targets actually exist. + * + * @throws MappingException + * @return void + */ + public function validateAssocations() + { + foreach ($this->associationMappings as $mapping) { + if ( ! ClassLoader::classExists($mapping['targetEntity']) ) { + throw MappingException::invalidTargetEntityClass($mapping['targetEntity'], $this->name, $mapping['fieldName']); + } + } + } + + /** + * Validate lifecycle callbacks + * + * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService + * @throws MappingException + * @return void + */ + public function validateLifecycleCallbacks($reflService) + { + foreach ($this->lifecycleCallbacks as $callbacks) { + foreach ($callbacks as $callbackFuncName) { + if ( ! $reflService->hasPublicMethod($this->name, $callbackFuncName)) { + throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callbackFuncName); + } + } + } + } + + /** + * {@inheritDoc} + */ + public function getReflectionClass() + { + return $this->reflClass; + } + + /** + * Sets the change tracking policy used by this class. + * + * @param integer $policy + */ + public function setChangeTrackingPolicy($policy) + { + $this->changeTrackingPolicy = $policy; + } + + /** + * Whether the change tracking policy of this class is "deferred explicit". + * + * @return boolean + */ + public function isChangeTrackingDeferredExplicit() + { + return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT; + } + + /** + * Whether the change tracking policy of this class is "deferred implicit". + * + * @return boolean + */ + public function isChangeTrackingDeferredImplicit() + { + return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT; + } + + /** + * Whether the change tracking policy of this class is "notify". + * + * @return boolean + */ + public function isChangeTrackingNotify() + { + return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY; + } + + /** + * Checks whether a field is part of the identifier/primary key field(s). + * + * @param string $fieldName The field name + * @return boolean TRUE if the field is part of the table identifier/primary key field(s), + * FALSE otherwise. + */ + public function isIdentifier($fieldName) + { + if ( ! $this->isIdentifierComposite) { + return $fieldName === $this->identifier[0]; + } + return in_array($fieldName, $this->identifier); + } + + /** + * Check if the field is unique. + * + * @param string $fieldName The field name + * @return boolean TRUE if the field is unique, FALSE otherwise. + */ + public function isUniqueField($fieldName) + { + $mapping = $this->getFieldMapping($fieldName); + if ($mapping !== false) { + return isset($mapping['unique']) && $mapping['unique'] == true; + } + return false; + } + + /** + * Check if the field is not null. + * + * @param string $fieldName The field name + * @return boolean TRUE if the field is not null, FALSE otherwise. + */ + public function isNullable($fieldName) + { + $mapping = $this->getFieldMapping($fieldName); + if ($mapping !== false) { + return isset($mapping['nullable']) && $mapping['nullable'] == true; + } + return false; + } + + /** + * Gets a column name for a field name. + * If the column name for the field cannot be found, the given field name + * is returned. + * + * @param string $fieldName The field name. + * @return string The column name. + */ + public function getColumnName($fieldName) + { + return isset($this->columnNames[$fieldName]) ? + $this->columnNames[$fieldName] : $fieldName; + } + + /** + * Gets the mapping of a (regular) field that holds some data but not a + * reference to another object. + * + * @param string $fieldName The field name. + * @throws MappingException + * @return array The field mapping. + */ + public function getFieldMapping($fieldName) + { + if ( ! isset($this->fieldMappings[$fieldName])) { + throw MappingException::mappingNotFound($this->name, $fieldName); + } + return $this->fieldMappings[$fieldName]; + } + + /** + * Gets the mapping of an association. + * + * @see ClassMetadataInfo::$associationMappings + * @param string $fieldName The field name that represents the association in + * the object model. + * @throws MappingException + * @return array The mapping. + */ + public function getAssociationMapping($fieldName) + { + if ( ! isset($this->associationMappings[$fieldName])) { + throw MappingException::mappingNotFound($this->name, $fieldName); + } + return $this->associationMappings[$fieldName]; + } + + /** + * Gets all association mappings of the class. + * + * @return array + */ + public function getAssociationMappings() + { + return $this->associationMappings; + } + + /** + * Gets the field name for a column name. + * If no field name can be found the column name is returned. + * + * @param string $columnName column name + * @return string column alias + */ + public function getFieldName($columnName) + { + return isset($this->fieldNames[$columnName]) ? + $this->fieldNames[$columnName] : $columnName; + } + + /** + * Gets the named query. + * + * @see ClassMetadataInfo::$namedQueries + * @throws MappingException + * @param string $queryName The query name + * @return string + */ + public function getNamedQuery($queryName) + { + if ( ! isset($this->namedQueries[$queryName])) { + throw MappingException::queryNotFound($this->name, $queryName); + } + return $this->namedQueries[$queryName]['dql']; + } + + /** + * Gets all named queries of the class. + * + * @return array + */ + public function getNamedQueries() + { + return $this->namedQueries; + } + + /** + * Gets the named native query. + * + * @see ClassMetadataInfo::$namedNativeQueries + * @throws MappingException + * @param string $queryName The query name + * @return array + */ + public function getNamedNativeQuery($queryName) + { + if ( ! isset($this->namedNativeQueries[$queryName])) { + throw MappingException::queryNotFound($this->name, $queryName); + } + + return $this->namedNativeQueries[$queryName]; + } + + /** + * Gets all named native queries of the class. + * + * @return array + */ + public function getNamedNativeQueries() + { + return $this->namedNativeQueries; + } + + /** + * Gets the result set mapping. + * + * @see ClassMetadataInfo::$sqlResultSetMappings + * @throws MappingException + * @param string $name The result set mapping name + * @return array + */ + public function getSqlResultSetMapping($name) + { + if ( ! isset($this->sqlResultSetMappings[$name])) { + throw MappingException::resultMappingNotFound($this->name, $name); + } + + return $this->sqlResultSetMappings[$name]; + } + + /** + * Gets all sql result set mappings of the class. + * + * @return array + */ + public function getSqlResultSetMappings() + { + return $this->sqlResultSetMappings; + } + + /** + * Validates & completes the given field mapping. + * + * @param array $mapping The field mapping to validated & complete. + * @throws MappingException + * @return array The validated and completed field mapping. + */ + protected function _validateAndCompleteFieldMapping(array &$mapping) + { + // Check mandatory fields + if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) { + throw MappingException::missingFieldName($this->name); + } + if ( ! isset($mapping['type'])) { + // Default to string + $mapping['type'] = 'string'; + } + + // Complete fieldName and columnName mapping + if ( ! isset($mapping['columnName'])) { + $mapping['columnName'] = $this->namingStrategy->propertyToColumnName($mapping['fieldName']); + } + + if ($mapping['columnName'][0] === '`') { + $mapping['columnName'] = trim($mapping['columnName'], '`'); + $mapping['quoted'] = true; + } + + $this->columnNames[$mapping['fieldName']] = $mapping['columnName']; + if (isset($this->fieldNames[$mapping['columnName']]) || ($this->discriminatorColumn != null && $this->discriminatorColumn['name'] == $mapping['columnName'])) { + throw MappingException::duplicateColumnName($this->name, $mapping['columnName']); + } + + $this->fieldNames[$mapping['columnName']] = $mapping['fieldName']; + + // Complete id mapping + if (isset($mapping['id']) && $mapping['id'] === true) { + if ($this->versionField == $mapping['fieldName']) { + throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName']); + } + + if ( ! in_array($mapping['fieldName'], $this->identifier)) { + $this->identifier[] = $mapping['fieldName']; + } + // Check for composite key + if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) { + $this->isIdentifierComposite = true; + } + } + + if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) { + if (isset($mapping['id']) && $mapping['id'] === true) { + throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']); + } + + $mapping['requireSQLConversion'] = true; + } + } + + /** + * Validates & completes the basic mapping information that is common to all + * association mappings (one-to-one, many-ot-one, one-to-many, many-to-many). + * + * @param array $mapping The mapping. + * @return array The updated mapping. + * @throws MappingException If something is wrong with the mapping. + */ + protected function _validateAndCompleteAssociationMapping(array $mapping) + { + if ( ! isset($mapping['mappedBy'])) { + $mapping['mappedBy'] = null; + } + if ( ! isset($mapping['inversedBy'])) { + $mapping['inversedBy'] = null; + } + $mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy + + // unset optional indexBy attribute if its empty + if ( ! isset($mapping['indexBy']) || !$mapping['indexBy']) { + unset($mapping['indexBy']); + } + + // If targetEntity is unqualified, assume it is in the same namespace as + // the sourceEntity. + $mapping['sourceEntity'] = $this->name; + + if (isset($mapping['targetEntity'])) { + if (strlen($this->namespace) > 0 && strpos($mapping['targetEntity'], '\\') === false) { + $mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity']; + } + + $mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\'); + } + + if ( ($mapping['type'] & self::MANY_TO_ONE) > 0 && + isset($mapping['orphanRemoval']) && + $mapping['orphanRemoval'] == true) { + + throw MappingException::illegalOrphanRemoval($this->name, $mapping['fieldName']); + } + + // Complete id mapping + if (isset($mapping['id']) && $mapping['id'] === true) { + if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'] == true) { + throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->name, $mapping['fieldName']); + } + + if ( ! in_array($mapping['fieldName'], $this->identifier)) { + if (count($mapping['joinColumns']) >= 2) { + throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId( + $mapping['targetEntity'], $this->name, $mapping['fieldName'] + ); + } + + $this->identifier[] = $mapping['fieldName']; + $this->containsForeignIdentifier = true; + } + // Check for composite key + if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) { + $this->isIdentifierComposite = true; + } + } + + // Mandatory attributes for both sides + // Mandatory: fieldName, targetEntity + if ( ! isset($mapping['fieldName']) || strlen($mapping['fieldName']) == 0) { + throw MappingException::missingFieldName($this->name); + } + if ( ! isset($mapping['targetEntity'])) { + throw MappingException::missingTargetEntity($mapping['fieldName']); + } + + // Mandatory and optional attributes for either side + if ( ! $mapping['mappedBy']) { + if (isset($mapping['joinTable']) && $mapping['joinTable']) { + if (isset($mapping['joinTable']['name']) && $mapping['joinTable']['name'][0] === '`') { + $mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`'); + $mapping['joinTable']['quoted'] = true; + } + } + } else { + $mapping['isOwningSide'] = false; + } + + if (isset($mapping['id']) && $mapping['id'] === true && $mapping['type'] & self::TO_MANY) { + throw MappingException::illegalToManyIdentifierAssoaction($this->name, $mapping['fieldName']); + } + + // Fetch mode. Default fetch mode to LAZY, if not set. + if ( ! isset($mapping['fetch'])) { + $mapping['fetch'] = self::FETCH_LAZY; + } + + // Cascades + $cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array(); + + if (in_array('all', $cascades)) { + $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach'); + } + + if (count($cascades) !== count(array_intersect($cascades, array('remove', 'persist', 'refresh', 'merge', 'detach')))) { + throw MappingException::invalidCascadeOption( + array_diff($cascades, array_intersect($cascades, array('remove', 'persist', 'refresh', 'merge', 'detach'))), + $this->name, + $mapping['fieldName'] + ); + } + + $mapping['cascade'] = $cascades; + $mapping['isCascadeRemove'] = in_array('remove', $cascades); + $mapping['isCascadePersist'] = in_array('persist', $cascades); + $mapping['isCascadeRefresh'] = in_array('refresh', $cascades); + $mapping['isCascadeMerge'] = in_array('merge', $cascades); + $mapping['isCascadeDetach'] = in_array('detach', $cascades); + + return $mapping; + } + + /** + * Validates & completes a one-to-one association mapping. + * + * @param array $mapping The mapping to validate & complete. + * @throws RuntimeException + * @throws MappingException + * @return array The validated & completed mapping.@override + */ + protected function _validateAndCompleteOneToOneMapping(array $mapping) + { + $mapping = $this->_validateAndCompleteAssociationMapping($mapping); + + if (isset($mapping['joinColumns']) && $mapping['joinColumns']) { + $mapping['isOwningSide'] = true; + } + + if ($mapping['isOwningSide']) { + if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) { + // Apply default join column + $mapping['joinColumns'] = array(array( + 'name' => $this->namingStrategy->joinColumnName($mapping['fieldName']), + 'referencedColumnName' => $this->namingStrategy->referenceColumnName() + )); + } + + $uniqueContraintColumns = array(); + foreach ($mapping['joinColumns'] as &$joinColumn) { + if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) { + if (count($mapping['joinColumns']) == 1) { + if ( ! isset($mapping['id']) || ! $mapping['id']) { + $joinColumn['unique'] = true; + } + } else { + $uniqueContraintColumns[] = $joinColumn['name']; + } + } + + if (empty($joinColumn['name'])) { + $joinColumn['name'] = $this->namingStrategy->joinColumnName($mapping['fieldName']); + } + + if (empty($joinColumn['referencedColumnName'])) { + $joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName(); + } + + if ($joinColumn['name'][0] === '`') { + $joinColumn['name'] = trim($joinColumn['name'], '`'); + $joinColumn['quoted'] = true; + } + + if ($joinColumn['referencedColumnName'][0] === '`') { + $joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`'); + $joinColumn['quoted'] = true; + } + + $mapping['sourceToTargetKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName']; + $mapping['joinColumnFieldNames'][$joinColumn['name']] = isset($joinColumn['fieldName']) + ? $joinColumn['fieldName'] : $joinColumn['name']; + } + + if ($uniqueContraintColumns) { + if ( ! $this->table) { + throw new RuntimeException("ClassMetadataInfo::setTable() has to be called before defining a one to one relationship."); + } + $this->table['uniqueConstraints'][$mapping['fieldName']."_uniq"] = array( + 'columns' => $uniqueContraintColumns + ); + } + + $mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']); + } + + $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false; + $mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove']; + + if (isset($mapping['id']) && $mapping['id'] === true && !$mapping['isOwningSide']) { + throw MappingException::illegalInverseIdentifierAssocation($this->name, $mapping['fieldName']); + } + + return $mapping; + } + + /** + * Validates and completes the mapping. + * + * @param array $mapping The mapping to validate and complete. + * @throws MappingException + * @throws InvalidArgumentException + * @return array The validated and completed mapping.@override + */ + protected function _validateAndCompleteOneToManyMapping(array $mapping) + { + $mapping = $this->_validateAndCompleteAssociationMapping($mapping); + + // OneToMany-side MUST be inverse (must have mappedBy) + if ( ! isset($mapping['mappedBy'])) { + throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']); + } + + $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false; + $mapping['isCascadeRemove'] = $mapping['orphanRemoval'] ? true : $mapping['isCascadeRemove']; + + if (isset($mapping['orderBy'])) { + if ( ! is_array($mapping['orderBy'])) { + throw new InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy'])); + } + } + + return $mapping; + } + + protected function _validateAndCompleteManyToManyMapping(array $mapping) + { + $mapping = $this->_validateAndCompleteAssociationMapping($mapping); + if ($mapping['isOwningSide']) { + // owning side MUST have a join table + if ( ! isset($mapping['joinTable']['name'])) { + $mapping['joinTable']['name'] = $this->namingStrategy->joinTableName($mapping['sourceEntity'], $mapping['targetEntity'], $mapping['fieldName']); + } + if ( ! isset($mapping['joinTable']['joinColumns'])) { + $mapping['joinTable']['joinColumns'] = array(array( + 'name' => $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity']), + 'referencedColumnName' => $this->namingStrategy->referenceColumnName(), + 'onDelete' => 'CASCADE')); + } + if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) { + $mapping['joinTable']['inverseJoinColumns'] = array(array( + 'name' => $this->namingStrategy->joinKeyColumnName($mapping['targetEntity']), + 'referencedColumnName' => $this->namingStrategy->referenceColumnName(), + 'onDelete' => 'CASCADE')); + } + + foreach ($mapping['joinTable']['joinColumns'] as &$joinColumn) { + if (empty($joinColumn['name'])) { + $joinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity'], $joinColumn['referencedColumnName']); + } + + if (empty($joinColumn['referencedColumnName'])) { + $joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName(); + } + + if ($joinColumn['name'][0] === '`') { + $joinColumn['name'] = trim($joinColumn['name'], '`'); + $joinColumn['quoted'] = true; + } + + if ($joinColumn['referencedColumnName'][0] === '`') { + $joinColumn['referencedColumnName'] = trim($joinColumn['referencedColumnName'], '`'); + $joinColumn['quoted'] = true; + } + + if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') { + $mapping['isOnDeleteCascade'] = true; + } + + $mapping['relationToSourceKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName']; + $mapping['joinTableColumns'][] = $joinColumn['name']; + } + + foreach ($mapping['joinTable']['inverseJoinColumns'] as &$inverseJoinColumn) { + if (empty($inverseJoinColumn['name'])) { + $inverseJoinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['targetEntity'], $inverseJoinColumn['referencedColumnName']); + } + + if (empty($inverseJoinColumn['referencedColumnName'])) { + $inverseJoinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName(); + } + + if ($inverseJoinColumn['name'][0] === '`') { + $inverseJoinColumn['name'] = trim($inverseJoinColumn['name'], '`'); + $inverseJoinColumn['quoted'] = true; + } + + if ($inverseJoinColumn['referencedColumnName'][0] === '`') { + $inverseJoinColumn['referencedColumnName'] = trim($inverseJoinColumn['referencedColumnName'], '`'); + $inverseJoinColumn['quoted'] = true; + } + + if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') { + $mapping['isOnDeleteCascade'] = true; + } + + $mapping['relationToTargetKeyColumns'][$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName']; + $mapping['joinTableColumns'][] = $inverseJoinColumn['name']; + } + } + + $mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false; + + if (isset($mapping['orderBy'])) { + if ( ! is_array($mapping['orderBy'])) { + throw new InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy'])); + } + } + + return $mapping; + } + + /** + * {@inheritDoc} + */ + public function getIdentifierFieldNames() + { + return $this->identifier; + } + + /** + * Gets the name of the single id field. Note that this only works on + * entity classes that have a single-field pk. + * + * @return string + * @throws MappingException If the class has a composite primary key. + */ + public function getSingleIdentifierFieldName() + { + if ($this->isIdentifierComposite) { + throw MappingException::singleIdNotAllowedOnCompositePrimaryKey($this->name); + } + return $this->identifier[0]; + } + + /** + * Gets the column name of the single id column. Note that this only works on + * entity classes that have a single-field pk. + * + * @return string + * @throws MappingException If the class has a composite primary key. + */ + public function getSingleIdentifierColumnName() + { + return $this->getColumnName($this->getSingleIdentifierFieldName()); + } + + /** + * INTERNAL: + * Sets the mapped identifier/primary key fields of this class. + * Mainly used by the ClassMetadataFactory to assign inherited identifiers. + * + * @param array $identifier + */ + public function setIdentifier(array $identifier) + { + $this->identifier = $identifier; + $this->isIdentifierComposite = (count($this->identifier) > 1); + } + + /** + * Gets the mapped identifier field of this class. + * + * @return array|string $identifier + */ + public function getIdentifier() + { + return $this->identifier; + } + + /** + * {@inheritDoc} + */ + public function hasField($fieldName) + { + return isset($this->fieldMappings[$fieldName]); + } + + /** + * Gets an array containing all the column names. + * + * @param array $fieldNames + * @return array + */ + public function getColumnNames(array $fieldNames = null) + { + if ($fieldNames === null) { + return array_keys($this->fieldNames); + } else { + $columnNames = array(); + foreach ($fieldNames as $fieldName) { + $columnNames[] = $this->getColumnName($fieldName); + } + return $columnNames; + } + } + + /** + * Returns an array with all the identifier column names. + * + * @return array + */ + public function getIdentifierColumnNames() + { + $columnNames = array(); + + foreach ($this->identifier as $idProperty) { + if (isset($this->fieldMappings[$idProperty])) { + $columnNames[] = $this->fieldMappings[$idProperty]['columnName']; + + continue; + } + + // Association defined as Id field + $joinColumns = $this->associationMappings[$idProperty]['joinColumns']; + $assocColumnNames = array_map(function ($joinColumn) { return $joinColumn['name']; }, $joinColumns); + + $columnNames = array_merge($columnNames, $assocColumnNames); + } + + return $columnNames; + } + + /** + * Sets the type of Id generator to use for the mapped class. + */ + public function setIdGeneratorType($generatorType) + { + $this->generatorType = $generatorType; + } + + /** + * Checks whether the mapped class uses an Id generator. + * + * @return boolean TRUE if the mapped class uses an Id generator, FALSE otherwise. + */ + public function usesIdGenerator() + { + return $this->generatorType != self::GENERATOR_TYPE_NONE; + } + + /** + * @return boolean + */ + public function isInheritanceTypeNone() + { + return $this->inheritanceType == self::INHERITANCE_TYPE_NONE; + } + + /** + * Checks whether the mapped class uses the JOINED inheritance mapping strategy. + * + * @return boolean TRUE if the class participates in a JOINED inheritance mapping, + * FALSE otherwise. + */ + public function isInheritanceTypeJoined() + { + return $this->inheritanceType == self::INHERITANCE_TYPE_JOINED; + } + + /** + * Checks whether the mapped class uses the SINGLE_TABLE inheritance mapping strategy. + * + * @return boolean TRUE if the class participates in a SINGLE_TABLE inheritance mapping, + * FALSE otherwise. + */ + public function isInheritanceTypeSingleTable() + { + return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_TABLE; + } + + /** + * Checks whether the mapped class uses the TABLE_PER_CLASS inheritance mapping strategy. + * + * @return boolean TRUE if the class participates in a TABLE_PER_CLASS inheritance mapping, + * FALSE otherwise. + */ + public function isInheritanceTypeTablePerClass() + { + return $this->inheritanceType == self::INHERITANCE_TYPE_TABLE_PER_CLASS; + } + + /** + * Checks whether the class uses an identity column for the Id generation. + * + * @return boolean TRUE if the class uses the IDENTITY generator, FALSE otherwise. + */ + public function isIdGeneratorIdentity() + { + return $this->generatorType == self::GENERATOR_TYPE_IDENTITY; + } + + /** + * Checks whether the class uses a sequence for id generation. + * + * @return boolean TRUE if the class uses the SEQUENCE generator, FALSE otherwise. + */ + public function isIdGeneratorSequence() + { + return $this->generatorType == self::GENERATOR_TYPE_SEQUENCE; + } + + /** + * Checks whether the class uses a table for id generation. + * + * @return boolean TRUE if the class uses the TABLE generator, FALSE otherwise. + */ + public function isIdGeneratorTable() + { + return $this->generatorType == self::GENERATOR_TYPE_TABLE; + } + + /** + * Checks whether the class has a natural identifier/pk (which means it does + * not use any Id generator. + * + * @return boolean + */ + public function isIdentifierNatural() + { + return $this->generatorType == self::GENERATOR_TYPE_NONE; + } + + /** + * Checks whether the class use a UUID for id generation + * + * @return boolean + */ + public function isIdentifierUuid() + { + return $this->generatorType == self::GENERATOR_TYPE_UUID; + } + + /** + * Gets the type of a field. + * + * @param string $fieldName + * @return \Doctrine\DBAL\Types\Type|string + */ + public function getTypeOfField($fieldName) + { + return isset($this->fieldMappings[$fieldName]) ? + $this->fieldMappings[$fieldName]['type'] : null; + } + + /** + * Gets the type of a column. + * + * @param string $columnName + * @return \Doctrine\DBAL\Types\Type + */ + public function getTypeOfColumn($columnName) + { + return $this->getTypeOfField($this->getFieldName($columnName)); + } + + /** + * Gets the name of the primary table. + * + * @return string + */ + public function getTableName() + { + return $this->table['name']; + } + + /** + * Gets the table name to use for temporary identifier tables of this class. + * + * @return string + */ + public function getTemporaryIdTableName() + { + // replace dots with underscores because PostgreSQL creates temporary tables in a special schema + return str_replace('.', '_', $this->getTableName() . '_id_tmp'); + } + + /** + * Sets the mapped subclasses of this class. + * + * @param array $subclasses The names of all mapped subclasses. + */ + public function setSubclasses(array $subclasses) + { + foreach ($subclasses as $subclass) { + if (strpos($subclass, '\\') === false && strlen($this->namespace)) { + $this->subClasses[] = $this->namespace . '\\' . $subclass; + } else { + $this->subClasses[] = $subclass; + } + } + } + + /** + * Sets the parent class names. + * Assumes that the class names in the passed array are in the order: + * directParent -> directParentParent -> directParentParentParent ... -> root. + */ + public function setParentClasses(array $classNames) + { + $this->parentClasses = $classNames; + if (count($classNames) > 0) { + $this->rootEntityName = array_pop($classNames); + } + } + + /** + * Sets the inheritance type used by the class and it's subclasses. + * + * @param integer $type + * @throws MappingException + * @return void + */ + public function setInheritanceType($type) + { + if ( ! $this->_isInheritanceType($type)) { + throw MappingException::invalidInheritanceType($this->name, $type); + } + $this->inheritanceType = $type; + } + + /** + * Sets the association to override association mapping of property for an entity relationship. + * + * @param string $fieldName + * @param array $overrideMapping + * @throws MappingException + * @return void + */ + public function setAssociationOverride($fieldName, array $overrideMapping) + { + if ( ! isset($this->associationMappings[$fieldName])) { + throw MappingException::invalidOverrideFieldName($this->name, $fieldName); + } + + $mapping = $this->associationMappings[$fieldName]; + + if (isset($overrideMapping['joinColumns'])) { + $mapping['joinColumns'] = $overrideMapping['joinColumns']; + } + + if (isset($overrideMapping['joinTable'])) { + $mapping['joinTable'] = $overrideMapping['joinTable']; + } + + $mapping['joinColumnFieldNames'] = null; + $mapping['joinTableColumns'] = null; + $mapping['sourceToTargetKeyColumns'] = null; + $mapping['relationToSourceKeyColumns'] = null; + $mapping['relationToTargetKeyColumns'] = null; + + switch ($mapping['type']) { + case self::ONE_TO_ONE: + $mapping = $this->_validateAndCompleteOneToOneMapping($mapping); + break; + case self::ONE_TO_MANY: + $mapping = $this->_validateAndCompleteOneToManyMapping($mapping); + break; + case self::MANY_TO_ONE: + $mapping = $this->_validateAndCompleteOneToOneMapping($mapping); + break; + case self::MANY_TO_MANY: + $mapping = $this->_validateAndCompleteManyToManyMapping($mapping); + break; + } + + $this->associationMappings[$fieldName] = $mapping; + } + + /** + * Sets the override for a mapped field. + * + * @param string $fieldName + * @param array $overrideMapping + * @throws MappingException + * @param array $overrideMapping + * @return void + */ + public function setAttributeOverride($fieldName, array $overrideMapping) + { + if ( ! isset($this->fieldMappings[$fieldName])) { + throw MappingException::invalidOverrideFieldName($this->name, $fieldName); + } + + $mapping = $this->fieldMappings[$fieldName]; + + if (isset($mapping['id'])) { + $overrideMapping['id'] = $mapping['id']; + } + + if ( ! isset($overrideMapping['type']) || $overrideMapping['type'] === null) { + $overrideMapping['type'] = $mapping['type']; + } + + if ( ! isset($overrideMapping['fieldName']) || $overrideMapping['fieldName'] === null) { + $overrideMapping['fieldName'] = $mapping['fieldName']; + } + + if ($overrideMapping['type'] !== $mapping['type']) { + throw MappingException::invalidOverrideFieldType($this->name, $fieldName); + } + + unset($this->fieldMappings[$fieldName]); + unset($this->fieldNames[$mapping['columnName']]); + unset($this->columnNames[$mapping['fieldName']]); + $this->_validateAndCompleteFieldMapping($overrideMapping); + + $this->fieldMappings[$fieldName] = $overrideMapping; + } + + /** + * Checks whether a mapped field is inherited from an entity superclass. + * + * @param string $fieldName + * @return bool TRUE if the field is inherited, FALSE otherwise. + */ + public function isInheritedField($fieldName) + { + return isset($this->fieldMappings[$fieldName]['inherited']); + } + + /** + * Check if this entity is the root in any entity-inheritance-hierachy. + * + * @return bool + */ + public function isRootEntity() + { + return $this->name == $this->rootEntityName; + } + + /** + * Checks whether a mapped association field is inherited from a superclass. + * + * @param string $fieldName + * @return boolean TRUE if the field is inherited, FALSE otherwise. + */ + public function isInheritedAssociation($fieldName) + { + return isset($this->associationMappings[$fieldName]['inherited']); + } + + /** + * Sets the name of the primary table the class is mapped to. + * + * @param string $tableName The table name. + * @deprecated Use {@link setPrimaryTable}. + */ + public function setTableName($tableName) + { + $this->table['name'] = $tableName; + } + + /** + * Sets the primary table definition. The provided array supports the + * following structure: + * + * name => (optional, defaults to class name) + * indexes => array of indexes (optional) + * uniqueConstraints => array of constraints (optional) + * + * If a key is omitted, the current value is kept. + * + * @param array $table The table description. + */ + public function setPrimaryTable(array $table) + { + if (isset($table['name'])) { + if ($table['name'][0] === '`') { + $table['name'] = trim($table['name'], '`'); + $this->table['quoted'] = true; + } + + $this->table['name'] = $table['name']; + } + + if (isset($table['indexes'])) { + $this->table['indexes'] = $table['indexes']; + } + + if (isset($table['uniqueConstraints'])) { + $this->table['uniqueConstraints'] = $table['uniqueConstraints']; + } + + if (isset($table['options'])) { + $this->table['options'] = $table['options']; + } + } + + /** + * Checks whether the given type identifies an inheritance type. + * + * @param integer $type + * @return boolean TRUE if the given type identifies an inheritance type, FALSe otherwise. + */ + private function _isInheritanceType($type) + { + return $type == self::INHERITANCE_TYPE_NONE || + $type == self::INHERITANCE_TYPE_SINGLE_TABLE || + $type == self::INHERITANCE_TYPE_JOINED || + $type == self::INHERITANCE_TYPE_TABLE_PER_CLASS; + } + + /** + * Adds a mapped field to the class. + * + * @param array $mapping The field mapping. + * @throws MappingException + * @return void + */ + public function mapField(array $mapping) + { + $this->_validateAndCompleteFieldMapping($mapping); + if (isset($this->fieldMappings[$mapping['fieldName']]) || isset($this->associationMappings[$mapping['fieldName']])) { + throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']); + } + $this->fieldMappings[$mapping['fieldName']] = $mapping; + } + + /** + * INTERNAL: + * Adds an association mapping without completing/validating it. + * This is mainly used to add inherited association mappings to derived classes. + * + * @param array $mapping + * @throws MappingException + * @return void + */ + public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/) + { + if (isset($this->associationMappings[$mapping['fieldName']])) { + throw MappingException::duplicateAssociationMapping($this->name, $mapping['fieldName']); + } + $this->associationMappings[$mapping['fieldName']] = $mapping; + } + + /** + * INTERNAL: + * Adds a field mapping without completing/validating it. + * This is mainly used to add inherited field mappings to derived classes. + * + * @param array $fieldMapping + * @return void + */ + public function addInheritedFieldMapping(array $fieldMapping) + { + $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping; + $this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName']; + $this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName']; + } + + /** + * INTERNAL: + * Adds a named query to this class. + * + * @throws MappingException + * @param array $queryMapping + */ + public function addNamedQuery(array $queryMapping) + { + if (!isset($queryMapping['name'])) { + throw MappingException::nameIsMandatoryForQueryMapping($this->name); + } + + if (isset($this->namedQueries[$queryMapping['name']])) { + throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']); + } + + if (!isset($queryMapping['query'])) { + throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']); + } + + $name = $queryMapping['name']; + $query = $queryMapping['query']; + $dql = str_replace('__CLASS__', $this->name, $query); + $this->namedQueries[$name] = array( + 'name' => $name, + 'query' => $query, + 'dql' => $dql + ); + } + + /** + * INTERNAL: + * Adds a named native query to this class. + * + * @throws MappingException + * @param array $queryMapping + */ + public function addNamedNativeQuery(array $queryMapping) + { + if (!isset($queryMapping['name'])) { + throw MappingException::nameIsMandatoryForQueryMapping($this->name); + } + + if (isset($this->namedNativeQueries[$queryMapping['name']])) { + throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']); + } + + if (!isset($queryMapping['query'])) { + throw MappingException::emptyQueryMapping($this->name, $queryMapping['name']); + } + + if (!isset($queryMapping['resultClass']) && !isset($queryMapping['resultSetMapping'])) { + throw MappingException::missingQueryMapping($this->name, $queryMapping['name']); + } + + $queryMapping['isSelfClass'] = false; + if (isset($queryMapping['resultClass'])) { + + if($queryMapping['resultClass'] === '__CLASS__') { + + $queryMapping['isSelfClass'] = true; + $queryMapping['resultClass'] = $this->name; + + } else if (strlen($this->namespace) > 0 && strpos($queryMapping['resultClass'], '\\') === false) { + $queryMapping['resultClass'] = $this->namespace . '\\' . $queryMapping['resultClass']; + } + + $queryMapping['resultClass'] = ltrim($queryMapping['resultClass'], '\\'); + } + + $this->namedNativeQueries[$queryMapping['name']] = $queryMapping; + } + + /** + * INTERNAL: + * Adds a sql result set mapping to this class. + * + * @throws MappingException + * @param array $resultMapping + */ + public function addSqlResultSetMapping(array $resultMapping) + { + if (!isset($resultMapping['name'])) { + throw MappingException::nameIsMandatoryForSqlResultSetMapping($this->name); + } + + if (isset($this->sqlResultSetMappings[$resultMapping['name']])) { + throw MappingException::duplicateResultSetMapping($this->name, $resultMapping['name']); + } + + if (isset($resultMapping['entities'])) { + foreach ($resultMapping['entities'] as $key => $entityResult) { + if (!isset($entityResult['entityClass'])) { + throw MappingException::missingResultSetMappingEntity($this->name, $resultMapping['name']); + } + + $entityResult['isSelfClass'] = false; + if($entityResult['entityClass'] === '__CLASS__') { + + $entityResult['isSelfClass'] = true; + $entityResult['entityClass'] = $this->name; + + } else if (strlen($this->namespace) > 0 && strpos($entityResult['entityClass'], '\\') === false) { + $entityResult['entityClass'] = $this->namespace . '\\' . $entityResult['entityClass']; + } + + $resultMapping['entities'][$key]['entityClass'] = ltrim($entityResult['entityClass'], '\\'); + $resultMapping['entities'][$key]['isSelfClass'] = $entityResult['isSelfClass']; + + if (isset($entityResult['fields'])) { + foreach ($entityResult['fields'] as $k => $field) { + if (!isset($field['name'])) { + throw MappingException::missingResultSetMappingFieldName($this->name, $resultMapping['name']); + } + + if (!isset($field['column'])) { + $fieldName = $field['name']; + if(strpos($fieldName, '.')){ + list(, $fieldName) = explode('.', $fieldName); + } + + $resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName; + } + } + } + } + } + + $this->sqlResultSetMappings[$resultMapping['name']] = $resultMapping; + } + + /** + * Adds a one-to-one mapping. + * + * @param array $mapping The mapping. + */ + public function mapOneToOne(array $mapping) + { + $mapping['type'] = self::ONE_TO_ONE; + $mapping = $this->_validateAndCompleteOneToOneMapping($mapping); + $this->_storeAssociationMapping($mapping); + } + + /** + * Adds a one-to-many mapping. + * + * @param array $mapping The mapping. + */ + public function mapOneToMany(array $mapping) + { + $mapping['type'] = self::ONE_TO_MANY; + $mapping = $this->_validateAndCompleteOneToManyMapping($mapping); + $this->_storeAssociationMapping($mapping); + } + + /** + * Adds a many-to-one mapping. + * + * @param array $mapping The mapping. + */ + public function mapManyToOne(array $mapping) + { + $mapping['type'] = self::MANY_TO_ONE; + // A many-to-one mapping is essentially a one-one backreference + $mapping = $this->_validateAndCompleteOneToOneMapping($mapping); + $this->_storeAssociationMapping($mapping); + } + + /** + * Adds a many-to-many mapping. + * + * @param array $mapping The mapping. + */ + public function mapManyToMany(array $mapping) + { + $mapping['type'] = self::MANY_TO_MANY; + $mapping = $this->_validateAndCompleteManyToManyMapping($mapping); + $this->_storeAssociationMapping($mapping); + } + + /** + * Stores the association mapping. + * + * @param array $assocMapping + * @throws MappingException + * @return void + */ + protected function _storeAssociationMapping(array $assocMapping) + { + $sourceFieldName = $assocMapping['fieldName']; + + if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) { + throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName); + } + + $this->associationMappings[$sourceFieldName] = $assocMapping; + } + + /** + * Registers a custom repository class for the entity class. + * + * @param string $repositoryClassName The class name of the custom mapper. + * @return void + */ + public function setCustomRepositoryClass($repositoryClassName) + { + if ($repositoryClassName !== null && strpos($repositoryClassName, '\\') === false + && strlen($this->namespace) > 0) { + $repositoryClassName = $this->namespace . '\\' . $repositoryClassName; + } + $this->customRepositoryClassName = $repositoryClassName; + } + + /** + * Dispatches the lifecycle event of the given entity to the registered + * lifecycle callbacks and lifecycle listeners. + * + * @param string $lifecycleEvent The lifecycle event. + * @param \Object $entity The Entity on which the event occured. + */ + public function invokeLifecycleCallbacks($lifecycleEvent, $entity) + { + foreach ($this->lifecycleCallbacks[$lifecycleEvent] as $callback) { + $entity->$callback(); + } + } + + /** + * Whether the class has any attached lifecycle listeners or callbacks for a lifecycle event. + * + * @param string $lifecycleEvent + * @return boolean + */ + public function hasLifecycleCallbacks($lifecycleEvent) + { + return isset($this->lifecycleCallbacks[$lifecycleEvent]); + } + + /** + * Gets the registered lifecycle callbacks for an event. + * + * @param string $event + * @return array + */ + public function getLifecycleCallbacks($event) + { + return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array(); + } + + /** + * Adds a lifecycle callback for entities of this class. + * + * @param string $callback + * @param string $event + */ + public function addLifecycleCallback($callback, $event) + { + $this->lifecycleCallbacks[$event][] = $callback; + } + + /** + * Sets the lifecycle callbacks for entities of this class. + * Any previously registered callbacks are overwritten. + * + * @param array $callbacks + */ + public function setLifecycleCallbacks(array $callbacks) + { + $this->lifecycleCallbacks = $callbacks; + } + + /** + * Sets the discriminator column definition. + * + * @param array $columnDef + * + * @param $columnDef + * @throws MappingException + * @return void + * @see getDiscriminatorColumn() + */ + public function setDiscriminatorColumn($columnDef) + { + if ($columnDef !== null) { + if ( ! isset($columnDef['name'])) { + throw MappingException::nameIsMandatoryForDiscriminatorColumns($this->name); + } + + if (isset($this->fieldNames[$columnDef['name']])) { + throw MappingException::duplicateColumnName($this->name, $columnDef['name']); + } + + if ( ! isset($columnDef['fieldName'])) { + $columnDef['fieldName'] = $columnDef['name']; + } + + if ( ! isset($columnDef['type'])) { + $columnDef['type'] = "string"; + } + + if (in_array($columnDef['type'], array("boolean", "array", "object", "datetime", "time", "date"))) { + throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']); + } + + $this->discriminatorColumn = $columnDef; + } + } + + /** + * Sets the discriminator values used by this class. + * Used for JOINED and SINGLE_TABLE inheritance mapping strategies. + * + * @param array $map + */ + public function setDiscriminatorMap(array $map) + { + foreach ($map as $value => $className) { + $this->addDiscriminatorMapClass($value, $className); + } + } + + /** + * Add one entry of the discriminator map with a new class and corresponding name. + * + * @param string $name + * @param string $className + * @throws MappingException + * @return void + */ + public function addDiscriminatorMapClass($name, $className) + { + if (strlen($this->namespace) > 0 && strpos($className, '\\') === false) { + $className = $this->namespace . '\\' . $className; + } + + $className = ltrim($className, '\\'); + $this->discriminatorMap[$name] = $className; + + if ($this->name == $className) { + $this->discriminatorValue = $name; + } else { + if ( ! class_exists($className)) { + throw MappingException::invalidClassInDiscriminatorMap($className, $this->name); + } + if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses)) { + $this->subClasses[] = $className; + } + } + } + + /** + * Checks whether the class has a named query with the given query name. + * + * @param string $queryName + * @return boolean + */ + public function hasNamedQuery($queryName) + { + return isset($this->namedQueries[$queryName]); + } + + /** + * Checks whether the class has a named native query with the given query name. + * + * @param string $queryName + * @return boolean + */ + public function hasNamedNativeQuery($queryName) + { + return isset($this->namedNativeQueries[$queryName]); + } + + /** + * Checks whether the class has a named native query with the given query name. + * + * @param string $name + * @return boolean + */ + public function hasSqlResultSetMapping($name) + { + return isset($this->sqlResultSetMappings[$name]); + } + + /** + * {@inheritDoc} + */ + public function hasAssociation($fieldName) + { + return isset($this->associationMappings[$fieldName]); + } + + /** + * {@inheritDoc} + */ + public function isSingleValuedAssociation($fieldName) + { + return isset($this->associationMappings[$fieldName]) && + ($this->associationMappings[$fieldName]['type'] & self::TO_ONE); + } + + /** + * {@inheritDoc} + */ + public function isCollectionValuedAssociation($fieldName) + { + return isset($this->associationMappings[$fieldName]) && + ! ($this->associationMappings[$fieldName]['type'] & self::TO_ONE); + } + + /** + * Is this an association that only has a single join column? + * + * @param string $fieldName + * @return bool + */ + public function isAssociationWithSingleJoinColumn($fieldName) + { + return ( + isset($this->associationMappings[$fieldName]) && + isset($this->associationMappings[$fieldName]['joinColumns'][0]) && + !isset($this->associationMappings[$fieldName]['joinColumns'][1]) + ); + } + + /** + * Return the single association join column (if any). + * + * @param string $fieldName + * @throws MappingException + * @return string + */ + public function getSingleAssociationJoinColumnName($fieldName) + { + if ( ! $this->isAssociationWithSingleJoinColumn($fieldName)) { + throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName); + } + return $this->associationMappings[$fieldName]['joinColumns'][0]['name']; + } + + /** + * Return the single association referenced join column name (if any). + * + * @param string $fieldName + * @throws MappingException + * @return string + */ + public function getSingleAssociationReferencedJoinColumnName($fieldName) + { + if ( ! $this->isAssociationWithSingleJoinColumn($fieldName)) { + throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName); + } + return $this->associationMappings[$fieldName]['joinColumns'][0]['referencedColumnName']; + } + + /** + * Used to retrieve a fieldname for either field or association from a given column, + * + * This method is used in foreign-key as primary-key contexts. + * + * @param string $columnName + * @throws MappingException + * @return string + */ + public function getFieldForColumn($columnName) + { + if (isset($this->fieldNames[$columnName])) { + return $this->fieldNames[$columnName]; + } else { + foreach ($this->associationMappings as $assocName => $mapping) { + if ($this->isAssociationWithSingleJoinColumn($assocName) && + $this->associationMappings[$assocName]['joinColumns'][0]['name'] == $columnName) { + + return $assocName; + } + } + + throw MappingException::noFieldNameFoundForColumn($this->name, $columnName); + } + } + + /** + * Sets the ID generator used to generate IDs for instances of this class. + * + * @param \Doctrine\ORM\Id\AbstractIdGenerator $generator + */ + public function setIdGenerator($generator) + { + $this->idGenerator = $generator; + } + + /** + * Sets definition + * @param array $definition + */ + public function setCustomGeneratorDefinition(array $definition) + { + $this->customGeneratorDefinition = $definition; + } + + /** + * Sets the definition of the sequence ID generator for this class. + * + * The definition must have the following structure: + * + * array( + * 'sequenceName' => 'name', + * 'allocationSize' => 20, + * 'initialValue' => 1 + * 'quoted' => 1 + * ) + * + * + * @param array $definition + */ + public function setSequenceGeneratorDefinition(array $definition) + { + if (isset($definition['name']) && $definition['name'] == '`') { + $definition['name'] = trim($definition['name'], '`'); + $definition['quoted'] = true; + } + + $this->sequenceGeneratorDefinition = $definition; + } + + /** + * Sets the version field mapping used for versioning. Sets the default + * value to use depending on the column type. + * + * @param array $mapping The version field mapping array + * @throws MappingException + * @return void + */ + public function setVersionMapping(array &$mapping) + { + $this->isVersioned = true; + $this->versionField = $mapping['fieldName']; + + if ( ! isset($mapping['default'])) { + if (in_array($mapping['type'], array('integer', 'bigint', 'smallint'))) { + $mapping['default'] = 1; + } else if ($mapping['type'] == 'datetime') { + $mapping['default'] = 'CURRENT_TIMESTAMP'; + } else { + throw MappingException::unsupportedOptimisticLockingType($this->name, $mapping['fieldName'], $mapping['type']); + } + } + } + + /** + * Sets whether this class is to be versioned for optimistic locking. + * + * @param boolean $bool + */ + public function setVersioned($bool) + { + $this->isVersioned = $bool; + } + + /** + * Sets the name of the field that is to be used for versioning if this class is + * versioned for optimistic locking. + * + * @param string $versionField + */ + public function setVersionField($versionField) + { + $this->versionField = $versionField; + } + + /** + * Mark this class as read only, no change tracking is applied to it. + * + * @return void + */ + public function markReadOnly() + { + $this->isReadOnly = true; + } + + /** + * {@inheritDoc} + */ + public function getFieldNames() + { + return array_keys($this->fieldMappings); + } + + /** + * {@inheritDoc} + */ + public function getAssociationNames() + { + return array_keys($this->associationMappings); + } + + /** + * {@inheritDoc} + * @throws InvalidArgumentException + */ + public function getAssociationTargetClass($assocName) + { + if ( ! isset($this->associationMappings[$assocName])) { + throw new InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association."); + } + + return $this->associationMappings[$assocName]['targetEntity']; + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return $this->name; + } + + /** + * Gets the (possibly quoted) identifier column names for safe use in an SQL statement. + * + * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy + * + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + * @return array + */ + public function getQuotedIdentifierColumnNames($platform) + { + $quotedColumnNames = array(); + + foreach ($this->identifier as $idProperty) { + if (isset($this->fieldMappings[$idProperty])) { + $quotedColumnNames[] = isset($this->fieldMappings[$idProperty]['quoted']) + ? $platform->quoteIdentifier($this->fieldMappings[$idProperty]['columnName']) + : $this->fieldMappings[$idProperty]['columnName']; + + continue; + } + + // Association defined as Id field + $joinColumns = $this->associationMappings[$idProperty]['joinColumns']; + $assocQuotedColumnNames = array_map( + function ($joinColumn) use ($platform) { + return isset($joinColumn['quoted']) + ? $platform->quoteIdentifier($joinColumn['name']) + : $joinColumn['name']; + }, + $joinColumns + ); + + $quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames); + } + + return $quotedColumnNames; + } + + /** + * Gets the (possibly quoted) column name of a mapped field for safe use in an SQL statement. + * + * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy + * + * @param string $field + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + * @return string + */ + public function getQuotedColumnName($field, $platform) + { + return isset($this->fieldMappings[$field]['quoted']) + ? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) + : $this->fieldMappings[$field]['columnName']; + } + + /** + * Gets the (possibly quoted) primary table name of this class for safe use in an SQL statement. + * + * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy + * + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + * @return string + */ + public function getQuotedTableName($platform) + { + return isset($this->table['quoted']) ? $platform->quoteIdentifier($this->table['name']) : $this->table['name']; + } + + /** + * Gets the (possibly quoted) name of the join table. + * + * @deprecated Deprecated since version 2.3 in favor of \Doctrine\ORM\Mapping\QuoteStrategy + * + * @param array $assoc + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform + * @return string + */ + public function getQuotedJoinTableName(array $assoc, $platform) + { + return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name']; + } + + /** + * {@inheritDoc} + */ + public function isAssociationInverseSide($fieldName) + { + return isset($this->associationMappings[$fieldName]) && ! $this->associationMappings[$fieldName]['isOwningSide']; + } + + /** + * {@inheritDoc} + */ + public function getAssociationMappedByTargetField($fieldName) + { + return $this->associationMappings[$fieldName]['mappedBy']; + } + + /** + * @param string $targetClass + * @return array + */ + public function getAssociationsByTargetClass($targetClass) + { + $relations = array(); + foreach ($this->associationMappings as $mapping) { + if ($mapping['targetEntity'] == $targetClass) { + $relations[$mapping['fieldName']] = $mapping; + } + } + return $relations; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Column.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Column.php new file mode 100644 index 0000000..b233566 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Column.php @@ -0,0 +1,46 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target({"PROPERTY","ANNOTATION"}) + */ +final class Column implements Annotation +{ + /** @var string */ + public $name; + /** @var mixed */ + public $type = 'string'; + /** @var integer */ + public $length; + /** @var integer */ + public $precision = 0; // The precision for a decimal (exact numeric) column (Applies only for decimal column) + /** @var integer */ + public $scale = 0; // The scale for a decimal (exact numeric) column (Applies only for decimal column) + /** @var boolean */ + public $unique = false; + /** @var boolean */ + public $nullable = false; + /** @var array */ + public $options = array(); + /** @var string */ + public $columnDefinition; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ColumnResult.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ColumnResult.php new file mode 100644 index 0000000..cf5c2b4 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ColumnResult.php @@ -0,0 +1,42 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * References name of a column in the SELECT clause of a SQL query. + * Scalar result types can be included in the query result by specifying this annotation in the metadata. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("ANNOTATION") + */ +final class ColumnResult implements Annotation +{ + + /** + * The name of a column in the SELECT clause of a SQL query + * + * @var string + */ + public $name; + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php new file mode 100644 index 0000000..f31f082 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/CustomIdGenerator.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class CustomIdGenerator implements Annotation +{ + /** @var string */ + public $class; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultNamingStrategy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultNamingStrategy.php new file mode 100644 index 0000000..4c64385 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultNamingStrategy.php @@ -0,0 +1,86 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * The default NamingStrategy + * + * + * @link www.doctrine-project.org + * @since 2.3 + * @author Fabio B. Silva + */ +class DefaultNamingStrategy implements NamingStrategy +{ + /** + * {@inheritdoc} + */ + public function classToTableName($className) + { + if (strpos($className, '\\') !== false) { + return substr($className, strrpos($className, '\\') + 1); + } + + return $className; + } + + /** + * {@inheritdoc} + */ + public function propertyToColumnName($propertyName) + { + return $propertyName; + } + + /** + * {@inheritdoc} + */ + public function referenceColumnName() + { + return 'id'; + } + + /** + * {@inheritdoc} + */ + public function joinColumnName($propertyName) + { + return $propertyName . '_' . $this->referenceColumnName(); + } + + /** + * {@inheritdoc} + */ + public function joinTableName($sourceEntity, $targetEntity, $propertyName = null) + { + return strtolower($this->classToTableName($sourceEntity) . '_' . + $this->classToTableName($targetEntity)); + } + + /** + * {@inheritdoc} + */ + public function joinKeyColumnName($entityName, $referencedColumnName = null) + { + return strtolower($this->classToTableName($entityName) . '_' . + ($referencedColumnName ?: $this->referenceColumnName())); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php new file mode 100644 index 0000000..b5a6fc4 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php @@ -0,0 +1,140 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * A set of rules for determining the physical column, alias and table quotes + * + * @since 2.3 + * @author Fabio B. Silva + */ +class DefaultQuoteStrategy implements QuoteStrategy +{ + /** + * {@inheritdoc} + */ + public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($class->fieldMappings[$fieldName]['quoted']) + ? $platform->quoteIdentifier($class->fieldMappings[$fieldName]['columnName']) + : $class->fieldMappings[$fieldName]['columnName']; + } + + /** + * {@inheritdoc} + */ + public function getTableName(ClassMetadata $class, AbstractPlatform $platform) + { + return isset($class->table['quoted']) + ? $platform->quoteIdentifier($class->table['name']) + : $class->table['name']; + } + + /** + * {@inheritdoc} + */ + public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($definition['quoted']) + ? $platform->quoteIdentifier($definition['sequenceName']) + : $definition['sequenceName']; + } + + /** + * {@inheritdoc} + */ + public function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($joinColumn['quoted']) + ? $platform->quoteIdentifier($joinColumn['name']) + : $joinColumn['name']; + } + + /** + * {@inheritdoc} + */ + public function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($joinColumn['quoted']) + ? $platform->quoteIdentifier($joinColumn['referencedColumnName']) + : $joinColumn['referencedColumnName']; + } + + /** + * {@inheritdoc} + */ + public function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform) + { + return isset($association['joinTable']['quoted']) + ? $platform->quoteIdentifier($association['joinTable']['name']) + : $association['joinTable']['name']; + } + + /** + * {@inheritdoc} + */ + public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform) + { + $quotedColumnNames = array(); + + foreach ($class->identifier as $fieldName) { + if (isset($class->fieldMappings[$fieldName])) { + $quotedColumnNames[] = $this->getColumnName($fieldName, $class, $platform); + + continue; + } + + // Association defined as Id field + $joinColumns = $class->associationMappings[$fieldName]['joinColumns']; + $assocQuotedColumnNames = array_map( + function ($joinColumn) use ($platform) + { + return isset($joinColumn['quoted']) + ? $platform->quoteIdentifier($joinColumn['name']) + : $joinColumn['name']; + }, + $joinColumns + ); + + $quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames); + } + + return $quotedColumnNames; + } + + /** + * {@inheritdoc} + */ + public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null) + { + // Trim the column alias to the maximum identifier length of the platform. + // If the alias is to long, characters are cut off from the beginning. + // And strip non alphanumeric characters + $columnName = $columnName . $counter; + $columnName = substr($columnName, -$platform->getMaxIdentifierLength()); + $columnName = preg_replace('/[^A-Za-z0-9_]/', '', $columnName); + + return $platform->getSQLResultCasing($columnName); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php new file mode 100644 index 0000000..f5cb077 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php @@ -0,0 +1,38 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class DiscriminatorColumn implements Annotation +{ + /** @var string */ + public $name; + /** @var string */ + public $type; + /** @var integer */ + public $length; + /** @var mixed */ + public $fieldName; // field name used in non-object hydration (array/scalar) + /** @var string */ + public $columnDefinition; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php new file mode 100644 index 0000000..d68b85b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/DiscriminatorMap.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class DiscriminatorMap implements Annotation +{ + /** @var array */ + public $value; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php new file mode 100644 index 0000000..bb01896 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -0,0 +1,555 @@ +. + */ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\Common\Annotations\AnnotationReader, + Doctrine\ORM\Mapping\MappingException, + Doctrine\ORM\Mapping\JoinColumn, + Doctrine\ORM\Mapping\Column, + Doctrine\Common\Persistence\Mapping\ClassMetadata, + Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver; + +/** + * The AnnotationDriver reads the mapping metadata from docblock annotations. + * + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel + */ +class AnnotationDriver extends AbstractAnnotationDriver +{ + /** + * {@inheritDoc} + */ + protected $entityAnnotationClasses = array( + 'Doctrine\ORM\Mapping\Entity' => 1, + 'Doctrine\ORM\Mapping\MappedSuperclass' => 2, + ); + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass($className, ClassMetadata $metadata) + { + /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */ + $class = $metadata->getReflectionClass(); + if ( ! $class) { + // this happens when running annotation driver in combination with + // static reflection services. This is not the nicest fix + $class = new \ReflectionClass($metadata->name); + } + + $classAnnotations = $this->reader->getClassAnnotations($class); + + if ($classAnnotations) { + foreach ($classAnnotations as $key => $annot) { + if ( ! is_numeric($key)) { + continue; + } + + $classAnnotations[get_class($annot)] = $annot; + } + } + + // Evaluate Entity annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\Entity'])) { + $entityAnnot = $classAnnotations['Doctrine\ORM\Mapping\Entity']; + if ($entityAnnot->repositoryClass !== null) { + $metadata->setCustomRepositoryClass($entityAnnot->repositoryClass); + } + if ($entityAnnot->readOnly) { + $metadata->markReadOnly(); + } + } else if (isset($classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'])) { + $mappedSuperclassAnnot = $classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass']; + $metadata->setCustomRepositoryClass($mappedSuperclassAnnot->repositoryClass); + $metadata->isMappedSuperclass = true; + } else { + throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className); + } + + // Evaluate Table annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\Table'])) { + $tableAnnot = $classAnnotations['Doctrine\ORM\Mapping\Table']; + $primaryTable = array( + 'name' => $tableAnnot->name, + 'schema' => $tableAnnot->schema + ); + + if ($tableAnnot->indexes !== null) { + foreach ($tableAnnot->indexes as $indexAnnot) { + $index = array('columns' => $indexAnnot->columns); + + if ( ! empty($indexAnnot->name)) { + $primaryTable['indexes'][$indexAnnot->name] = $index; + } else { + $primaryTable['indexes'][] = $index; + } + } + } + + if ($tableAnnot->uniqueConstraints !== null) { + foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) { + $uniqueConstraint = array('columns' => $uniqueConstraintAnnot->columns); + + if ( ! empty($uniqueConstraintAnnot->name)) { + $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint; + } else { + $primaryTable['uniqueConstraints'][] = $uniqueConstraint; + } + } + } + + if ($tableAnnot->options !== null) { + $primaryTable['options'] = $tableAnnot->options; + } + + $metadata->setPrimaryTable($primaryTable); + } + + // Evaluate NamedNativeQueries annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries'])) { + $namedNativeQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries']; + + foreach ($namedNativeQueriesAnnot->value as $namedNativeQuery) { + $metadata->addNamedNativeQuery(array( + 'name' => $namedNativeQuery->name, + 'query' => $namedNativeQuery->query, + 'resultClass' => $namedNativeQuery->resultClass, + 'resultSetMapping' => $namedNativeQuery->resultSetMapping, + )); + } + } + + // Evaluate SqlResultSetMappings annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings'])) { + $sqlResultSetMappingsAnnot = $classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings']; + + foreach ($sqlResultSetMappingsAnnot->value as $resultSetMapping) { + $entities = array(); + $columns = array(); + foreach ($resultSetMapping->entities as $entityResultAnnot) { + $entityResult = array( + 'fields' => array(), + 'entityClass' => $entityResultAnnot->entityClass, + 'discriminatorColumn' => $entityResultAnnot->discriminatorColumn, + ); + + foreach ($entityResultAnnot->fields as $fieldResultAnnot) { + $entityResult['fields'][] = array( + 'name' => $fieldResultAnnot->name, + 'column' => $fieldResultAnnot->column + ); + } + + $entities[] = $entityResult; + } + + foreach ($resultSetMapping->columns as $columnResultAnnot) { + $columns[] = array( + 'name' => $columnResultAnnot->name, + ); + } + + $metadata->addSqlResultSetMapping(array( + 'name' => $resultSetMapping->name, + 'entities' => $entities, + 'columns' => $columns + )); + } + } + + // Evaluate NamedQueries annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedQueries'])) { + $namedQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedQueries']; + + if ( ! is_array($namedQueriesAnnot->value)) { + throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations."); + } + + foreach ($namedQueriesAnnot->value as $namedQuery) { + if ( ! ($namedQuery instanceof \Doctrine\ORM\Mapping\NamedQuery)) { + throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations."); + } + $metadata->addNamedQuery(array( + 'name' => $namedQuery->name, + 'query' => $namedQuery->query + )); + } + } + + // Evaluate InheritanceType annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\InheritanceType'])) { + $inheritanceTypeAnnot = $classAnnotations['Doctrine\ORM\Mapping\InheritanceType']; + $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAnnot->value)); + + if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) { + // Evaluate DiscriminatorColumn annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\DiscriminatorColumn'])) { + $discrColumnAnnot = $classAnnotations['Doctrine\ORM\Mapping\DiscriminatorColumn']; + $metadata->setDiscriminatorColumn(array( + 'name' => $discrColumnAnnot->name, + 'type' => $discrColumnAnnot->type, + 'length' => $discrColumnAnnot->length, + 'columnDefinition' => $discrColumnAnnot->columnDefinition + )); + } else { + $metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255)); + } + + // Evaluate DiscriminatorMap annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\DiscriminatorMap'])) { + $discrMapAnnot = $classAnnotations['Doctrine\ORM\Mapping\DiscriminatorMap']; + $metadata->setDiscriminatorMap($discrMapAnnot->value); + } + } + } + + + // Evaluate DoctrineChangeTrackingPolicy annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy'])) { + $changeTrackingAnnot = $classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy']; + $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAnnot->value)); + } + + // Evaluate annotations on properties/fields + /* @var $property \ReflectionProperty */ + foreach ($class->getProperties() as $property) { + if ($metadata->isMappedSuperclass && ! $property->isPrivate() + || + $metadata->isInheritedField($property->name) + || + $metadata->isInheritedAssociation($property->name)) { + continue; + } + + $mapping = array(); + $mapping['fieldName'] = $property->getName(); + + // Check for JoinColummn/JoinColumns annotations + $joinColumns = array(); + + if ($joinColumnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumn')) { + $joinColumns[] = $this->joinColumnToArray($joinColumnAnnot); + } else if ($joinColumnsAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) { + foreach ($joinColumnsAnnot->value as $joinColumn) { + $joinColumns[] = $this->joinColumnToArray($joinColumn); + } + } + + // Field can only be annotated with one of: + // @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany + if ($columnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Column')) { + if ($columnAnnot->type == null) { + throw MappingException::propertyTypeIsRequired($className, $property->getName()); + } + + $mapping = $this->columnToArray($property->getName(), $columnAnnot); + + if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) { + $mapping['id'] = true; + } + + if ($generatedValueAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\GeneratedValue')) { + $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAnnot->strategy)); + } + + if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Version')) { + $metadata->setVersionMapping($mapping); + } + + $metadata->mapField($mapping); + + // Check for SequenceGenerator/TableGenerator definition + if ($seqGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\SequenceGenerator')) { + $metadata->setSequenceGeneratorDefinition(array( + 'sequenceName' => $seqGeneratorAnnot->sequenceName, + 'allocationSize' => $seqGeneratorAnnot->allocationSize, + 'initialValue' => $seqGeneratorAnnot->initialValue + )); + } else if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) { + throw MappingException::tableIdGeneratorNotImplemented($className); + } else if ($customGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\CustomIdGenerator')) { + $metadata->setCustomGeneratorDefinition(array( + 'class' => $customGeneratorAnnot->class + )); + } + } else if ($oneToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToOne')) { + if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) { + $mapping['id'] = true; + } + + $mapping['targetEntity'] = $oneToOneAnnot->targetEntity; + $mapping['joinColumns'] = $joinColumns; + $mapping['mappedBy'] = $oneToOneAnnot->mappedBy; + $mapping['inversedBy'] = $oneToOneAnnot->inversedBy; + $mapping['cascade'] = $oneToOneAnnot->cascade; + $mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval; + $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch); + $metadata->mapOneToOne($mapping); + } else if ($oneToManyAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) { + $mapping['mappedBy'] = $oneToManyAnnot->mappedBy; + $mapping['targetEntity'] = $oneToManyAnnot->targetEntity; + $mapping['cascade'] = $oneToManyAnnot->cascade; + $mapping['indexBy'] = $oneToManyAnnot->indexBy; + $mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval; + $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch); + + if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) { + $mapping['orderBy'] = $orderByAnnot->value; + } + + $metadata->mapOneToMany($mapping); + } else if ($manyToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToOne')) { + if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) { + $mapping['id'] = true; + } + + $mapping['joinColumns'] = $joinColumns; + $mapping['cascade'] = $manyToOneAnnot->cascade; + $mapping['inversedBy'] = $manyToOneAnnot->inversedBy; + $mapping['targetEntity'] = $manyToOneAnnot->targetEntity; + $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch); + $metadata->mapManyToOne($mapping); + } else if ($manyToManyAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) { + $joinTable = array(); + + if ($joinTableAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinTable')) { + $joinTable = array( + 'name' => $joinTableAnnot->name, + 'schema' => $joinTableAnnot->schema + ); + + foreach ($joinTableAnnot->joinColumns as $joinColumn) { + $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn); + } + + foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) { + $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn); + } + } + + $mapping['joinTable'] = $joinTable; + $mapping['targetEntity'] = $manyToManyAnnot->targetEntity; + $mapping['mappedBy'] = $manyToManyAnnot->mappedBy; + $mapping['inversedBy'] = $manyToManyAnnot->inversedBy; + $mapping['cascade'] = $manyToManyAnnot->cascade; + $mapping['indexBy'] = $manyToManyAnnot->indexBy; + $mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval; + $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch); + + if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) { + $mapping['orderBy'] = $orderByAnnot->value; + } + + $metadata->mapManyToMany($mapping); + } + } + + // Evaluate AssociationOverrides annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\AssociationOverrides'])) { + $associationOverridesAnnot = $classAnnotations['Doctrine\ORM\Mapping\AssociationOverrides']; + + foreach ($associationOverridesAnnot->value as $associationOverride) { + $override = array(); + $fieldName = $associationOverride->name; + + // Check for JoinColummn/JoinColumns annotations + if ($associationOverride->joinColumns) { + $joinColumns = array(); + foreach ($associationOverride->joinColumns as $joinColumn) { + $joinColumns[] = $this->joinColumnToArray($joinColumn); + } + $override['joinColumns'] = $joinColumns; + } + + // Check for JoinTable annotations + if ($associationOverride->joinTable) { + $joinTable = null; + $joinTableAnnot = $associationOverride->joinTable; + $joinTable = array( + 'name' => $joinTableAnnot->name, + 'schema' => $joinTableAnnot->schema + ); + + foreach ($joinTableAnnot->joinColumns as $joinColumn) { + $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn); + } + + foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) { + $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn); + } + + $override['joinTable'] = $joinTable; + } + + $metadata->setAssociationOverride($fieldName, $override); + } + } + + // Evaluate AttributeOverrides annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\AttributeOverrides'])) { + $attributeOverridesAnnot = $classAnnotations['Doctrine\ORM\Mapping\AttributeOverrides']; + foreach ($attributeOverridesAnnot->value as $attributeOverrideAnnot) { + $attributeOverride = $this->columnToArray($attributeOverrideAnnot->name, $attributeOverrideAnnot->column); + $metadata->setAttributeOverride($attributeOverrideAnnot->name, $attributeOverride); + } + } + + // Evaluate @HasLifecycleCallbacks annotation + if (isset($classAnnotations['Doctrine\ORM\Mapping\HasLifecycleCallbacks'])) { + /* @var $method \ReflectionMethod */ + foreach ($class->getMethods() as $method) { + // filter for the declaring class only, callbacks from parents will already be registered. + if ($method->isPublic() && $method->getDeclaringClass()->getName() == $class->name) { + $annotations = $this->reader->getMethodAnnotations($method); + + if ($annotations) { + foreach ($annotations as $key => $annot) { + if ( ! is_numeric($key)) { + continue; + } + $annotations[get_class($annot)] = $annot; + } + } + + if (isset($annotations['Doctrine\ORM\Mapping\PrePersist'])) { + $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::prePersist); + } + + if (isset($annotations['Doctrine\ORM\Mapping\PostPersist'])) { + $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postPersist); + } + + if (isset($annotations['Doctrine\ORM\Mapping\PreUpdate'])) { + $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::preUpdate); + } + + if (isset($annotations['Doctrine\ORM\Mapping\PostUpdate'])) { + $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postUpdate); + } + + if (isset($annotations['Doctrine\ORM\Mapping\PreRemove'])) { + $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::preRemove); + } + + if (isset($annotations['Doctrine\ORM\Mapping\PostRemove'])) { + $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postRemove); + } + + if (isset($annotations['Doctrine\ORM\Mapping\PostLoad'])) { + $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postLoad); + } + + if (isset($annotations['Doctrine\ORM\Mapping\PreFlush'])) { + $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::preFlush); + } + } + } + } + } + + /** + * Attempts to resolve the fetch mode. + * + * @param string $className The class name + * @param string $fetchMode The fetch mode + * @return integer The fetch mode as defined in ClassMetadata + * @throws MappingException If the fetch mode is not valid + */ + private function getFetchMode($className, $fetchMode) + { + if( ! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) { + throw MappingException::invalidFetchMode($className, $fetchMode); + } + + return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode); + } + + /** + * Parse the given JoinColumn as array + * + * @param JoinColumn $joinColumn + * @return array + */ + private function joinColumnToArray(JoinColumn $joinColumn) + { + return array( + 'name' => $joinColumn->name, + 'unique' => $joinColumn->unique, + 'nullable' => $joinColumn->nullable, + 'onDelete' => $joinColumn->onDelete, + 'columnDefinition' => $joinColumn->columnDefinition, + 'referencedColumnName' => $joinColumn->referencedColumnName, + ); + } + + /** + * Parse the given Column as array + * + * @param string $fieldName + * @param Column $column + * @return array + */ + private function columnToArray($fieldName, Column $column) + { + $mapping = array( + 'fieldName' => $fieldName, + 'type' => $column->type, + 'scale' => $column->scale, + 'length' => $column->length, + 'unique' => $column->unique, + 'nullable' => $column->nullable, + 'precision' => $column->precision + ); + + if ($column->options) { + $mapping['options'] = $column->options; + } + + if (isset($column->name)) { + $mapping['columnName'] = $column->name; + } + + if (isset($column->columnDefinition)) { + $mapping['columnDefinition'] = $column->columnDefinition; + } + + return $mapping; + } + + /** + * Factory method for the Annotation Driver + * + * @param array|string $paths + * @param AnnotationReader $reader + * @return AnnotationDriver + */ + static public function create($paths = array(), AnnotationReader $reader = null) + { + if ($reader == null) { + $reader = new AnnotationReader(); + } + + return new self($reader, $paths); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php new file mode 100644 index 0000000..0882c50 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php @@ -0,0 +1,411 @@ +. + */ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\DBAL\Schema\AbstractSchemaManager, + Doctrine\DBAL\Schema\SchemaException, + Doctrine\Common\Persistence\Mapping\Driver\MappingDriver, + Doctrine\Common\Persistence\Mapping\ClassMetadata, + Doctrine\ORM\Mapping\ClassMetadataInfo, + Doctrine\Common\Util\Inflector, + Doctrine\ORM\Mapping\MappingException; + +/** + * The DatabaseDriver reverse engineers the mapping metadata from a database. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Benjamin Eberlei + */ +class DatabaseDriver implements MappingDriver +{ + /** + * @var AbstractSchemaManager + */ + private $_sm; + + /** + * @var array + */ + private $tables = null; + + private $classToTableNames = array(); + + /** + * @var array + */ + private $manyToManyTables = array(); + + /** + * @var array + */ + private $classNamesForTables = array(); + + /** + * @var array + */ + private $fieldNamesForColumns = array(); + + /** + * The namespace for the generated entities. + * + * @var string + */ + private $namespace; + + /** + * + * @param AbstractSchemaManager $schemaManager + */ + public function __construct(AbstractSchemaManager $schemaManager) + { + $this->_sm = $schemaManager; + } + + /** + * Set tables manually instead of relying on the reverse engeneering capabilities of SchemaManager. + * + * @param array $entityTables + * @param array $manyToManyTables + * @return void + */ + public function setTables($entityTables, $manyToManyTables) + { + $this->tables = $this->manyToManyTables = $this->classToTableNames = array(); + foreach ($entityTables as $table) { + $className = $this->getClassNameForTable($table->getName()); + $this->classToTableNames[$className] = $table->getName(); + $this->tables[$table->getName()] = $table; + } + foreach ($manyToManyTables as $table) { + $this->manyToManyTables[$table->getName()] = $table; + } + } + + private function reverseEngineerMappingFromDatabase() + { + if ($this->tables !== null) { + return; + } + + $tables = array(); + + foreach ($this->_sm->listTableNames() as $tableName) { + $tables[$tableName] = $this->_sm->listTableDetails($tableName); + } + + $this->tables = $this->manyToManyTables = $this->classToTableNames = array(); + foreach ($tables as $tableName => $table) { + /* @var $table \Doctrine\DBAL\Schema\Table */ + if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $foreignKeys = $table->getForeignKeys(); + } else { + $foreignKeys = array(); + } + + $allForeignKeyColumns = array(); + foreach ($foreignKeys as $foreignKey) { + $allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns()); + } + + if ( ! $table->hasPrimaryKey()) { + throw new MappingException( + "Table " . $table->getName() . " has no primary key. Doctrine does not ". + "support reverse engineering from tables that don't have a primary key." + ); + } + + $pkColumns = $table->getPrimaryKey()->getColumns(); + sort($pkColumns); + sort($allForeignKeyColumns); + + if ($pkColumns == $allForeignKeyColumns && count($foreignKeys) == 2) { + $this->manyToManyTables[$tableName] = $table; + } else { + // lower-casing is necessary because of Oracle Uppercase Tablenames, + // assumption is lower-case + underscore separated. + $className = $this->getClassNameForTable($tableName); + $this->tables[$tableName] = $table; + $this->classToTableNames[$className] = $tableName; + } + } + } + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass($className, ClassMetadata $metadata) + { + $this->reverseEngineerMappingFromDatabase(); + + if (!isset($this->classToTableNames[$className])) { + throw new \InvalidArgumentException("Unknown class " . $className); + } + + $tableName = $this->classToTableNames[$className]; + + $metadata->name = $className; + $metadata->table['name'] = $tableName; + + $columns = $this->tables[$tableName]->getColumns(); + $indexes = $this->tables[$tableName]->getIndexes(); + try { + $primaryKeyColumns = $this->tables[$tableName]->getPrimaryKey()->getColumns(); + } catch(SchemaException $e) { + $primaryKeyColumns = array(); + } + + if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $foreignKeys = $this->tables[$tableName]->getForeignKeys(); + } else { + $foreignKeys = array(); + } + + $allForeignKeyColumns = array(); + foreach ($foreignKeys as $foreignKey) { + $allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns()); + } + + $ids = array(); + $fieldMappings = array(); + foreach ($columns as $column) { + $fieldMapping = array(); + + if (in_array($column->getName(), $allForeignKeyColumns)) { + continue; + } else if ($primaryKeyColumns && in_array($column->getName(), $primaryKeyColumns)) { + $fieldMapping['id'] = true; + } + + $fieldMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $column->getName(), false); + $fieldMapping['columnName'] = $column->getName(); + $fieldMapping['type'] = strtolower((string) $column->getType()); + + if ($column->getType() instanceof \Doctrine\DBAL\Types\StringType) { + $fieldMapping['length'] = $column->getLength(); + $fieldMapping['fixed'] = $column->getFixed(); + } else if ($column->getType() instanceof \Doctrine\DBAL\Types\IntegerType) { + $fieldMapping['unsigned'] = $column->getUnsigned(); + } + $fieldMapping['nullable'] = $column->getNotNull() ? false : true; + + if (isset($fieldMapping['id'])) { + $ids[] = $fieldMapping; + } else { + $fieldMappings[] = $fieldMapping; + } + } + + if ($ids) { + if (count($ids) == 1) { + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); + } + + foreach ($ids as $id) { + $metadata->mapField($id); + } + } + + foreach ($fieldMappings as $fieldMapping) { + $metadata->mapField($fieldMapping); + } + + foreach ($this->manyToManyTables as $manyTable) { + foreach ($manyTable->getForeignKeys() as $foreignKey) { + // foreign key maps to the table of the current entity, many to many association probably exists + if (strtolower($tableName) == strtolower($foreignKey->getForeignTableName())) { + $myFk = $foreignKey; + $otherFk = null; + foreach ($manyTable->getForeignKeys() as $foreignKey) { + if ($foreignKey != $myFk) { + $otherFk = $foreignKey; + break; + } + } + + if (!$otherFk) { + // the definition of this many to many table does not contain + // enough foreign key information to continue reverse engeneering. + continue; + } + + $localColumn = current($myFk->getColumns()); + $associationMapping = array(); + $associationMapping['fieldName'] = $this->getFieldNameForColumn($manyTable->getName(), current($otherFk->getColumns()), true); + $associationMapping['targetEntity'] = $this->getClassNameForTable($otherFk->getForeignTableName()); + if (current($manyTable->getColumns())->getName() == $localColumn) { + $associationMapping['inversedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true); + $associationMapping['joinTable'] = array( + 'name' => strtolower($manyTable->getName()), + 'joinColumns' => array(), + 'inverseJoinColumns' => array(), + ); + + $fkCols = $myFk->getForeignColumns(); + $cols = $myFk->getColumns(); + for ($i = 0; $i < count($cols); $i++) { + $associationMapping['joinTable']['joinColumns'][] = array( + 'name' => $cols[$i], + 'referencedColumnName' => $fkCols[$i], + ); + } + + $fkCols = $otherFk->getForeignColumns(); + $cols = $otherFk->getColumns(); + for ($i = 0; $i < count($cols); $i++) { + $associationMapping['joinTable']['inverseJoinColumns'][] = array( + 'name' => $cols[$i], + 'referencedColumnName' => $fkCols[$i], + ); + } + } else { + $associationMapping['mappedBy'] = $this->getFieldNameForColumn($manyTable->getName(), current($myFk->getColumns()), true); + } + $metadata->mapManyToMany($associationMapping); + break; + } + } + } + + foreach ($foreignKeys as $foreignKey) { + $foreignTable = $foreignKey->getForeignTableName(); + $cols = $foreignKey->getColumns(); + $fkCols = $foreignKey->getForeignColumns(); + + $localColumn = current($cols); + $associationMapping = array(); + $associationMapping['fieldName'] = $this->getFieldNameForColumn($tableName, $localColumn, true); + $associationMapping['targetEntity'] = $this->getClassNameForTable($foreignTable); + + if ($primaryKeyColumns && in_array($localColumn, $primaryKeyColumns)) { + $associationMapping['id'] = true; + } + + for ($i = 0; $i < count($cols); $i++) { + $associationMapping['joinColumns'][] = array( + 'name' => $cols[$i], + 'referencedColumnName' => $fkCols[$i], + ); + } + + //Here we need to check if $cols are the same as $primaryKeyColums + if (!array_diff($cols,$primaryKeyColumns)) { + $metadata->mapOneToOne($associationMapping); + } else { + $metadata->mapManyToOne($associationMapping); + } + } + } + + /** + * {@inheritDoc} + */ + public function isTransient($className) + { + return true; + } + + /** + * {@inheritDoc} + */ + public function getAllClassNames() + { + $this->reverseEngineerMappingFromDatabase(); + + return array_keys($this->classToTableNames); + } + + /** + * Set class name for a table. + * + * @param string $tableName + * @param string $className + * @return void + */ + public function setClassNameForTable($tableName, $className) + { + $this->classNamesForTables[$tableName] = $className; + } + + /** + * Set field name for a column on a specific table. + * + * @param string $tableName + * @param string $columnName + * @param string $fieldName + * @return void + */ + public function setFieldNameForColumn($tableName, $columnName, $fieldName) + { + $this->fieldNamesForColumns[$tableName][$columnName] = $fieldName; + } + + /** + * Return the mapped class name for a table if it exists. Otherwise return "classified" version. + * + * @param string $tableName + * @return string + */ + private function getClassNameForTable($tableName) + { + if (isset($this->classNamesForTables[$tableName])) { + return $this->namespace . $this->classNamesForTables[$tableName]; + } + + return $this->namespace . Inflector::classify(strtolower($tableName)); + } + + /** + * Return the mapped field name for a column, if it exists. Otherwise return camelized version. + * + * @param string $tableName + * @param string $columnName + * @param boolean $fk Whether the column is a foreignkey or not. + * @return string + */ + private function getFieldNameForColumn($tableName, $columnName, $fk = false) + { + if (isset($this->fieldNamesForColumns[$tableName]) && isset($this->fieldNamesForColumns[$tableName][$columnName])) { + return $this->fieldNamesForColumns[$tableName][$columnName]; + } + + $columnName = strtolower($columnName); + + // Replace _id if it is a foreignkey column + if ($fk) { + $columnName = str_replace('_id', '', $columnName); + } + return Inflector::camelize($columnName); + } + + /** + * Set the namespace for the generated entities. + * + * @param string $namespace + * @return void + */ + public function setNamespace($namespace) + { + $this->namespace = $namespace; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php new file mode 100644 index 0000000..04bf2de --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php @@ -0,0 +1,66 @@ +. + */ + +require_once __DIR__.'/../Annotation.php'; +require_once __DIR__.'/../Entity.php'; +require_once __DIR__.'/../MappedSuperclass.php'; +require_once __DIR__.'/../InheritanceType.php'; +require_once __DIR__.'/../DiscriminatorColumn.php'; +require_once __DIR__.'/../DiscriminatorMap.php'; +require_once __DIR__.'/../Id.php'; +require_once __DIR__.'/../GeneratedValue.php'; +require_once __DIR__.'/../Version.php'; +require_once __DIR__.'/../JoinColumn.php'; +require_once __DIR__.'/../JoinColumns.php'; +require_once __DIR__.'/../Column.php'; +require_once __DIR__.'/../OneToOne.php'; +require_once __DIR__.'/../OneToMany.php'; +require_once __DIR__.'/../ManyToOne.php'; +require_once __DIR__.'/../ManyToMany.php'; +require_once __DIR__.'/../ElementCollection.php'; +require_once __DIR__.'/../Table.php'; +require_once __DIR__.'/../UniqueConstraint.php'; +require_once __DIR__.'/../Index.php'; +require_once __DIR__.'/../JoinTable.php'; +require_once __DIR__.'/../SequenceGenerator.php'; +require_once __DIR__.'/../CustomIdGenerator.php'; +require_once __DIR__.'/../ChangeTrackingPolicy.php'; +require_once __DIR__.'/../OrderBy.php'; +require_once __DIR__.'/../NamedQueries.php'; +require_once __DIR__.'/../NamedQuery.php'; +require_once __DIR__.'/../HasLifecycleCallbacks.php'; +require_once __DIR__.'/../PrePersist.php'; +require_once __DIR__.'/../PostPersist.php'; +require_once __DIR__.'/../PreUpdate.php'; +require_once __DIR__.'/../PostUpdate.php'; +require_once __DIR__.'/../PreRemove.php'; +require_once __DIR__.'/../PostRemove.php'; +require_once __DIR__.'/../PostLoad.php'; +require_once __DIR__.'/../PreFlush.php'; +require_once __DIR__.'/../FieldResult.php'; +require_once __DIR__.'/../ColumnResult.php'; +require_once __DIR__.'/../EntityResult.php'; +require_once __DIR__.'/../NamedNativeQuery.php'; +require_once __DIR__.'/../NamedNativeQueries.php'; +require_once __DIR__.'/../SqlResultSetMapping.php'; +require_once __DIR__.'/../SqlResultSetMappings.php'; +require_once __DIR__.'/../AssociationOverride.php'; +require_once __DIR__.'/../AssociationOverrides.php'; +require_once __DIR__.'/../AttributeOverride.php'; +require_once __DIR__.'/../AttributeOverrides.php'; diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DriverChain.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DriverChain.php new file mode 100644 index 0000000..02d409d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DriverChain.php @@ -0,0 +1,31 @@ +. + */ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain; + +/** + * {@inheritDoc} + * + * @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain instead + */ +class DriverChain extends MappingDriverChain +{ +} \ No newline at end of file diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php new file mode 100644 index 0000000..3d60447 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/PHPDriver.php @@ -0,0 +1,31 @@ +. + */ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver as CommonPHPDriver; + +/** + * {@inheritDoc} + * + * @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver instead + */ +class PHPDriver extends CommonPHPDriver +{ +} \ No newline at end of file diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php new file mode 100644 index 0000000..85221f3 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php @@ -0,0 +1,43 @@ +. +*/ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator; + +/** + * XmlDriver that additionally looks for mapping information in a global file. + * + * @author Fabien Potencier + * @author Benjamin Eberlei + * @license MIT + */ +class SimplifiedXmlDriver extends XmlDriver +{ + const DEFAULT_FILE_EXTENSION = '.orm.xml'; + + /** + * {@inheritDoc} + */ + public function __construct($prefixes, $fileExtension = self::DEFAULT_FILE_EXTENSION) + { + $locator = new SymfonyFileLocator((array) $prefixes, $fileExtension); + parent::__construct($locator, $fileExtension); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php new file mode 100644 index 0000000..d2b8c0f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php @@ -0,0 +1,43 @@ +. +*/ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator; + +/** + * YamlDriver that additionally looks for mapping information in a global file. + * + * @author Fabien Potencier + * @author Benjamin Eberlei + * @license MIT + */ +class SimplifiedYamlDriver extends YamlDriver +{ + const DEFAULT_FILE_EXTENSION = '.orm.yml'; + + /** + * {@inheritDoc} + */ + public function __construct($prefixes, $fileExtension = self::DEFAULT_FILE_EXTENSION) + { + $locator = new SymfonyFileLocator((array) $prefixes, $fileExtension); + parent::__construct($locator, $fileExtension); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php new file mode 100644 index 0000000..6d53f77 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php @@ -0,0 +1,31 @@ +. + */ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver as CommonStaticPHPDriver; + +/** + * {@inheritDoc} + * + * @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver instead + */ +class StaticPHPDriver extends CommonStaticPHPDriver +{ +} \ No newline at end of file diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php new file mode 100644 index 0000000..251b719 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -0,0 +1,713 @@ +. + */ + +namespace Doctrine\ORM\Mapping\Driver; + +use SimpleXMLElement, + Doctrine\Common\Persistence\Mapping\Driver\FileDriver, + Doctrine\Common\Persistence\Mapping\ClassMetadata, + Doctrine\ORM\Mapping\MappingException; + +/** + * XmlDriver is a metadata driver that enables mapping through XML files. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel + */ +class XmlDriver extends FileDriver +{ + const DEFAULT_FILE_EXTENSION = '.dcm.xml'; + + /** + * {@inheritDoc} + */ + public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION) + { + parent::__construct($locator, $fileExtension); + } + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass($className, ClassMetadata $metadata) + { + /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */ + /* @var $xmlRoot SimpleXMLElement */ + $xmlRoot = $this->getElement($className); + + if ($xmlRoot->getName() == 'entity') { + if (isset($xmlRoot['repository-class'])) { + $metadata->setCustomRepositoryClass((string)$xmlRoot['repository-class']); + } + if (isset($xmlRoot['read-only']) && $xmlRoot['read-only'] == "true") { + $metadata->markReadOnly(); + } + } else if ($xmlRoot->getName() == 'mapped-superclass') { + $metadata->setCustomRepositoryClass( + isset($xmlRoot['repository-class']) ? (string)$xmlRoot['repository-class'] : null + ); + $metadata->isMappedSuperclass = true; + } else { + throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className); + } + + // Evaluate attributes + $table = array(); + if (isset($xmlRoot['table'])) { + $table['name'] = (string)$xmlRoot['table']; + } + + $metadata->setPrimaryTable($table); + + // Evaluate named queries + if (isset($xmlRoot->{'named-queries'})) { + foreach ($xmlRoot->{'named-queries'}->{'named-query'} as $namedQueryElement) { + $metadata->addNamedQuery(array( + 'name' => (string)$namedQueryElement['name'], + 'query' => (string)$namedQueryElement['query'] + )); + } + } + + // Evaluate native named queries + if (isset($xmlRoot->{'named-native-queries'})) { + foreach ($xmlRoot->{'named-native-queries'}->{'named-native-query'} as $nativeQueryElement) { + $metadata->addNamedNativeQuery(array( + 'name' => isset($nativeQueryElement['name']) ? (string)$nativeQueryElement['name'] : null, + 'query' => isset($nativeQueryElement->query) ? (string)$nativeQueryElement->query : null, + 'resultClass' => isset($nativeQueryElement['result-class']) ? (string)$nativeQueryElement['result-class'] : null, + 'resultSetMapping' => isset($nativeQueryElement['result-set-mapping']) ? (string)$nativeQueryElement['result-set-mapping'] : null, + )); + } + } + + // Evaluate sql result set mapping + if (isset($xmlRoot->{'sql-result-set-mappings'})) { + foreach ($xmlRoot->{'sql-result-set-mappings'}->{'sql-result-set-mapping'} as $rsmElement) { + $entities = array(); + $columns = array(); + foreach ($rsmElement as $entityElement) { + // + if (isset($entityElement['entity-class'])) { + $entityResult = array( + 'fields' => array(), + 'entityClass' => (string)$entityElement['entity-class'], + 'discriminatorColumn' => isset($entityElement['discriminator-column']) ? (string)$entityElement['discriminator-column'] : null, + ); + + foreach ($entityElement as $fieldElement) { + $entityResult['fields'][] = array( + 'name' => isset($fieldElement['name']) ? (string)$fieldElement['name'] : null, + 'column' => isset($fieldElement['column']) ? (string)$fieldElement['column'] : null, + ); + } + + $entities[] = $entityResult; + } + + // + if (isset($entityElement['name'])) { + $columns[] = array( + 'name' => (string)$entityElement['name'], + ); + } + } + + $metadata->addSqlResultSetMapping(array( + 'name' => (string)$rsmElement['name'], + 'entities' => $entities, + 'columns' => $columns + )); + } + } + + /* not implemented specially anyway. use table = schema.table + if (isset($xmlRoot['schema'])) { + $metadata->table['schema'] = (string)$xmlRoot['schema']; + }*/ + + if (isset($xmlRoot['inheritance-type'])) { + $inheritanceType = (string)$xmlRoot['inheritance-type']; + $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType)); + + if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) { + // Evaluate + if (isset($xmlRoot->{'discriminator-column'})) { + $discrColumn = $xmlRoot->{'discriminator-column'}; + $metadata->setDiscriminatorColumn(array( + 'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null, + 'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null, + 'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null, + 'columnDefinition' => isset($discrColumn['column-definition']) ? (string)$discrColumn['column-definition'] : null + )); + } else { + $metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255)); + } + + // Evaluate + if (isset($xmlRoot->{'discriminator-map'})) { + $map = array(); + foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} as $discrMapElement) { + $map[(string)$discrMapElement['value']] = (string)$discrMapElement['class']; + } + $metadata->setDiscriminatorMap($map); + } + } + } + + + // Evaluate + if (isset($xmlRoot['change-tracking-policy'])) { + $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' + . strtoupper((string)$xmlRoot['change-tracking-policy']))); + } + + // Evaluate + if (isset($xmlRoot->indexes)) { + $metadata->table['indexes'] = array(); + foreach ($xmlRoot->indexes->index as $index) { + $columns = explode(',', (string)$index['columns']); + + if (isset($index['name'])) { + $metadata->table['indexes'][(string)$index['name']] = array( + 'columns' => $columns + ); + } else { + $metadata->table['indexes'][] = array( + 'columns' => $columns + ); + } + } + } + + // Evaluate + if (isset($xmlRoot->{'unique-constraints'})) { + $metadata->table['uniqueConstraints'] = array(); + foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} as $unique) { + $columns = explode(',', (string)$unique['columns']); + + if (isset($unique['name'])) { + $metadata->table['uniqueConstraints'][(string)$unique['name']] = array( + 'columns' => $columns + ); + } else { + $metadata->table['uniqueConstraints'][] = array( + 'columns' => $columns + ); + } + } + } + + if (isset($xmlRoot->options)) { + $metadata->table['options'] = $this->_parseOptions($xmlRoot->options->children()); + } + + // The mapping assignement is done in 2 times as a bug might occurs on some php/xml lib versions + // The internal SimpleXmlIterator get resetted, to this generate a duplicate field exception + $mappings = array(); + // Evaluate mappings + if (isset($xmlRoot->field)) { + foreach ($xmlRoot->field as $fieldMapping) { + $mapping = $this->columnToArray($fieldMapping); + $metadata->mapField($mapping); + } + } + + foreach ($mappings as $mapping) { + $metadata->mapField($mapping); + } + + // Evaluate mappings + $associationIds = array(); + foreach ($xmlRoot->id as $idElement) { + if ((bool)$idElement['association-key'] == true) { + $associationIds[(string)$idElement['name']] = true; + continue; + } + + $mapping = array( + 'id' => true, + 'fieldName' => (string)$idElement['name'] + ); + + if (isset($idElement['type'])) { + $mapping['type'] = (string)$idElement['type']; + } + + if (isset($idElement['length'])) { + $mapping['length'] = (string)$idElement['length']; + } + + if (isset($idElement['column'])) { + $mapping['columnName'] = (string)$idElement['column']; + } + + if (isset($idElement['column-definition'])) { + $mapping['columnDefinition'] = (string)$idElement['column-definition']; + } + + $metadata->mapField($mapping); + + if (isset($idElement->generator)) { + $strategy = isset($idElement->generator['strategy']) ? + (string)$idElement->generator['strategy'] : 'AUTO'; + $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' + . $strategy)); + } + + // Check for SequenceGenerator/TableGenerator definition + if (isset($idElement->{'sequence-generator'})) { + $seqGenerator = $idElement->{'sequence-generator'}; + $metadata->setSequenceGeneratorDefinition(array( + 'sequenceName' => (string)$seqGenerator['sequence-name'], + 'allocationSize' => (string)$seqGenerator['allocation-size'], + 'initialValue' => (string)$seqGenerator['initial-value'] + )); + } else if (isset($idElement->{'custom-id-generator'})) { + $customGenerator = $idElement->{'custom-id-generator'}; + $metadata->setCustomGeneratorDefinition(array( + 'class' => (string) $customGenerator['class'] + )); + } else if (isset($idElement->{'table-generator'})) { + throw MappingException::tableIdGeneratorNotImplemented($className); + } + } + + // Evaluate mappings + if (isset($xmlRoot->{'one-to-one'})) { + foreach ($xmlRoot->{'one-to-one'} as $oneToOneElement) { + $mapping = array( + 'fieldName' => (string)$oneToOneElement['field'], + 'targetEntity' => (string)$oneToOneElement['target-entity'] + ); + + if (isset($associationIds[$mapping['fieldName']])) { + $mapping['id'] = true; + } + + if (isset($oneToOneElement['fetch'])) { + $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$oneToOneElement['fetch']); + } + + if (isset($oneToOneElement['mapped-by'])) { + $mapping['mappedBy'] = (string)$oneToOneElement['mapped-by']; + } else { + if (isset($oneToOneElement['inversed-by'])) { + $mapping['inversedBy'] = (string)$oneToOneElement['inversed-by']; + } + $joinColumns = array(); + + if (isset($oneToOneElement->{'join-column'})) { + $joinColumns[] = $this->joinColumnToArray($oneToOneElement->{'join-column'}); + } else if (isset($oneToOneElement->{'join-columns'})) { + foreach ($oneToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) { + $joinColumns[] = $this->joinColumnToArray($joinColumnElement); + } + } + + $mapping['joinColumns'] = $joinColumns; + } + + if (isset($oneToOneElement->cascade)) { + $mapping['cascade'] = $this->_getCascadeMappings($oneToOneElement->cascade); + } + + if (isset($oneToOneElement['orphan-removal'])) { + $mapping['orphanRemoval'] = (bool)$oneToOneElement['orphan-removal']; + } + + $metadata->mapOneToOne($mapping); + } + } + + // Evaluate mappings + if (isset($xmlRoot->{'one-to-many'})) { + foreach ($xmlRoot->{'one-to-many'} as $oneToManyElement) { + $mapping = array( + 'fieldName' => (string)$oneToManyElement['field'], + 'targetEntity' => (string)$oneToManyElement['target-entity'], + 'mappedBy' => (string)$oneToManyElement['mapped-by'] + ); + + if (isset($oneToManyElement['fetch'])) { + $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$oneToManyElement['fetch']); + } + + if (isset($oneToManyElement->cascade)) { + $mapping['cascade'] = $this->_getCascadeMappings($oneToManyElement->cascade); + } + + if (isset($oneToManyElement['orphan-removal'])) { + $mapping['orphanRemoval'] = (bool)$oneToManyElement['orphan-removal']; + } + + if (isset($oneToManyElement->{'order-by'})) { + $orderBy = array(); + foreach ($oneToManyElement->{'order-by'}->{'order-by-field'} as $orderByField) { + $orderBy[(string)$orderByField['name']] = (string)$orderByField['direction']; + } + $mapping['orderBy'] = $orderBy; + } + + if (isset($oneToManyElement['index-by'])) { + $mapping['indexBy'] = (string)$oneToManyElement['index-by']; + } else if (isset($oneToManyElement->{'index-by'})) { + throw new \InvalidArgumentException(" is not a valid tag"); + } + + $metadata->mapOneToMany($mapping); + } + } + + // Evaluate mappings + if (isset($xmlRoot->{'many-to-one'})) { + foreach ($xmlRoot->{'many-to-one'} as $manyToOneElement) { + $mapping = array( + 'fieldName' => (string)$manyToOneElement['field'], + 'targetEntity' => (string)$manyToOneElement['target-entity'] + ); + + if (isset($associationIds[$mapping['fieldName']])) { + $mapping['id'] = true; + } + + if (isset($manyToOneElement['fetch'])) { + $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToOneElement['fetch']); + } + + if (isset($manyToOneElement['inversed-by'])) { + $mapping['inversedBy'] = (string)$manyToOneElement['inversed-by']; + } + + $joinColumns = array(); + + if (isset($manyToOneElement->{'join-column'})) { + $joinColumns[] = $this->joinColumnToArray($manyToOneElement->{'join-column'}); + } else if (isset($manyToOneElement->{'join-columns'})) { + foreach ($manyToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) { + $joinColumns[] = $this->joinColumnToArray($joinColumnElement); + } + } + + $mapping['joinColumns'] = $joinColumns; + + if (isset($manyToOneElement->cascade)) { + $mapping['cascade'] = $this->_getCascadeMappings($manyToOneElement->cascade); + } + + $metadata->mapManyToOne($mapping); + } + } + + // Evaluate mappings + if (isset($xmlRoot->{'many-to-many'})) { + foreach ($xmlRoot->{'many-to-many'} as $manyToManyElement) { + $mapping = array( + 'fieldName' => (string)$manyToManyElement['field'], + 'targetEntity' => (string)$manyToManyElement['target-entity'] + ); + + if (isset($manyToManyElement['fetch'])) { + $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToManyElement['fetch']); + } + + if (isset($manyToManyElement['orphan-removal'])) { + $mapping['orphanRemoval'] = (bool)$manyToManyElement['orphan-removal']; + } + + if (isset($manyToManyElement['mapped-by'])) { + $mapping['mappedBy'] = (string)$manyToManyElement['mapped-by']; + } else if (isset($manyToManyElement->{'join-table'})) { + if (isset($manyToManyElement['inversed-by'])) { + $mapping['inversedBy'] = (string)$manyToManyElement['inversed-by']; + } + + $joinTableElement = $manyToManyElement->{'join-table'}; + $joinTable = array( + 'name' => (string)$joinTableElement['name'] + ); + + if (isset($joinTableElement['schema'])) { + $joinTable['schema'] = (string)$joinTableElement['schema']; + } + + foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) { + $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement); + } + + foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) { + $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement); + } + + $mapping['joinTable'] = $joinTable; + } + + if (isset($manyToManyElement->cascade)) { + $mapping['cascade'] = $this->_getCascadeMappings($manyToManyElement->cascade); + } + + if (isset($manyToManyElement->{'order-by'})) { + $orderBy = array(); + foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} as $orderByField) { + $orderBy[(string)$orderByField['name']] = (string)$orderByField['direction']; + } + $mapping['orderBy'] = $orderBy; + } + + if (isset($manyToManyElement['index-by'])) { + $mapping['indexBy'] = (string)$manyToManyElement['index-by']; + } else if (isset($manyToManyElement->{'index-by'})) { + throw new \InvalidArgumentException(" is not a valid tag"); + } + + $metadata->mapManyToMany($mapping); + } + } + + // Evaluate association-overrides + if (isset($xmlRoot->{'attribute-overrides'})) { + foreach ($xmlRoot->{'attribute-overrides'}->{'attribute-override'} as $overrideElement) { + $fieldName = (string) $overrideElement['name']; + foreach ($overrideElement->field as $field) { + $mapping = $this->columnToArray($field); + $mapping['fieldName'] = $fieldName; + $metadata->setAttributeOverride($fieldName, $mapping); + } + } + } + + // Evaluate association-overrides + if (isset($xmlRoot->{'association-overrides'})) { + foreach ($xmlRoot->{'association-overrides'}->{'association-override'} as $overrideElement) { + $fieldName = (string) $overrideElement['name']; + $override = array(); + + // Check for join-columns + if (isset($overrideElement->{'join-columns'})) { + $joinColumns = array(); + foreach ($overrideElement->{'join-columns'}->{'join-column'} as $joinColumnElement) { + $joinColumns[] = $this->joinColumnToArray($joinColumnElement); + } + $override['joinColumns'] = $joinColumns; + } + + // Check for join-table + if ($overrideElement->{'join-table'}) { + $joinTable = null; + $joinTableElement = $overrideElement->{'join-table'}; + + $joinTable = array( + 'name' => (string) $joinTableElement['name'], + 'schema' => (string) $joinTableElement['schema'] + ); + + if (isset($joinTableElement->{'join-columns'})) { + foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) { + $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement); + } + } + + if (isset($joinTableElement->{'inverse-join-columns'})) { + foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) { + $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement); + } + } + + $override['joinTable'] = $joinTable; + } + + $metadata->setAssociationOverride($fieldName, $override); + } + } + + // Evaluate + if (isset($xmlRoot->{'lifecycle-callbacks'})) { + foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} as $lifecycleCallback) { + $metadata->addLifecycleCallback((string)$lifecycleCallback['method'], constant('Doctrine\ORM\Events::' . (string)$lifecycleCallback['type'])); + } + } + } + + /** + * Parses (nested) option elements. + * + * @param SimpleXMLElement $options the XML element. + * @return array The options array. + */ + private function _parseOptions(SimpleXMLElement $options) + { + $array = array(); + + /* @var $option SimpleXMLElement */ + foreach ($options as $option) { + if ($option->count()) { + $value = $this->_parseOptions($option->children()); + } else { + $value = (string) $option; + } + + $attr = $option->attributes(); + + if (isset($attr->name)) { + $array[(string) $attr->name] = $value; + } else { + $array[] = $value; + } + } + + return $array; + } + + /** + * Constructs a joinColumn mapping array based on the information + * found in the given SimpleXMLElement. + * + * @param SimpleXMLElement $joinColumnElement the XML element. + * @return array The mapping array. + */ + private function joinColumnToArray(SimpleXMLElement $joinColumnElement) + { + $joinColumn = array( + 'name' => (string)$joinColumnElement['name'], + 'referencedColumnName' => (string)$joinColumnElement['referenced-column-name'] + ); + + if (isset($joinColumnElement['unique'])) { + $joinColumn['unique'] = ((string)$joinColumnElement['unique'] == "false") ? false : true; + } + + if (isset($joinColumnElement['nullable'])) { + $joinColumn['nullable'] = ((string)$joinColumnElement['nullable'] == "false") ? false : true; + } + + if (isset($joinColumnElement['on-delete'])) { + $joinColumn['onDelete'] = (string)$joinColumnElement['on-delete']; + } + + if (isset($joinColumnElement['column-definition'])) { + $joinColumn['columnDefinition'] = (string)$joinColumnElement['column-definition']; + } + + return $joinColumn; + } + + /** + * Parse the given field as array + * + * @param SimpleXMLElement $fieldMapping + * @return array + */ + private function columnToArray(SimpleXMLElement $fieldMapping) + { + $mapping = array( + 'fieldName' => (string) $fieldMapping['name'], + ); + + if (isset($fieldMapping['type'])) { + $mapping['type'] = (string) $fieldMapping['type']; + } + + if (isset($fieldMapping['column'])) { + $mapping['columnName'] = (string) $fieldMapping['column']; + } + + if (isset($fieldMapping['length'])) { + $mapping['length'] = (int) $fieldMapping['length']; + } + + if (isset($fieldMapping['precision'])) { + $mapping['precision'] = (int) $fieldMapping['precision']; + } + + if (isset($fieldMapping['scale'])) { + $mapping['scale'] = (int) $fieldMapping['scale']; + } + + if (isset($fieldMapping['unique'])) { + $mapping['unique'] = ((string) $fieldMapping['unique'] == "false") ? false : true; + } + + if (isset($fieldMapping['nullable'])) { + $mapping['nullable'] = ((string) $fieldMapping['nullable'] == "false") ? false : true; + } + + if (isset($fieldMapping['version']) && $fieldMapping['version']) { + $mapping['version'] = $fieldMapping['version']; + } + + if (isset($fieldMapping['column-definition'])) { + $mapping['columnDefinition'] = (string) $fieldMapping['column-definition']; + } + + if (isset($fieldMapping->options)) { + $mapping['options'] = $this->_parseOptions($fieldMapping->options->children()); + } + + return $mapping; + } + + /** + * Gathers a list of cascade options found in the given cascade element. + * + * @param SimpleXMLElement $cascadeElement the cascade element. + * @return array The list of cascade options. + */ + private function _getCascadeMappings($cascadeElement) + { + $cascades = array(); + /* @var $action SimpleXmlElement */ + foreach ($cascadeElement->children() as $action) { + // According to the JPA specifications, XML uses "cascade-persist" + // instead of "persist". Here, both variations + // are supported because both YAML and Annotation use "persist" + // and we want to make sure that this driver doesn't need to know + // anything about the supported cascading actions + $cascades[] = str_replace('cascade-', '', $action->getName()); + } + return $cascades; + } + + /** + * {@inheritDoc} + */ + protected function loadMappingFile($file) + { + $result = array(); + $xmlElement = simplexml_load_file($file); + + if (isset($xmlElement->entity)) { + foreach ($xmlElement->entity as $entityElement) { + $entityName = (string)$entityElement['name']; + $result[$entityName] = $entityElement; + } + } else if (isset($xmlElement->{'mapped-superclass'})) { + foreach ($xmlElement->{'mapped-superclass'} as $mappedSuperClass) { + $className = (string)$mappedSuperClass['name']; + $result[$className] = $mappedSuperClass; + } + } + + return $result; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php new file mode 100644 index 0000000..4ade739 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -0,0 +1,681 @@ +. + */ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\Common\Persistence\Mapping\ClassMetadata, + Doctrine\Common\Persistence\Mapping\Driver\FileDriver, + Doctrine\ORM\Mapping\MappingException, + Symfony\Component\Yaml\Yaml; + +/** + * The YamlDriver reads the mapping metadata from yaml schema files. + * + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan H. Wage + * @author Roman Borschel + */ +class YamlDriver extends FileDriver +{ + const DEFAULT_FILE_EXTENSION = '.dcm.yml'; + + /** + * {@inheritDoc} + */ + public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION) + { + parent::__construct($locator, $fileExtension); + } + + /** + * {@inheritDoc} + */ + public function loadMetadataForClass($className, ClassMetadata $metadata) + { + /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */ + $element = $this->getElement($className); + + if ($element['type'] == 'entity') { + if (isset($element['repositoryClass'])) { + $metadata->setCustomRepositoryClass($element['repositoryClass']); + } + if (isset($element['readOnly']) && $element['readOnly'] == true) { + $metadata->markReadOnly(); + } + } else if ($element['type'] == 'mappedSuperclass') { + $metadata->setCustomRepositoryClass( + isset($element['repositoryClass']) ? $element['repositoryClass'] : null + ); + $metadata->isMappedSuperclass = true; + } else { + throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className); + } + + // Evaluate root level properties + $table = array(); + if (isset($element['table'])) { + $table['name'] = $element['table']; + } + $metadata->setPrimaryTable($table); + + // Evaluate named queries + if (isset($element['namedQueries'])) { + foreach ($element['namedQueries'] as $name => $queryMapping) { + if (is_string($queryMapping)) { + $queryMapping = array('query' => $queryMapping); + } + + if ( ! isset($queryMapping['name'])) { + $queryMapping['name'] = $name; + } + + $metadata->addNamedQuery($queryMapping); + } + } + + // Evaluate named native queries + if (isset($element['namedNativeQueries'])) { + foreach ($element['namedNativeQueries'] as $name => $mappingElement) { + if (!isset($mappingElement['name'])) { + $mappingElement['name'] = $name; + } + $metadata->addNamedNativeQuery(array( + 'name' => $mappingElement['name'], + 'query' => isset($mappingElement['query']) ? $mappingElement['query'] : null, + 'resultClass' => isset($mappingElement['resultClass']) ? $mappingElement['resultClass'] : null, + 'resultSetMapping' => isset($mappingElement['resultSetMapping']) ? $mappingElement['resultSetMapping'] : null, + )); + } + } + + // Evaluate sql result set mappings + if (isset($element['sqlResultSetMappings'])) { + foreach ($element['sqlResultSetMappings'] as $name => $resultSetMapping) { + if (!isset($resultSetMapping['name'])) { + $resultSetMapping['name'] = $name; + } + + $entities = array(); + $columns = array(); + if (isset($resultSetMapping['entityResult'])) { + foreach ($resultSetMapping['entityResult'] as $entityResultElement) { + $entityResult = array( + 'fields' => array(), + 'entityClass' => isset($entityResultElement['entityClass']) ? $entityResultElement['entityClass'] : null, + 'discriminatorColumn' => isset($entityResultElement['discriminatorColumn']) ? $entityResultElement['discriminatorColumn'] : null, + ); + + if (isset($entityResultElement['fieldResult'])) { + foreach ($entityResultElement['fieldResult'] as $fieldResultElement) { + $entityResult['fields'][] = array( + 'name' => isset($fieldResultElement['name']) ? $fieldResultElement['name'] : null, + 'column' => isset($fieldResultElement['column']) ? $fieldResultElement['column'] : null, + ); + } + } + + $entities[] = $entityResult; + } + } + + + if (isset($resultSetMapping['columnResult'])) { + foreach ($resultSetMapping['columnResult'] as $columnResultAnnot) { + $columns[] = array( + 'name' => isset($columnResultAnnot['name']) ? $columnResultAnnot['name'] : null, + ); + } + } + + $metadata->addSqlResultSetMapping(array( + 'name' => $resultSetMapping['name'], + 'entities' => $entities, + 'columns' => $columns + )); + } + } + + /* not implemented specially anyway. use table = schema.table + if (isset($element['schema'])) { + $metadata->table['schema'] = $element['schema']; + }*/ + + if (isset($element['inheritanceType'])) { + $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($element['inheritanceType']))); + + if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) { + // Evaluate discriminatorColumn + if (isset($element['discriminatorColumn'])) { + $discrColumn = $element['discriminatorColumn']; + $metadata->setDiscriminatorColumn(array( + 'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null, + 'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null, + 'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null, + 'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string)$discrColumn['columnDefinition'] : null + )); + } else { + $metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255)); + } + + // Evaluate discriminatorMap + if (isset($element['discriminatorMap'])) { + $metadata->setDiscriminatorMap($element['discriminatorMap']); + } + } + } + + + // Evaluate changeTrackingPolicy + if (isset($element['changeTrackingPolicy'])) { + $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' + . strtoupper($element['changeTrackingPolicy']))); + } + + // Evaluate indexes + if (isset($element['indexes'])) { + foreach ($element['indexes'] as $name => $index) { + if ( ! isset($index['name'])) { + $index['name'] = $name; + } + + if (is_string($index['columns'])) { + $columns = explode(',', $index['columns']); + } else { + $columns = $index['columns']; + } + + $metadata->table['indexes'][$index['name']] = array( + 'columns' => $columns + ); + } + } + + // Evaluate uniqueConstraints + if (isset($element['uniqueConstraints'])) { + foreach ($element['uniqueConstraints'] as $name => $unique) { + if ( ! isset($unique['name'])) { + $unique['name'] = $name; + } + + if (is_string($unique['columns'])) { + $columns = explode(',', $unique['columns']); + } else { + $columns = $unique['columns']; + } + + $metadata->table['uniqueConstraints'][$unique['name']] = array( + 'columns' => $columns + ); + } + } + + if (isset($element['options'])) { + $metadata->table['options'] = $element['options']; + } + + $associationIds = array(); + if (isset($element['id'])) { + // Evaluate identifier settings + foreach ($element['id'] as $name => $idElement) { + if (isset($idElement['associationKey']) && $idElement['associationKey'] == true) { + $associationIds[$name] = true; + continue; + } + + $mapping = array( + 'id' => true, + 'fieldName' => $name + ); + + if (isset($idElement['type'])) { + $mapping['type'] = $idElement['type']; + } + + if (isset($idElement['column'])) { + $mapping['columnName'] = $idElement['column']; + } + + if (isset($idElement['length'])) { + $mapping['length'] = $idElement['length']; + } + + if (isset($idElement['columnDefinition'])) { + $mapping['columnDefinition'] = $idElement['columnDefinition']; + } + + $metadata->mapField($mapping); + + if (isset($idElement['generator'])) { + $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' + . strtoupper($idElement['generator']['strategy']))); + } + // Check for SequenceGenerator/TableGenerator definition + if (isset($idElement['sequenceGenerator'])) { + $metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']); + } else if (isset($idElement['customIdGenerator'])) { + $customGenerator = $idElement['customIdGenerator']; + $metadata->setCustomGeneratorDefinition(array( + 'class' => (string) $customGenerator['class'] + )); + } else if (isset($idElement['tableGenerator'])) { + throw MappingException::tableIdGeneratorNotImplemented($className); + } + } + } + + // Evaluate fields + if (isset($element['fields'])) { + foreach ($element['fields'] as $name => $fieldMapping) { + + $mapping = $this->columnToArray($name, $fieldMapping); + + if (isset($fieldMapping['id'])) { + $mapping['id'] = true; + if (isset($fieldMapping['generator']['strategy'])) { + $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' + . strtoupper($fieldMapping['generator']['strategy']))); + } + } + + $metadata->mapField($mapping); + } + } + + // Evaluate oneToOne relationships + if (isset($element['oneToOne'])) { + foreach ($element['oneToOne'] as $name => $oneToOneElement) { + $mapping = array( + 'fieldName' => $name, + 'targetEntity' => $oneToOneElement['targetEntity'] + ); + + if (isset($associationIds[$mapping['fieldName']])) { + $mapping['id'] = true; + } + + if (isset($oneToOneElement['fetch'])) { + $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneElement['fetch']); + } + + if (isset($oneToOneElement['mappedBy'])) { + $mapping['mappedBy'] = $oneToOneElement['mappedBy']; + } else { + if (isset($oneToOneElement['inversedBy'])) { + $mapping['inversedBy'] = $oneToOneElement['inversedBy']; + } + + $joinColumns = array(); + + if (isset($oneToOneElement['joinColumn'])) { + $joinColumns[] = $this->joinColumnToArray($oneToOneElement['joinColumn']); + } else if (isset($oneToOneElement['joinColumns'])) { + foreach ($oneToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) { + if ( ! isset($joinColumnElement['name'])) { + $joinColumnElement['name'] = $joinColumnName; + } + + $joinColumns[] = $this->joinColumnToArray($joinColumnElement); + } + } + + $mapping['joinColumns'] = $joinColumns; + } + + if (isset($oneToOneElement['cascade'])) { + $mapping['cascade'] = $oneToOneElement['cascade']; + } + + if (isset($oneToOneElement['orphanRemoval'])) { + $mapping['orphanRemoval'] = (bool)$oneToOneElement['orphanRemoval']; + } + + $metadata->mapOneToOne($mapping); + } + } + + // Evaluate oneToMany relationships + if (isset($element['oneToMany'])) { + foreach ($element['oneToMany'] as $name => $oneToManyElement) { + $mapping = array( + 'fieldName' => $name, + 'targetEntity' => $oneToManyElement['targetEntity'], + 'mappedBy' => $oneToManyElement['mappedBy'] + ); + + if (isset($oneToManyElement['fetch'])) { + $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyElement['fetch']); + } + + if (isset($oneToManyElement['cascade'])) { + $mapping['cascade'] = $oneToManyElement['cascade']; + } + + if (isset($oneToManyElement['orphanRemoval'])) { + $mapping['orphanRemoval'] = (bool)$oneToManyElement['orphanRemoval']; + } + + if (isset($oneToManyElement['orderBy'])) { + $mapping['orderBy'] = $oneToManyElement['orderBy']; + } + + if (isset($oneToManyElement['indexBy'])) { + $mapping['indexBy'] = $oneToManyElement['indexBy']; + } + + $metadata->mapOneToMany($mapping); + } + } + + // Evaluate manyToOne relationships + if (isset($element['manyToOne'])) { + foreach ($element['manyToOne'] as $name => $manyToOneElement) { + $mapping = array( + 'fieldName' => $name, + 'targetEntity' => $manyToOneElement['targetEntity'] + ); + + if (isset($associationIds[$mapping['fieldName']])) { + $mapping['id'] = true; + } + + if (isset($manyToOneElement['fetch'])) { + $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneElement['fetch']); + } + + if (isset($manyToOneElement['inversedBy'])) { + $mapping['inversedBy'] = $manyToOneElement['inversedBy']; + } + + $joinColumns = array(); + + if (isset($manyToOneElement['joinColumn'])) { + $joinColumns[] = $this->joinColumnToArray($manyToOneElement['joinColumn']); + } else if (isset($manyToOneElement['joinColumns'])) { + foreach ($manyToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) { + if ( ! isset($joinColumnElement['name'])) { + $joinColumnElement['name'] = $joinColumnName; + } + + $joinColumns[] = $this->joinColumnToArray($joinColumnElement); + } + } + + $mapping['joinColumns'] = $joinColumns; + + if (isset($manyToOneElement['cascade'])) { + $mapping['cascade'] = $manyToOneElement['cascade']; + } + + $metadata->mapManyToOne($mapping); + } + } + + // Evaluate manyToMany relationships + if (isset($element['manyToMany'])) { + foreach ($element['manyToMany'] as $name => $manyToManyElement) { + $mapping = array( + 'fieldName' => $name, + 'targetEntity' => $manyToManyElement['targetEntity'] + ); + + if (isset($manyToManyElement['fetch'])) { + $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyElement['fetch']); + } + + if (isset($manyToManyElement['mappedBy'])) { + $mapping['mappedBy'] = $manyToManyElement['mappedBy']; + } else if (isset($manyToManyElement['joinTable'])) { + + $joinTableElement = $manyToManyElement['joinTable']; + $joinTable = array( + 'name' => $joinTableElement['name'] + ); + + if (isset($joinTableElement['schema'])) { + $joinTable['schema'] = $joinTableElement['schema']; + } + + foreach ($joinTableElement['joinColumns'] as $joinColumnName => $joinColumnElement) { + if ( ! isset($joinColumnElement['name'])) { + $joinColumnElement['name'] = $joinColumnName; + } + + $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement); + } + + foreach ($joinTableElement['inverseJoinColumns'] as $joinColumnName => $joinColumnElement) { + if ( ! isset($joinColumnElement['name'])) { + $joinColumnElement['name'] = $joinColumnName; + } + + $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement); + } + + $mapping['joinTable'] = $joinTable; + } + + if (isset($manyToManyElement['inversedBy'])) { + $mapping['inversedBy'] = $manyToManyElement['inversedBy']; + } + + if (isset($manyToManyElement['cascade'])) { + $mapping['cascade'] = $manyToManyElement['cascade']; + } + + if (isset($manyToManyElement['orderBy'])) { + $mapping['orderBy'] = $manyToManyElement['orderBy']; + } + + if (isset($manyToManyElement['indexBy'])) { + $mapping['indexBy'] = $manyToManyElement['indexBy']; + } + + if (isset($manyToManyElement['orphanRemoval'])) { + $mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval']; + } + + $metadata->mapManyToMany($mapping); + } + } + + // Evaluate associationOverride + if (isset($element['associationOverride']) && is_array($element['associationOverride'])) { + + foreach ($element['associationOverride'] as $fieldName => $associationOverrideElement) { + $override = array(); + + // Check for joinColumn + if (isset($associationOverrideElement['joinColumn'])) { + $joinColumns = array(); + foreach ($associationOverrideElement['joinColumn'] as $name => $joinColumnElement) { + if ( ! isset($joinColumnElement['name'])) { + $joinColumnElement['name'] = $name; + } + $joinColumns[] = $this->joinColumnToArray($joinColumnElement); + } + $override['joinColumns'] = $joinColumns; + } + + // Check for joinTable + if (isset($associationOverrideElement['joinTable'])) { + + $joinTableElement = $associationOverrideElement['joinTable']; + $joinTable = array( + 'name' => $joinTableElement['name'] + ); + + if (isset($joinTableElement['schema'])) { + $joinTable['schema'] = $joinTableElement['schema']; + } + + foreach ($joinTableElement['joinColumns'] as $name => $joinColumnElement) { + if ( ! isset($joinColumnElement['name'])) { + $joinColumnElement['name'] = $name; + } + + $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement); + } + + foreach ($joinTableElement['inverseJoinColumns'] as $name => $joinColumnElement) { + if ( ! isset($joinColumnElement['name'])) { + $joinColumnElement['name'] = $name; + } + + $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement); + } + + $override['joinTable'] = $joinTable; + } + + $metadata->setAssociationOverride($fieldName, $override); + } + } + + // Evaluate associationOverride + if (isset($element['attributeOverride']) && is_array($element['attributeOverride'])) { + + foreach ($element['attributeOverride'] as $fieldName => $attributeOverrideElement) { + $mapping = $this->columnToArray($fieldName, $attributeOverrideElement); + $metadata->setAttributeOverride($fieldName, $mapping); + } + } + + // Evaluate lifeCycleCallbacks + if (isset($element['lifecycleCallbacks'])) { + foreach ($element['lifecycleCallbacks'] as $type => $methods) { + foreach ($methods as $method) { + $metadata->addLifecycleCallback($method, constant('Doctrine\ORM\Events::' . $type)); + } + } + } + } + + /** + * Constructs a joinColumn mapping array based on the information + * found in the given join column element. + * + * @param array $joinColumnElement The array join column element + * @return array The mapping array. + */ + private function joinColumnToArray($joinColumnElement) + { + $joinColumn = array(); + if (isset($joinColumnElement['referencedColumnName'])) { + $joinColumn['referencedColumnName'] = (string) $joinColumnElement['referencedColumnName']; + } + + if (isset($joinColumnElement['name'])) { + $joinColumn['name'] = (string) $joinColumnElement['name']; + } + + if (isset($joinColumnElement['fieldName'])) { + $joinColumn['fieldName'] = (string) $joinColumnElement['fieldName']; + } + + if (isset($joinColumnElement['unique'])) { + $joinColumn['unique'] = (bool) $joinColumnElement['unique']; + } + + if (isset($joinColumnElement['nullable'])) { + $joinColumn['nullable'] = (bool) $joinColumnElement['nullable']; + } + + if (isset($joinColumnElement['onDelete'])) { + $joinColumn['onDelete'] = $joinColumnElement['onDelete']; + } + + if (isset($joinColumnElement['columnDefinition'])) { + $joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition']; + } + + return $joinColumn; + } + + /** + * Parse the given column as array + * + * @param string $fieldName + * @param array $column + * @return array + */ + private function columnToArray($fieldName, $column) + { + $mapping = array( + 'fieldName' => $fieldName + ); + + if (isset($column['type'])) { + $params = explode('(', $column['type']); + $column['type'] = $params[0]; + $mapping['type'] = $column['type']; + + if (isset($params[1])) { + $column['length'] = substr($params[1], 0, strlen($params[1]) - 1); + } + } + + if (isset($column['column'])) { + $mapping['columnName'] = $column['column']; + } + + if (isset($column['length'])) { + $mapping['length'] = $column['length']; + } + + if (isset($column['precision'])) { + $mapping['precision'] = $column['precision']; + } + + if (isset($column['scale'])) { + $mapping['scale'] = $column['scale']; + } + + if (isset($column['unique'])) { + $mapping['unique'] = (bool)$column['unique']; + } + + if (isset($column['options'])) { + $mapping['options'] = $column['options']; + } + + if (isset($column['nullable'])) { + $mapping['nullable'] = $column['nullable']; + } + + if (isset($column['version']) && $column['version']) { + $mapping['version'] = $column['version']; + } + + if (isset($column['columnDefinition'])) { + $mapping['columnDefinition'] = $column['columnDefinition']; + } + + return $mapping; + } + + /** + * {@inheritDoc} + */ + protected function loadMappingFile($file) + { + return Yaml::parse($file); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ElementCollection.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ElementCollection.php new file mode 100644 index 0000000..f3f4f4c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ElementCollection.php @@ -0,0 +1,31 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("ALL") + * @todo check available targets + */ +final class ElementCollection implements Annotation +{ + /** @var string */ + public $tableName; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Entity.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Entity.php new file mode 100644 index 0000000..d1b4eb2 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Entity.php @@ -0,0 +1,32 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class Entity implements Annotation +{ + /** @var string */ + public $repositoryClass; + /** @var boolean */ + public $readOnly = false; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/EntityResult.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/EntityResult.php new file mode 100644 index 0000000..af26a11 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/EntityResult.php @@ -0,0 +1,58 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * References an entity in the SELECT clause of a SQL query. + * If this annotation is used, the SQL statement should select all of the columns that are mapped to the entity object. + * This should include foreign key columns to related entities. + * The results obtained when insufficient data is available are undefined. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("ANNOTATION") + */ +final class EntityResult implements Annotation +{ + + /** + * The class of the result + * + * @var string + */ + public $entityClass; + + /** + * Maps the columns specified in the SELECT list of the query to the properties or fields of the entity class. + * + * @var array<\Doctrine\ORM\Mapping\FieldResult> + */ + public $fields = array(); + + /** + * Specifies the column name of the column in the SELECT list that is used to determine the type of the entity instance. + * + * @var string + */ + public $discriminatorColumn; + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/FieldResult.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/FieldResult.php new file mode 100644 index 0000000..ee330b2 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/FieldResult.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * Is used to map the columns specified in the SELECT list of the query to the properties or fields of the entity class. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("ANNOTATION") + */ +final class FieldResult implements Annotation +{ + + /** + * Name of the column in the SELECT clause. + * + * @var string + */ + public $name; + + /** + * Name of the persistent field or property of the class. + * + * @var string + */ + public $column; + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/GeneratedValue.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/GeneratedValue.php new file mode 100644 index 0000000..d128d16 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/GeneratedValue.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class GeneratedValue implements Annotation +{ + /** @var string */ + public $strategy = 'AUTO'; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php new file mode 100644 index 0000000..313ece3 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class HasLifecycleCallbacks implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Id.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Id.php new file mode 100644 index 0000000..6c9bcef --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Id.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class Id implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Index.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Index.php new file mode 100644 index 0000000..51f037a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Index.php @@ -0,0 +1,32 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("ANNOTATION") + */ +final class Index implements Annotation +{ + /** @var string */ + public $name; + /** @var array */ + public $columns; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/InheritanceType.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/InheritanceType.php new file mode 100644 index 0000000..d9a2471 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/InheritanceType.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class InheritanceType implements Annotation +{ + /** @var string */ + public $value; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinColumn.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinColumn.php new file mode 100644 index 0000000..8c9bc10 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinColumn.php @@ -0,0 +1,42 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target({"PROPERTY","ANNOTATION"}) + */ +final class JoinColumn implements Annotation +{ + /** @var string */ + public $name; + /** @var string */ + public $referencedColumnName = 'id'; + /** @var boolean */ + public $unique = false; + /** @var boolean */ + public $nullable = true; + /** @var mixed */ + public $onDelete; + /** @var string */ + public $columnDefinition; + /** @var string */ + public $fieldName; // field name used in non-object hydration (array/scalar) +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinColumns.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinColumns.php new file mode 100644 index 0000000..8d4c045 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinColumns.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class JoinColumns implements Annotation +{ + /** @var array<\Doctrine\ORM\Mapping\JoinColumn> */ + public $value; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinTable.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinTable.php new file mode 100644 index 0000000..7fb69cb --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/JoinTable.php @@ -0,0 +1,36 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target({"PROPERTY","ANNOTATION"}) + */ +final class JoinTable implements Annotation +{ + /** @var string */ + public $name; + /** @var string */ + public $schema; + /** @var array<\Doctrine\ORM\Mapping\JoinColumn> */ + public $joinColumns = array(); + /** @var array<\Doctrine\ORM\Mapping\JoinColumn> */ + public $inverseJoinColumns = array(); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ManyToMany.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ManyToMany.php new file mode 100644 index 0000000..9c79689 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ManyToMany.php @@ -0,0 +1,42 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class ManyToMany implements Annotation +{ + /** @var string */ + public $targetEntity; + /** @var string */ + public $mappedBy; + /** @var string */ + public $inversedBy; + /** @var array */ + public $cascade; + /** @var string */ + public $fetch = 'LAZY'; + /** @var boolean */ + public $orphanRemoval = false; + /** @var string */ + public $indexBy; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ManyToOne.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ManyToOne.php new file mode 100644 index 0000000..eb09755 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ManyToOne.php @@ -0,0 +1,36 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class ManyToOne implements Annotation +{ + /** @var string */ + public $targetEntity; + /** @var array */ + public $cascade; + /** @var string */ + public $fetch = 'LAZY'; + /** @var string */ + public $inversedBy; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappedSuperclass.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappedSuperclass.php new file mode 100644 index 0000000..b551610 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappedSuperclass.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class MappedSuperclass implements Annotation +{ + /** @var string */ + public $repositoryClass; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappingException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappingException.php new file mode 100644 index 0000000..fd4e1a8 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/MappingException.php @@ -0,0 +1,441 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * A MappingException indicates that something is wrong with the mapping setup. + * + * @since 2.0 + */ +class MappingException extends \Doctrine\ORM\ORMException +{ + public static function pathRequired() + { + return new self("Specifying the paths to your entities is required ". + "in the AnnotationDriver to retrieve all class names."); + } + + public static function identifierRequired($entityName) + { + if (null !== ($parent = get_parent_class($entityName))) { + return new self(sprintf( + 'No identifier/primary key specified for Entity "%s" sub class of "%s". Every Entity must have an identifier/primary key.', + $entityName, $parent + )); + } + + return new self(sprintf( + 'No identifier/primary key specified for Entity "%s". Every Entity must have an identifier/primary key.', + $entityName + )); + + } + + public static function invalidInheritanceType($entityName, $type) + { + return new self("The inheritance type '$type' specified for '$entityName' does not exist."); + } + + public static function generatorNotAllowedWithCompositeId() + { + return new self("Id generators can't be used with a composite id."); + } + + public static function missingFieldName($entity) + { + return new self("The field or association mapping misses the 'fieldName' attribute in entity '$entity'."); + } + + public static function missingTargetEntity($fieldName) + { + return new self("The association mapping '$fieldName' misses the 'targetEntity' attribute."); + } + + public static function missingSourceEntity($fieldName) + { + return new self("The association mapping '$fieldName' misses the 'sourceEntity' attribute."); + } + + public static function mappingFileNotFound($entityName, $fileName) + { + return new self("No mapping file found named '$fileName' for class '$entityName'."); + } + + /** + * Exception for invalid property name override. + * + * @param string $className The entity's name + * @param string $fieldName + */ + public static function invalidOverrideFieldName($className, $fieldName) + { + return new self("Invalid field override named '$fieldName' for class '$className'."); + } + + /** + * Exception for invalid property type override. + * + * @param string $className The entity's name + * @param string $fieldName + */ + public static function invalidOverrideFieldType($className, $fieldName) + { + return new self("The column type of attribute '$fieldName' on class '$className' could not be changed."); + } + + public static function mappingNotFound($className, $fieldName) + { + return new self("No mapping found for field '$fieldName' on class '$className'."); + } + + public static function queryNotFound($className, $queryName) + { + return new self("No query found named '$queryName' on class '$className'."); + } + + public static function resultMappingNotFound($className, $resultName) + { + return new self("No result set mapping found named '$resultName' on class '$className'."); + } + + public static function emptyQueryMapping($entity, $queryName) + { + return new self('Query named "'.$queryName.'" in "'.$entity.'" could not be empty.'); + } + + public static function nameIsMandatoryForQueryMapping($className) + { + return new self("Query name on entity class '$className' is not defined."); + } + + public static function missingQueryMapping($entity, $queryName) + { + return new self('Query named "'.$queryName.'" in "'.$entity.' requires a result class or result set mapping.'); + } + + public static function missingResultSetMappingEntity($entity, $resultName) + { + return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a entity class name.'); + } + + public static function missingResultSetMappingFieldName($entity, $resultName) + { + return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a field name.'); + } + + public static function nameIsMandatoryForSqlResultSetMapping($className) + { + return new self("Result set mapping name on entity class '$className' is not defined."); + } + + public static function oneToManyRequiresMappedBy($fieldName) + { + return new self("OneToMany mapping on field '$fieldName' requires the 'mappedBy' attribute."); + } + + public static function joinTableRequired($fieldName) + { + return new self("The mapping of field '$fieldName' requires an the 'joinTable' attribute."); + } + + /** + * Called if a required option was not found but is required + * + * @param string $field which field cannot be processed? + * @param string $expectedOption which option is required + * @param string $hint Can optionally be used to supply a tip for common mistakes, + * e.g. "Did you think of the plural s?" + * @return MappingException + */ + static function missingRequiredOption($field, $expectedOption, $hint = '') + { + $message = "The mapping of field '{$field}' is invalid: The option '{$expectedOption}' is required."; + + if ( ! empty($hint)) { + $message .= ' (Hint: ' . $hint . ')'; + } + + return new self($message); + } + + /** + * Generic exception for invalid mappings. + * + * @param string $fieldName + */ + public static function invalidMapping($fieldName) + { + return new self("The mapping of field '$fieldName' is invalid."); + } + + /** + * Exception for reflection exceptions - adds the entity name, + * because there might be long classnames that will be shortened + * within the stacktrace + * + * @param string $entity The entity's name + * @param \ReflectionException $previousException + */ + public static function reflectionFailure($entity, \ReflectionException $previousException) + { + return new self('An error occurred in ' . $entity, 0, $previousException); + } + + public static function joinColumnMustPointToMappedField($className, $joinColumn) + { + return new self('The column ' . $joinColumn . ' must be mapped to a field in class ' + . $className . ' since it is referenced by a join column of another class.'); + } + + public static function classIsNotAValidEntityOrMappedSuperClass($className) + { + if (null !== ($parent = get_parent_class($className))) { + return new self(sprintf( + 'Class "%s" sub class of "%s" is not a valid entity or mapped super class.', + $className, $parent + )); + } + + return new self(sprintf( + 'Class "%s" is not a valid entity or mapped super class.', + $className + )); + } + + public static function propertyTypeIsRequired($className, $propertyName) + { + return new self("The attribute 'type' is required for the column description of property ".$className."::\$".$propertyName."."); + } + + public static function tableIdGeneratorNotImplemented($className) + { + return new self("TableIdGenerator is not yet implemented for use with class ".$className); + } + + /** + * @param string $entity The entity's name + * @param string $fieldName The name of the field that was already declared + */ + public static function duplicateFieldMapping($entity, $fieldName) + { + return new self('Property "'.$fieldName.'" in "'.$entity.'" was already declared, but it must be declared only once'); + } + + public static function duplicateAssociationMapping($entity, $fieldName) + { + return new self('Property "'.$fieldName.'" in "'.$entity.'" was already declared, but it must be declared only once'); + } + + public static function duplicateQueryMapping($entity, $queryName) + { + return new self('Query named "'.$queryName.'" in "'.$entity.'" was already declared, but it must be declared only once'); + } + + public static function duplicateResultSetMapping($entity, $resultName) + { + return new self('Result set mapping named "'.$resultName.'" in "'.$entity.'" was already declared, but it must be declared only once'); + } + + public static function singleIdNotAllowedOnCompositePrimaryKey($entity) + { + return new self('Single id is not allowed on composite primary key in entity '.$entity); + } + + public static function unsupportedOptimisticLockingType($entity, $fieldName, $unsupportedType) + { + return new self('Locking type "'.$unsupportedType.'" (specified in "'.$entity.'", field "'.$fieldName.'") ' + .'is not supported by Doctrine.' + ); + } + + public static function fileMappingDriversRequireConfiguredDirectoryPath($path = null) + { + if ( ! empty($path)) { + $path = '[' . $path . ']'; + } + + return new self( + 'File mapping drivers must have a valid directory path, ' . + 'however the given path ' . $path . ' seems to be incorrect!' + ); + } + + /** + * Throws an exception that indicates that a class used in a discriminator map does not exist. + * An example would be an outdated (maybe renamed) classname. + * + * @param string $className The class that could not be found + * @param string $owningClass The class that declares the discriminator map. + * @return self + */ + public static function invalidClassInDiscriminatorMap($className, $owningClass) + { + return new self( + "Entity class '$className' used in the discriminator map of class '$owningClass' ". + "does not exist." + ); + } + + public static function duplicateDiscriminatorEntry($className, array $entries, array $map) + { + return new self( + "The entries " . implode(', ', $entries) . " in discriminator map of class '" . $className . "' is duplicated. " . + "If the discriminator map is automatically generated you have to convert it to an explicit discriminator map now. " . + "The entries of the current map are: @DiscriminatorMap({" . implode(', ', array_map( + function($a, $b) { return "'$a': '$b'"; }, array_keys($map), array_values($map) + )) . "})" + ); + } + + public static function missingDiscriminatorMap($className) + { + return new self("Entity class '$className' is using inheritance but no discriminator map was defined."); + } + + public static function missingDiscriminatorColumn($className) + { + return new self("Entity class '$className' is using inheritance but no discriminator column was defined."); + } + + public static function invalidDiscriminatorColumnType($className, $type) + { + return new self("Discriminator column type on entity class '$className' is not allowed to be '$type'. 'string' or 'integer' type variables are suggested!"); + } + + public static function nameIsMandatoryForDiscriminatorColumns($className) + { + return new self("Discriminator column name on entity class '$className' is not defined."); + } + + public static function cannotVersionIdField($className, $fieldName) + { + return new self("Setting Id field '$fieldName' as versionale in entity class '$className' is not supported."); + } + + public static function sqlConversionNotAllowedForIdentifiers($className, $fieldName, $type) + { + return new self("It is not possible to set id field '$fieldName' to type '$type' in entity class '$className'. The type '$type' requires conversion SQL which is not allowed for identifiers."); + } + + /** + * @param string $className + * @param string $columnName + * @return self + */ + public static function duplicateColumnName($className, $columnName) + { + return new self("Duplicate definition of column '".$columnName."' on entity '".$className."' in a field or discriminator column mapping."); + } + + public static function illegalToManyAssocationOnMappedSuperclass($className, $field) + { + return new self("It is illegal to put an inverse side one-to-many or many-to-many association on mapped superclass '".$className."#".$field."'."); + } + + /** + * @param string $className + * @param string $targetEntity + * @param string $targetField + * @return self + */ + public static function cannotMapCompositePrimaryKeyEntitiesAsForeignId($className, $targetEntity, $targetField) + { + return new self("It is not possible to map entity '".$className."' with a composite primary key ". + "as part of the primary key of another entity '".$targetEntity."#".$targetField."'."); + } + + public static function noSingleAssociationJoinColumnFound($className, $field) + { + return new self("'$className#$field' is not an association with a single join column."); + } + + public static function noFieldNameFoundForColumn($className, $column) + { + return new self("Cannot find a field on '$className' that is mapped to column '$column'. Either the ". + "field does not exist or an association exists but it has multiple join columns."); + } + + public static function illegalOrphanRemovalOnIdentifierAssociation($className, $field) + { + return new self("The orphan removal option is not allowed on an association that is ". + "part of the identifier in '$className#$field'."); + } + + public static function illegalOrphanRemoval($className, $field) + { + return new self("Orphan removal is only allowed on one-to-one and one-to-many ". + "associations, but " . $className."#" .$field . " is not."); + } + + public static function illegalInverseIdentifierAssocation($className, $field) + { + return new self("An inverse association is not allowed to be identifier in '$className#$field'."); + } + + public static function illegalToManyIdentifierAssoaction($className, $field) + { + return new self("Many-to-many or one-to-many associations are not allowed to be identifier in '$className#$field'."); + } + + public static function noInheritanceOnMappedSuperClass($className) + { + return new self("Its not supported to define inheritance information on a mapped superclass '" . $className . "'."); + } + + public static function mappedClassNotPartOfDiscriminatorMap($className, $rootClassName) + { + return new self( + "Entity '" . $className . "' has to be part of the discriminator map of '" . $rootClassName . "' " . + "to be properly mapped in the inheritance hierachy. Alternatively you can make '".$className."' an abstract class " . + "to avoid this exception from occuring." + ); + } + + public static function lifecycleCallbackMethodNotFound($className, $methodName) + { + return new self("Entity '" . $className . "' has no method '" . $methodName . "' to be registered as lifecycle callback."); + } + + public static function invalidFetchMode($className, $annotation) + { + return new self("Entity '" . $className . "' has a mapping with invalid fetch mode '" . $annotation . "'"); + } + + public static function compositeKeyAssignedIdGeneratorRequired($className) + { + return new self("Entity '". $className . "' has a composite identifier but uses an ID generator other than manually assigning (Identity, Sequence). This is not supported."); + } + + public static function invalidTargetEntityClass($targetEntity, $sourceEntity, $associationName) + { + return new self("The target-entity " . $targetEntity . " cannot be found in '" . $sourceEntity."#".$associationName."'."); + } + + public static function invalidCascadeOption(array $cascades, $className, $propertyName) + { + $cascades = implode(", ", array_map(function ($e) { return "'" . $e . "'"; }, $cascades)); + return new self(sprintf( + "You have specified invalid cascade options for %s::$%s: %s; available options: 'remove', 'persist', 'refresh', 'merge', and 'detach'", + $className, + $propertyName, + $cascades + )); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedNativeQueries.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedNativeQueries.php new file mode 100644 index 0000000..7f5460a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedNativeQueries.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * Is used to specify an array of native SQL named queries. + * The NamedNativeQueries annotation can be applied to an entity or mapped superclass. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("CLASS") + */ +final class NamedNativeQueries implements Annotation +{ + /** + * One or more NamedNativeQuery annotations. + * + * @var array<\Doctrine\ORM\Mapping\NamedNativeQuery> + */ + public $value = array(); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedNativeQuery.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedNativeQuery.php new file mode 100644 index 0000000..f0192ae --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedNativeQuery.php @@ -0,0 +1,63 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * Is used to specify a native SQL named query. + * The NamedNativeQuery annotation can be applied to an entity or mapped superclass. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("ANNOTATION") + */ +final class NamedNativeQuery implements Annotation +{ + + /** + * The name used to refer to the query with the EntityManager methods that create query objects. + * + * @var string + */ + public $name; + + /** + * The SQL query string. + * + * @var string + */ + public $query; + + /** + * The class of the result. + * + * @var string + */ + public $resultClass; + + /** + * The name of a SqlResultSetMapping, as defined in metadata. + * + * @var string + */ + public $resultSetMapping; + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedQueries.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedQueries.php new file mode 100644 index 0000000..14bb479 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedQueries.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class NamedQueries implements Annotation +{ + /** @var array<\Doctrine\ORM\Mapping\NamedQuery> */ + public $value; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedQuery.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedQuery.php new file mode 100644 index 0000000..2826820 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamedQuery.php @@ -0,0 +1,32 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("ANNOTATION") + */ +final class NamedQuery implements Annotation +{ + /** @var string */ + public $name; + /** @var string */ + public $query; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamingStrategy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamingStrategy.php new file mode 100644 index 0000000..a6acac2 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/NamingStrategy.php @@ -0,0 +1,82 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * A set of rules for determining the physical column and table names + * + * + * @link www.doctrine-project.org + * @since 2.3 + * @author Fabio B. Silva + */ +interface NamingStrategy +{ + /** + * Return a table name for an entity class + * + * @param string $className The fully-qualified class name + * @return string A table name + */ + function classToTableName($className); + + /** + * Return a column name for a property + * + * @param string $propertyName A property + * @return string A column name + */ + function propertyToColumnName($propertyName); + + /** + * Return the default reference column name + * + * @return string A column name + */ + function referenceColumnName(); + + /** + * Return a join column name for a property + * + * @param string $propertyName A property + * @return string A join column name + */ + function joinColumnName($propertyName); + + /** + * Return a join table name + * + * @param string $sourceEntity The source entity + * @param string $targetEntity The target entity + * @param string $propertyName A property + * @return string A join table name + */ + function joinTableName($sourceEntity, $targetEntity, $propertyName = null); + + /** + * Return the foreign key column name for the given parameters + * + * @param string $entityName A entity + * @param string $referencedColumnName A property + * @return string A join column name + */ + function joinKeyColumnName($entityName, $referencedColumnName = null); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OneToMany.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OneToMany.php new file mode 100644 index 0000000..233dc90 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OneToMany.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class OneToMany implements Annotation +{ + /** @var string */ + public $mappedBy; + /** @var string */ + public $targetEntity; + /** @var array */ + public $cascade; + /** @var string */ + public $fetch = 'LAZY'; + /** @var boolean */ + public $orphanRemoval = false; + /** @var string */ + public $indexBy; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OneToOne.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OneToOne.php new file mode 100644 index 0000000..68689ef --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OneToOne.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class OneToOne implements Annotation +{ + /** @var string */ + public $targetEntity; + /** @var string */ + public $mappedBy; + /** @var string */ + public $inversedBy; + /** @var array */ + public $cascade; + /** @var string */ + public $fetch = 'LAZY'; + /** @var boolean */ + public $orphanRemoval = false; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OrderBy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OrderBy.php new file mode 100644 index 0000000..4041973 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/OrderBy.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class OrderBy implements Annotation +{ + /** @var array */ + public $value; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostLoad.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostLoad.php new file mode 100644 index 0000000..2f8e993 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostLoad.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PostLoad implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostPersist.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostPersist.php new file mode 100644 index 0000000..2aea719 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostPersist.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PostPersist implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostRemove.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostRemove.php new file mode 100644 index 0000000..321c4bd --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostRemove.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PostRemove implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostUpdate.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostUpdate.php new file mode 100644 index 0000000..a55f707 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PostUpdate.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PostUpdate implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreFlush.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreFlush.php new file mode 100644 index 0000000..6697d37 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreFlush.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PreFlush implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PrePersist.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PrePersist.php new file mode 100644 index 0000000..fea05be --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PrePersist.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PrePersist implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreRemove.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreRemove.php new file mode 100644 index 0000000..29822ed --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreRemove.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PreRemove implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreUpdate.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreUpdate.php new file mode 100644 index 0000000..290df72 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/PreUpdate.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PreUpdate implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/QuoteStrategy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/QuoteStrategy.php new file mode 100644 index 0000000..52e846d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/QuoteStrategy.php @@ -0,0 +1,112 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * A set of rules for determining the column, alias and table quotes + * + * @since 2.3 + * @author Fabio B. Silva + */ +interface QuoteStrategy +{ + /** + * Gets the (possibly quoted) column name for safe use in an SQL statement. + * + * @param string $fieldName + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) primary table name for safe use in an SQL statement. + * + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getTableName(ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) sequence name for safe use in an SQL statement. + * + * @param array $definition + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) name of the join table. + * + * @param array $association + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) join column name. + * + * @param array $joinColumn + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) join column name. + * + * @param array $joinColumn + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return string + */ + function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the (possibly quoted) identifier column names for safe use in an SQL statement. + * + * @param ClassMetadata $class + * @param AbstractPlatform $platform + * @return array + */ + function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform); + + /** + * Gets the column alias. + * + * @param string $columnName + * @param integer $counter + * @param AbstractPlatform $platform + * @param ClassMetadata $class + * @return string + */ + function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null); + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SequenceGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SequenceGenerator.php new file mode 100644 index 0000000..1acb498 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SequenceGenerator.php @@ -0,0 +1,34 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class SequenceGenerator implements Annotation +{ + /** @var string */ + public $sequenceName; + /** @var integer */ + public $allocationSize = 1; + /** @var integer */ + public $initialValue = 1; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SqlResultSetMapping.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SqlResultSetMapping.php new file mode 100644 index 0000000..881e873 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SqlResultSetMapping.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * The SqlResultSetMapping annotation is used to specify the mapping of the result of a native SQL query. + * The SqlResultSetMapping annotation can be applied to an entity or mapped superclass. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("ANNOTATION") + */ +final class SqlResultSetMapping implements Annotation +{ + + /** + * The name given to the result set mapping, and used to refer to it in the methods of the Query API. + * + * @var string + */ + public $name; + + /** + * Specifies the result set mapping to entities. + * + * @var array<\Doctrine\ORM\Mapping\EntityResult> + */ + public $entities = array(); + + /** + * Specifies the result set mapping to scalar values. + * + * @var array<\Doctrine\ORM\Mapping\ColumnResult> + */ + public $columns = array(); + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SqlResultSetMappings.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SqlResultSetMappings.php new file mode 100644 index 0000000..c21b2ab --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/SqlResultSetMappings.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * Is used to specify an array of mappings. + * The SqlResultSetMappings annotation can be applied to an entity or mapped superclass. + * + * @author Fabio B. Silva + * @since 2.3 + * + * @Annotation + * @Target("CLASS") + */ +final class SqlResultSetMappings implements Annotation +{ + /** + * One or more SqlResultSetMapping annotations. + * + * @var array<\Doctrine\ORM\Mapping\SqlResultSetMapping> + */ + public $value = array(); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Table.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Table.php new file mode 100644 index 0000000..8f94f0c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Table.php @@ -0,0 +1,38 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class Table implements Annotation +{ + /** @var string */ + public $name; + /** @var string */ + public $schema; + /** @var array<\Doctrine\ORM\Mapping\Index> */ + public $indexes; + /** @var array<\Doctrine\ORM\Mapping\UniqueConstraint> */ + public $uniqueConstraints; + /** @var array */ + public $options = array(); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/UnderscoreNamingStrategy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/UnderscoreNamingStrategy.php new file mode 100644 index 0000000..236ab5c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/UnderscoreNamingStrategy.php @@ -0,0 +1,135 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * Naming strategy implementing the underscore naming convention. + * Converts 'MyEntity' to 'my_entity' or 'MY_ENTITY'. + * + * + * @link www.doctrine-project.org + * @since 2.3 + * @author Fabio B. Silva + */ +class UnderscoreNamingStrategy implements NamingStrategy +{ + /** + * @var integer + */ + private $case; + + /** + * Underscore naming strategy construct + * + * @param integer $case CASE_LOWER | CASE_UPPER + */ + public function __construct($case = CASE_LOWER) + { + $this->case = $case; + } + + /** + * @return integer + */ + public function getCase() + { + return $this->case; + } + + /** + * Sets string case CASE_LOWER | CASE_UPPER + * Alphabetic characters converted to lowercase or uppercase + * + * @param integer $case + */ + public function setCase($case) + { + $this->case = $case; + } + + /** + * {@inheritdoc} + */ + public function classToTableName($className) + { + if (strpos($className, '\\') !== false) { + $className = substr($className, strrpos($className, '\\') + 1); + } + + return $this->underscore($className); + } + + /** + * {@inheritdoc} + */ + public function propertyToColumnName($propertyName) + { + return $this->underscore($propertyName); + } + + /** + * {@inheritdoc} + */ + public function referenceColumnName() + { + return $this->case === CASE_UPPER ? 'ID' : 'id'; + } + + /** + * {@inheritdoc} + */ + public function joinColumnName($propertyName) + { + return $this->underscore($propertyName) . '_' . $this->referenceColumnName(); + } + + /** + * {@inheritdoc} + */ + public function joinTableName($sourceEntity, $targetEntity, $propertyName = null) + { + return $this->classToTableName($sourceEntity) . '_' . $this->classToTableName($targetEntity); + } + + /** + * {@inheritdoc} + */ + public function joinKeyColumnName($entityName, $referencedColumnName = null) + { + return $this->classToTableName($entityName) . '_' . + ($referencedColumnName ?: $this->referenceColumnName()); + } + + /** + * @param string $string + * @return string + */ + private function underscore($string) + { + $string = preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $string); + + if ($this->case === CASE_UPPER) { + return strtoupper($string); + } + + return strtolower($string); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/UniqueConstraint.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/UniqueConstraint.php new file mode 100644 index 0000000..7df2a2c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/UniqueConstraint.php @@ -0,0 +1,32 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("ANNOTATION") + */ +final class UniqueConstraint implements Annotation +{ + /** @var string */ + public $name; + /** @var array */ + public $columns; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Version.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Version.php new file mode 100644 index 0000000..a237702 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Version.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class Version implements Annotation +{ +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/NativeQuery.php b/vendor/doctrine/orm/lib/Doctrine/ORM/NativeQuery.php new file mode 100644 index 0000000..1b9b022 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/NativeQuery.php @@ -0,0 +1,87 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Represents a native SQL query. + * + * @author Roman Borschel + * @since 2.0 + */ +final class NativeQuery extends AbstractQuery +{ + private $_sql; + + /** + * Sets the SQL of the query. + * + * @param string $sql + * @return NativeQuery This query instance. + */ + public function setSQL($sql) + { + $this->_sql = $sql; + + return $this; + } + + /** + * Gets the SQL query. + * + * @return mixed The built SQL query or an array of all SQL queries. + * @override + */ + public function getSQL() + { + return $this->_sql; + } + + /** + * {@inheritdoc} + */ + protected function _doExecute() + { + $parameters = array(); + $types = array(); + + foreach ($this->getParameters() as $parameter) { + $name = $parameter->getName(); + $value = $this->processParameterValue($parameter->getValue()); + $type = ($parameter->getValue() === $value) + ? $parameter->getType() + : Query\ParameterTypeInferer::inferType($value); + + $parameters[$name] = $value; + $types[$name] = $type; + } + + if ($parameters && is_int(key($parameters))) { + ksort($parameters); + ksort($types); + + $parameters = array_values($parameters); + $types = array_values($types); + } + + return $this->_em->getConnection()->executeQuery( + $this->_sql, $parameters, $types, $this->_queryCacheProfile + ); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/NoResultException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/NoResultException.php new file mode 100644 index 0000000..682cb3a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/NoResultException.php @@ -0,0 +1,34 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Exception thrown when an ORM query unexpectedly does not return any results. + * + * @author robo + * @since 2.0 + */ +class NoResultException extends UnexpectedResultException +{ + public function __construct() + { + parent::__construct('No result was found for query although at least one row was expected.'); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/NonUniqueResultException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/NonUniqueResultException.php new file mode 100644 index 0000000..4523af2 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/NonUniqueResultException.php @@ -0,0 +1,31 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Exception thrown when an ORM query unexpectedly returns more than one result. + * + * @author robo + * @since 2.0 + */ +class NonUniqueResultException extends UnexpectedResultException +{ + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/ORMException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/ORMException.php new file mode 100644 index 0000000..2776753 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/ORMException.php @@ -0,0 +1,167 @@ +. + */ + +namespace Doctrine\ORM; + +use Exception; + +/** + * Base exception class for all ORM exceptions. + * + * @author Roman Borschel + * @since 2.0 + */ +class ORMException extends Exception +{ + public static function missingMappingDriverImpl() + { + return new self("It's a requirement to specify a Metadata Driver and pass it ". + "to Doctrine\\ORM\\Configuration::setMetadataDriverImpl()."); + } + + public static function namedQueryNotFound($queryName) + { + return new self('Could not find a named query by the name "' . $queryName . '"'); + } + + public static function namedNativeQueryNotFound($nativeQueryName) + { + return new self('Could not find a named native query by the name "' . $nativeQueryName . '"'); + } + + public static function entityMissingForeignAssignedId($entity, $relatedEntity) + { + return new self( + "Entity of type " . get_class($entity) . " has identity through a foreign entity " . get_class($relatedEntity) . ", " . + "however this entity has no identity itself. You have to call EntityManager#persist() on the related entity " . + "and make sure that an identifier was generated before trying to persist '" . get_class($entity) . "'. In case " . + "of Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call " . + "EntityManager#flush() between both persist operations." + ); + } + + public static function entityMissingAssignedIdForField($entity, $field) + { + return new self("Entity of type " . get_class($entity) . " is missing an assigned ID for field '" . $field . "'. " . + "The identifier generation strategy for this entity requires the ID field to be populated before ". + "EntityManager#persist() is called. If you want automatically generated identifiers instead " . + "you need to adjust the metadata mapping accordingly." + ); + } + + public static function unrecognizedField($field) + { + return new self("Unrecognized field: $field"); + } + + /** + * @param string $className + * @param string $field + */ + public static function invalidOrientation($className, $field) + { + return new self("Invalid order by orientation specified for " . $className . "#" . $field); + } + + public static function invalidFlushMode($mode) + { + return new self("'$mode' is an invalid flush mode."); + } + + public static function entityManagerClosed() + { + return new self("The EntityManager is closed."); + } + + public static function invalidHydrationMode($mode) + { + return new self("'$mode' is an invalid hydration mode."); + } + + public static function mismatchedEventManager() + { + return new self("Cannot use different EventManager instances for EntityManager and Connection."); + } + + public static function findByRequiresParameter($methodName) + { + return new self("You need to pass a parameter to '".$methodName."'"); + } + + public static function invalidFindByCall($entityName, $fieldName, $method) + { + return new self( + "Entity '".$entityName."' has no field '".$fieldName."'. ". + "You can therefore not call '".$method."' on the entities' repository" + ); + } + + public static function invalidFindByInverseAssociation($entityName, $associationFieldName) + { + return new self( + "You cannot search for the association field '".$entityName."#".$associationFieldName."', ". + "because it is the inverse side of an association. Find methods only work on owning side associations." + ); + } + + public static function invalidResultCacheDriver() { + return new self("Invalid result cache driver; it must implement Doctrine\\Common\\Cache\\Cache."); + } + + public static function notSupported() { + return new self("This behaviour is (currently) not supported by Doctrine 2"); + } + + public static function queryCacheNotConfigured() + { + return new self('Query Cache is not configured.'); + } + + public static function metadataCacheNotConfigured() + { + return new self('Class Metadata Cache is not configured.'); + } + + public static function proxyClassesAlwaysRegenerating() + { + return new self('Proxy Classes are always regenerating.'); + } + + public static function unknownEntityNamespace($entityNamespaceAlias) + { + return new self( + "Unknown Entity namespace alias '$entityNamespaceAlias'." + ); + } + + public static function invalidEntityRepository($className) + { + return new self("Invalid repository class '".$className."'. It must be a Doctrine\Common\Persistence\ObjectRepository."); + } + + public static function missingIdentifierField($className, $fieldName) + { + return new self("The identifier $fieldName is missing for a query of " . $className); + } + + public static function overwriteInternalDQLFunctionNotAllowed($functionName) + { + return new self("It is not allowed to overwrite internal function '$functionName' in the DQL parser through user-defined functions."); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/ORMInvalidArgumentException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/ORMInvalidArgumentException.php new file mode 100644 index 0000000..d889173 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/ORMInvalidArgumentException.php @@ -0,0 +1,115 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Contains exception messages for all invalid lifecycle state exceptions inside UnitOfWork + * + * @author Benjamin Eberlei + */ +class ORMInvalidArgumentException extends \InvalidArgumentException +{ + static public function scheduleInsertForManagedEntity($entity) + { + return new self("A managed+dirty entity " . self::objToStr($entity) . " can not be scheduled for insertion."); + } + + static public function scheduleInsertForRemovedEntity($entity) + { + return new self("Removed entity " . self::objToStr($entity) . " can not be scheduled for insertion."); + } + + static public function scheduleInsertTwice($entity) + { + return new self("Entity " . self::objToStr($entity) . " can not be scheduled for insertion twice."); + } + + static public function entityWithoutIdentity($className, $entity) + { + return new self( + "The given entity of type '" . $className . "' (".self::objToStr($entity).") has no identity/no " . + "id values set. It cannot be added to the identity map." + ); + } + + static public function readOnlyRequiresManagedEntity($entity) + { + return new self("Only managed entities can be marked or checked as read only. But " . self::objToStr($entity) . " is not"); + } + + static public function newEntityFoundThroughRelationship(array $assoc, $entry) + { + return new self("A new entity was found through the relationship '" + . $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' that was not" + . " configured to cascade persist operations for entity: " . self::objToStr($entry) . "." + . " To solve this issue: Either explicitly call EntityManager#persist()" + . " on this unknown entity or configure cascade persist " + . " this association in the mapping for example @ManyToOne(..,cascade={\"persist\"})." + . (method_exists($entry, '__toString') ? + "": + " If you cannot find out which entity causes the problem" + ." implement '" . $assoc['targetEntity'] . "#__toString()' to get a clue.")); + } + + static public function detachedEntityFoundThroughRelationship(array $assoc, $entry) + { + return new self("A detached entity of type " . $assoc['targetEntity'] . " (" . self::objToStr($entry) . ") " + . " was found through the relationship '" . $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' " + . "during cascading a persist operation."); + } + + static public function entityNotManaged($entity) + { + return new self("Entity " . self::objToStr($entity) . " is not managed. An entity is managed if its fetched " . + "from the database or registered as new through EntityManager#persist"); + } + + static public function entityHasNoIdentity($entity, $operation) + { + return new self("Entity has no identity, therefore " . $operation ." cannot be performed. " . self::objToStr($entity)); + } + + static public function entityIsRemoved($entity, $operation) + { + return new self("Entity is removed, therefore " . $operation ." cannot be performed. " . self::objToStr($entity)); + } + + static public function detachedEntityCannot($entity, $operation) + { + return new self("A detached entity was found during " . $operation . " " . self::objToStr($entity)); + } + + public static function invalidObject($context, $given, $parameterIndex = 1) + { + return new self($context .' expects parameter ' . $parameterIndex . + ' to be an entity object, '. gettype($given) . ' given.'); + } + + /** + * Helper method to show an object as string. + * + * @param object $obj + * @return string + */ + private static function objToStr($obj) + { + return method_exists($obj, '__toString') ? (string)$obj : get_class($obj).'@'.spl_object_hash($obj); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/OptimisticLockException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/OptimisticLockException.php new file mode 100644 index 0000000..b425ac3 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/OptimisticLockException.php @@ -0,0 +1,64 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * An OptimisticLockException is thrown when a version check on an object + * that uses optimistic locking through a version field fails. + * + * @author Roman Borschel + * @author Benjamin Eberlei + * @since 2.0 + */ +class OptimisticLockException extends ORMException +{ + private $entity; + + public function __construct($msg, $entity) + { + parent::__construct($msg); + $this->entity = $entity; + } + + /** + * Gets the entity that caused the exception. + * + * @return object + */ + public function getEntity() + { + return $this->entity; + } + + public static function lockFailed($entity) + { + return new self("The optimistic lock on an entity failed.", $entity); + } + + public static function lockFailedVersionMissmatch($entity, $expectedLockVersion, $actualLockVersion) + { + return new self("The optimistic lock failed, version " . $expectedLockVersion . " was expected, but is actually ".$actualLockVersion, $entity); + } + + public static function notVersioned($entityName) + { + return new self("Cannot obtain optimistic lock on unversioned entity " . $entityName, null); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php b/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php new file mode 100644 index 0000000..ec97340 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php @@ -0,0 +1,838 @@ +. + */ + +namespace Doctrine\ORM; + +use Doctrine\ORM\Mapping\ClassMetadata; + +use Doctrine\Common\Collections\Collection; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Selectable; +use Doctrine\Common\Collections\Criteria; +use Doctrine\Common\Collections\ExpressionBuilder; + +use Closure; + +/** + * A PersistentCollection represents a collection of elements that have persistent state. + * + * Collections of entities represent only the associations (links) to those entities. + * That means, if the collection is part of a many-many mapping and you remove + * entities from the collection, only the links in the relation table are removed (on flush). + * Similarly, if you remove entities from a collection that is part of a one-many + * mapping this will only result in the nulling out of the foreign keys on flush. + * + * @since 2.0 + * @author Konsta Vesterinen + * @author Roman Borschel + * @author Giorgio Sironi + * @author Stefano Rodriguez + * @todo Design for inheritance to allow custom implementations? + */ +final class PersistentCollection implements Collection, Selectable +{ + /** + * A snapshot of the collection at the moment it was fetched from the database. + * This is used to create a diff of the collection at commit time. + * + * @var array + */ + private $snapshot = array(); + + /** + * The entity that owns this collection. + * + * @var object + */ + private $owner; + + /** + * The association mapping the collection belongs to. + * This is currently either a OneToManyMapping or a ManyToManyMapping. + * + * @var array + */ + private $association; + + /** + * The EntityManager that manages the persistence of the collection. + * + * @var \Doctrine\ORM\EntityManager + */ + private $em; + + /** + * The name of the field on the target entities that points to the owner + * of the collection. This is only set if the association is bi-directional. + * + * @var string + */ + private $backRefFieldName; + + /** + * The class descriptor of the collection's entity type. + */ + private $typeClass; + + /** + * Whether the collection is dirty and needs to be synchronized with the database + * when the UnitOfWork that manages its persistent state commits. + * + * @var boolean + */ + private $isDirty = false; + + /** + * Whether the collection has already been initialized. + * + * @var boolean + */ + private $initialized = true; + + /** + * The wrapped Collection instance. + * + * @var Collection + */ + private $coll; + + /** + * Creates a new persistent collection. + * + * @param EntityManager $em The EntityManager the collection will be associated with. + * @param ClassMetadata $class The class descriptor of the entity type of this collection. + * @param array The collection elements. + */ + public function __construct(EntityManager $em, $class, $coll) + { + $this->coll = $coll; + $this->em = $em; + $this->typeClass = $class; + } + + /** + * INTERNAL: + * Sets the collection's owning entity together with the AssociationMapping that + * describes the association between the owner and the elements of the collection. + * + * @param object $entity + * @param AssociationMapping $assoc + */ + public function setOwner($entity, array $assoc) + { + $this->owner = $entity; + $this->association = $assoc; + $this->backRefFieldName = $assoc['inversedBy'] ?: $assoc['mappedBy']; + } + + /** + * INTERNAL: + * Gets the collection owner. + * + * @return object + */ + public function getOwner() + { + return $this->owner; + } + + public function getTypeClass() + { + return $this->typeClass; + } + + /** + * INTERNAL: + * Adds an element to a collection during hydration. This will automatically + * complete bidirectional associations in the case of a one-to-many association. + * + * @param mixed $element The element to add. + */ + public function hydrateAdd($element) + { + $this->coll->add($element); + + // If _backRefFieldName is set and its a one-to-many association, + // we need to set the back reference. + if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) { + // Set back reference to owner + $this->typeClass->reflFields[$this->backRefFieldName]->setValue( + $element, $this->owner + ); + + $this->em->getUnitOfWork()->setOriginalEntityProperty( + spl_object_hash($element), $this->backRefFieldName, $this->owner + ); + } + } + + /** + * INTERNAL: + * Sets a keyed element in the collection during hydration. + * + * @param mixed $key The key to set. + * $param mixed $value The element to set. + */ + public function hydrateSet($key, $element) + { + $this->coll->set($key, $element); + + // If _backRefFieldName is set, then the association is bidirectional + // and we need to set the back reference. + if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) { + // Set back reference to owner + $this->typeClass->reflFields[$this->backRefFieldName]->setValue( + $element, $this->owner + ); + } + } + + /** + * Initializes the collection by loading its contents from the database + * if the collection is not yet initialized. + */ + public function initialize() + { + if ($this->initialized || ! $this->association) { + return; + } + + // Has NEW objects added through add(). Remember them. + $newObjects = array(); + + if ($this->isDirty) { + $newObjects = $this->coll->toArray(); + } + + $this->coll->clear(); + $this->em->getUnitOfWork()->loadCollection($this); + $this->takeSnapshot(); + + // Reattach NEW objects added through add(), if any. + if ($newObjects) { + foreach ($newObjects as $obj) { + $this->coll->add($obj); + } + + $this->isDirty = true; + } + + $this->initialized = true; + } + + /** + * INTERNAL: + * Tells this collection to take a snapshot of its current state. + */ + public function takeSnapshot() + { + $this->snapshot = $this->coll->toArray(); + $this->isDirty = false; + } + + /** + * INTERNAL: + * Returns the last snapshot of the elements in the collection. + * + * @return array The last snapshot of the elements. + */ + public function getSnapshot() + { + return $this->snapshot; + } + + /** + * INTERNAL: + * getDeleteDiff + * + * @return array + */ + public function getDeleteDiff() + { + return array_udiff_assoc( + $this->snapshot, + $this->coll->toArray(), + function($a, $b) { return $a === $b ? 0 : 1; } + ); + } + + /** + * INTERNAL: + * getInsertDiff + * + * @return array + */ + public function getInsertDiff() + { + return array_udiff_assoc( + $this->coll->toArray(), + $this->snapshot, + function($a, $b) { return $a === $b ? 0 : 1; } + ); + } + + /** + * INTERNAL: Gets the association mapping of the collection. + * + * @return array + */ + public function getMapping() + { + return $this->association; + } + + /** + * Marks this collection as changed/dirty. + */ + private function changed() + { + if ($this->isDirty) { + return; + } + + $this->isDirty = true; + + if ($this->association !== null && + $this->association['isOwningSide'] && + $this->association['type'] === ClassMetadata::MANY_TO_MANY && + $this->owner && + $this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) { + $this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner); + } + } + + /** + * Gets a boolean flag indicating whether this collection is dirty which means + * its state needs to be synchronized with the database. + * + * @return boolean TRUE if the collection is dirty, FALSE otherwise. + */ + public function isDirty() + { + return $this->isDirty; + } + + /** + * Sets a boolean flag, indicating whether this collection is dirty. + * + * @param boolean $dirty Whether the collection should be marked dirty or not. + */ + public function setDirty($dirty) + { + $this->isDirty = $dirty; + } + + /** + * Sets the initialized flag of the collection, forcing it into that state. + * + * @param boolean $bool + */ + public function setInitialized($bool) + { + $this->initialized = $bool; + } + + /** + * Checks whether this collection has been initialized. + * + * @return boolean + */ + public function isInitialized() + { + return $this->initialized; + } + + /** {@inheritdoc} */ + public function first() + { + $this->initialize(); + + return $this->coll->first(); + } + + /** {@inheritdoc} */ + public function last() + { + $this->initialize(); + + return $this->coll->last(); + } + + /** + * {@inheritdoc} + */ + public function remove($key) + { + // TODO: If the keys are persistent as well (not yet implemented) + // and the collection is not initialized and orphanRemoval is + // not used we can issue a straight SQL delete/update on the + // association (table). Without initializing the collection. + $this->initialize(); + + $removed = $this->coll->remove($key); + + if ( ! $removed) { + return $removed; + } + + $this->changed(); + + if ($this->association !== null && + $this->association['type'] & ClassMetadata::TO_MANY && + $this->owner && + $this->association['orphanRemoval']) { + $this->em->getUnitOfWork()->scheduleOrphanRemoval($removed); + } + + return $removed; + } + + /** + * {@inheritdoc} + */ + public function removeElement($element) + { + if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { + if ($this->coll->contains($element)) { + return $this->coll->removeElement($element); + } + + $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + + if ($persister->removeElement($this, $element)) { + return $element; + } + + return null; + } + + $this->initialize(); + + $removed = $this->coll->removeElement($element); + + if ( ! $removed) { + return $removed; + } + + $this->changed(); + + if ($this->association !== null && + $this->association['type'] & ClassMetadata::TO_MANY && + $this->owner && + $this->association['orphanRemoval']) { + $this->em->getUnitOfWork()->scheduleOrphanRemoval($element); + } + + return $removed; + } + + /** + * {@inheritdoc} + */ + public function containsKey($key) + { + $this->initialize(); + + return $this->coll->containsKey($key); + } + + /** + * {@inheritdoc} + */ + public function contains($element) + { + if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { + $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + + return $this->coll->contains($element) || $persister->contains($this, $element); + } + + $this->initialize(); + + return $this->coll->contains($element); + } + + /** + * {@inheritdoc} + */ + public function exists(Closure $p) + { + $this->initialize(); + + return $this->coll->exists($p); + } + + /** + * {@inheritdoc} + */ + public function indexOf($element) + { + $this->initialize(); + + return $this->coll->indexOf($element); + } + + /** + * {@inheritdoc} + */ + public function get($key) + { + $this->initialize(); + + return $this->coll->get($key); + } + + /** + * {@inheritdoc} + */ + public function getKeys() + { + $this->initialize(); + + return $this->coll->getKeys(); + } + + /** + * {@inheritdoc} + */ + public function getValues() + { + $this->initialize(); + + return $this->coll->getValues(); + } + + /** + * {@inheritdoc} + */ + public function count() + { + if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { + $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + + return $persister->count($this) + ($this->isDirty ? $this->coll->count() : 0); + } + + $this->initialize(); + + return $this->coll->count(); + } + + /** + * {@inheritdoc} + */ + public function set($key, $value) + { + $this->initialize(); + + $this->coll->set($key, $value); + + $this->changed(); + } + + /** + * {@inheritdoc} + */ + public function add($value) + { + $this->coll->add($value); + + $this->changed(); + + return true; + } + + /** + * {@inheritdoc} + */ + public function isEmpty() + { + $this->initialize(); + + return $this->coll->isEmpty(); + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + $this->initialize(); + + return $this->coll->getIterator(); + } + + /** + * {@inheritdoc} + */ + public function map(Closure $func) + { + $this->initialize(); + + return $this->coll->map($func); + } + + /** + * {@inheritdoc} + */ + public function filter(Closure $p) + { + $this->initialize(); + + return $this->coll->filter($p); + } + + /** + * {@inheritdoc} + */ + public function forAll(Closure $p) + { + $this->initialize(); + + return $this->coll->forAll($p); + } + + /** + * {@inheritdoc} + */ + public function partition(Closure $p) + { + $this->initialize(); + + return $this->coll->partition($p); + } + + /** + * {@inheritdoc} + */ + public function toArray() + { + $this->initialize(); + + return $this->coll->toArray(); + } + + /** + * {@inheritdoc} + */ + public function clear() + { + if ($this->initialized && $this->isEmpty()) { + return; + } + + $uow = $this->em->getUnitOfWork(); + + if ($this->association['type'] & ClassMetadata::TO_MANY && + $this->association['orphanRemoval'] && + $this->owner) { + // we need to initialize here, as orphan removal acts like implicit cascadeRemove, + // hence for event listeners we need the objects in memory. + $this->initialize(); + + foreach ($this->coll as $element) { + $uow->scheduleOrphanRemoval($element); + } + } + + $this->coll->clear(); + + $this->initialized = true; // direct call, {@link initialize()} is too expensive + + if ($this->association['isOwningSide']) { + $this->changed(); + + $uow->scheduleCollectionDeletion($this); + + $this->takeSnapshot(); + } + } + + /** + * Called by PHP when this collection is serialized. Ensures that only the + * elements are properly serialized. + * + * @internal Tried to implement Serializable first but that did not work well + * with circular references. This solution seems simpler and works well. + */ + public function __sleep() + { + return array('coll', 'initialized'); + } + + /* ArrayAccess implementation */ + + /** + * @see containsKey() + */ + public function offsetExists($offset) + { + return $this->containsKey($offset); + } + + /** + * @see get() + */ + public function offsetGet($offset) + { + return $this->get($offset); + } + + /** + * @see add() + * @see set() + */ + public function offsetSet($offset, $value) + { + if ( ! isset($offset)) { + return $this->add($value); + } + + return $this->set($offset, $value); + } + + /** + * @see remove() + */ + public function offsetUnset($offset) + { + return $this->remove($offset); + } + + public function key() + { + return $this->coll->key(); + } + + /** + * Gets the element of the collection at the current iterator position. + */ + public function current() + { + return $this->coll->current(); + } + + /** + * Moves the internal iterator position to the next element. + */ + public function next() + { + return $this->coll->next(); + } + + /** + * Retrieves the wrapped Collection instance. + * + * @return \Doctrine\Common\Collections\Collection + */ + public function unwrap() + { + return $this->coll; + } + + /** + * Extract a slice of $length elements starting at position $offset from the Collection. + * + * If $length is null it returns all elements from $offset to the end of the Collection. + * Keys have to be preserved by this method. Calling this method will only return the + * selected slice and NOT change the elements contained in the collection slice is called on. + * + * @param int $offset + * @param int $length + * + * @return array + */ + public function slice($offset, $length = null) + { + if ( ! $this->initialized && ! $this->isDirty && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { + $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + + return $persister->slice($this, $offset, $length); + } + + $this->initialize(); + + return $this->coll->slice($offset, $length); + } + + /** + * Cleanup internal state of cloned persistent collection. + * + * The following problems have to be prevented: + * 1. Added entities are added to old PC + * 2. New collection is not dirty, if reused on other entity nothing + * changes. + * 3. Snapshot leads to invalid diffs being generated. + * 4. Lazy loading grabs entities from old owner object. + * 5. New collection is connected to old owner and leads to duplicate keys. + */ + public function __clone() + { + if (is_object($this->coll)) { + $this->coll = clone $this->coll; + } + + $this->initialize(); + + $this->owner = null; + $this->snapshot = array(); + + $this->changed(); + } + + /** + * Select all elements from a selectable that match the expression and + * return a new collection containing these elements. + * + * @param \Doctrine\Common\Collections\Criteria $criteria + * @return Collection + */ + public function matching(Criteria $criteria) + { + if ($this->initialized) { + return $this->coll->matching($criteria); + } + + if ($this->association['type'] !== ClassMetadata::ONE_TO_MANY) { + throw new \RuntimeException("Matching Criteria on PersistentCollection only works on OneToMany assocations at the moment."); + } + + // If there are NEW objects we have to check if any of them matches the criteria + $newObjects = array(); + + if ($this->isDirty) { + $newObjects = $this->coll->matching($criteria)->toArray(); + } + + $targetClass = $this->em->getClassMetadata(get_class($this->owner)); + + $id = $targetClass->getSingleIdReflectionProperty()->getValue($this->owner); + $builder = Criteria::expr(); + $ownerExpression = $builder->eq($this->backRefFieldName, $id); + $expression = $criteria->getWhereExpression(); + $expression = $expression ? $builder->andX($expression, $ownerExpression) : $ownerExpression; + + $criteria->where($expression); + + $persister = $this->em->getUnitOfWork()->getEntityPersister($this->association['targetEntity']); + + return new ArrayCollection(array_merge($persister->loadCriteria($criteria), $newObjects)); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/AbstractCollectionPersister.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/AbstractCollectionPersister.php new file mode 100644 index 0000000..2728918 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/AbstractCollectionPersister.php @@ -0,0 +1,223 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use Doctrine\ORM\EntityManager, + Doctrine\ORM\PersistentCollection; + +/** + * Base class for all collection persisters. + * + * @since 2.0 + * @author Roman Borschel + */ +abstract class AbstractCollectionPersister +{ + /** + * @var EntityManager + */ + protected $_em; + + /** + * @var \Doctrine\DBAL\Connection + */ + protected $_conn; + + /** + * @var \Doctrine\ORM\UnitOfWork + */ + protected $_uow; + + /** + * The database platform. + * + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + protected $platform; + + /** + * The quote strategy. + * + * @var \Doctrine\ORM\Mapping\QuoteStrategy + */ + protected $quoteStrategy; + + /** + * Initializes a new instance of a class derived from AbstractCollectionPersister. + * + * @param \Doctrine\ORM\EntityManager $em + */ + public function __construct(EntityManager $em) + { + $this->_em = $em; + $this->_uow = $em->getUnitOfWork(); + $this->_conn = $em->getConnection(); + $this->platform = $this->_conn->getDatabasePlatform(); + $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); + } + + /** + * Deletes the persistent state represented by the given collection. + * + * @param PersistentCollection $coll + */ + public function delete(PersistentCollection $coll) + { + $mapping = $coll->getMapping(); + + if ( ! $mapping['isOwningSide']) { + return; // ignore inverse side + } + + $sql = $this->_getDeleteSQL($coll); + $this->_conn->executeUpdate($sql, $this->_getDeleteSQLParameters($coll)); + } + + /** + * Gets the SQL statement for deleting the given collection. + * + * @param PersistentCollection $coll + */ + abstract protected function _getDeleteSQL(PersistentCollection $coll); + + /** + * Gets the SQL parameters for the corresponding SQL statement to delete + * the given collection. + * + * @param PersistentCollection $coll + */ + abstract protected function _getDeleteSQLParameters(PersistentCollection $coll); + + /** + * Updates the given collection, synchronizing it's state with the database + * by inserting, updating and deleting individual elements. + * + * @param PersistentCollection $coll + */ + public function update(PersistentCollection $coll) + { + $mapping = $coll->getMapping(); + + if ( ! $mapping['isOwningSide']) { + return; // ignore inverse side + } + + $this->deleteRows($coll); + //$this->updateRows($coll); + $this->insertRows($coll); + } + + public function deleteRows(PersistentCollection $coll) + { + $deleteDiff = $coll->getDeleteDiff(); + $sql = $this->_getDeleteRowSQL($coll); + + foreach ($deleteDiff as $element) { + $this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element)); + } + } + + //public function updateRows(PersistentCollection $coll) + //{} + + public function insertRows(PersistentCollection $coll) + { + $insertDiff = $coll->getInsertDiff(); + $sql = $this->_getInsertRowSQL($coll); + + foreach ($insertDiff as $element) { + $this->_conn->executeUpdate($sql, $this->_getInsertRowSQLParameters($coll, $element)); + } + } + + public function count(PersistentCollection $coll) + { + throw new \BadMethodCallException("Counting the size of this persistent collection is not supported by this CollectionPersister."); + } + + public function slice(PersistentCollection $coll, $offset, $length = null) + { + throw new \BadMethodCallException("Slicing elements is not supported by this CollectionPersister."); + } + + public function contains(PersistentCollection $coll, $element) + { + throw new \BadMethodCallException("Checking for existance of an element is not supported by this CollectionPersister."); + } + + public function containsKey(PersistentCollection $coll, $key) + { + throw new \BadMethodCallException("Checking for existance of a key is not supported by this CollectionPersister."); + } + + public function removeElement(PersistentCollection $coll, $element) + { + throw new \BadMethodCallException("Removing an element is not supported by this CollectionPersister."); + } + + public function removeKey(PersistentCollection $coll, $key) + { + throw new \BadMethodCallException("Removing a key is not supported by this CollectionPersister."); + } + + public function get(PersistentCollection $coll, $index) + { + throw new \BadMethodCallException("Selecting a collection by index is not supported by this CollectionPersister."); + } + + /** + * Gets the SQL statement used for deleting a row from the collection. + * + * @param PersistentCollection $coll + */ + abstract protected function _getDeleteRowSQL(PersistentCollection $coll); + + /** + * Gets the SQL parameters for the corresponding SQL statement to delete the given + * element from the given collection. + * + * @param PersistentCollection $coll + * @param mixed $element + */ + abstract protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element); + + /** + * Gets the SQL statement used for updating a row in the collection. + * + * @param PersistentCollection $coll + */ + abstract protected function _getUpdateRowSQL(PersistentCollection $coll); + + /** + * Gets the SQL statement used for inserting a row in the collection. + * + * @param PersistentCollection $coll + */ + abstract protected function _getInsertRowSQL(PersistentCollection $coll); + + /** + * Gets the SQL parameters for the corresponding SQL statement to insert the given + * element of the given collection into the database. + * + * @param PersistentCollection $coll + * @param mixed $element + */ + abstract protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php new file mode 100644 index 0000000..19e77a4 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php @@ -0,0 +1,83 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\DBAL\Types\Type; + +/** + * Base class for entity persisters that implement a certain inheritance mapping strategy. + * All these persisters are assumed to use a discriminator column to discriminate entity + * types in the hierarchy. + * + * @author Roman Borschel + * @author Benjamin Eberlei + * @since 2.0 + */ +abstract class AbstractEntityInheritancePersister extends BasicEntityPersister +{ + /** + * {@inheritdoc} + */ + protected function _prepareInsertData($entity) + { + $data = parent::_prepareInsertData($entity); + + // Populate the discriminator column + $discColumn = $this->_class->discriminatorColumn; + $this->_columnTypes[$discColumn['name']] = $discColumn['type']; + $data[$this->_getDiscriminatorColumnTableName()][$discColumn['name']] = $this->_class->discriminatorValue; + + return $data; + } + + /** + * Gets the name of the table that contains the discriminator column. + * + * @return string The table name. + */ + abstract protected function _getDiscriminatorColumnTableName(); + + /** + * {@inheritdoc} + */ + protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r') + { + $columnName = $class->columnNames[$field]; + $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $this->quoteStrategy->getColumnName($field, $class, $this->_platform); + $columnAlias = $this->getSQLColumnAlias($columnName); + $this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name); + + if (isset($class->fieldMappings[$field]['requireSQLConversion'])) { + $type = Type::getType($class->getTypeOfField($field)); + $sql = $type->convertToPHPValueSQL($sql, $this->_platform); + } + + return $sql . ' AS ' . $columnAlias; + } + + protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className) + { + $columnAlias = $this->getSQLColumnAlias($joinColumnName); + $this->_rsm->addMetaResult('r', $columnAlias, $joinColumnName); + + return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php new file mode 100644 index 0000000..d73983c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -0,0 +1,1791 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use PDO; + +use Doctrine\DBAL\LockMode; +use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Connection; + +use Doctrine\ORM\ORMException; +use Doctrine\ORM\OptimisticLockException; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\UnitOfWork; +use Doctrine\ORM\Query; +use Doctrine\ORM\PersistentCollection; +use Doctrine\ORM\Mapping\MappingException; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Events; +use Doctrine\ORM\Event\LifecycleEventArgs; + +use Doctrine\Common\Util\ClassUtils; +use Doctrine\Common\Collections\Criteria; +use Doctrine\Common\Collections\Expr\Comparison; + +/** + * A BasicEntityPersiter maps an entity to a single table in a relational database. + * + * A persister is always responsible for a single entity type. + * + * EntityPersisters are used during a UnitOfWork to apply any changes to the persistent + * state of entities onto a relational database when the UnitOfWork is committed, + * as well as for basic querying of entities and their associations (not DQL). + * + * The persisting operations that are invoked during a commit of a UnitOfWork to + * persist the persistent entity state are: + * + * - {@link addInsert} : To schedule an entity for insertion. + * - {@link executeInserts} : To execute all scheduled insertions. + * - {@link update} : To update the persistent state of an entity. + * - {@link delete} : To delete the persistent state of an entity. + * + * As can be seen from the above list, insertions are batched and executed all at once + * for increased efficiency. + * + * The querying operations invoked during a UnitOfWork, either through direct find + * requests or lazy-loading, are the following: + * + * - {@link load} : Loads (the state of) a single, managed entity. + * - {@link loadAll} : Loads multiple, managed entities. + * - {@link loadOneToOneEntity} : Loads a one/many-to-one entity association (lazy-loading). + * - {@link loadOneToManyCollection} : Loads a one-to-many entity association (lazy-loading). + * - {@link loadManyToManyCollection} : Loads a many-to-many entity association (lazy-loading). + * + * The BasicEntityPersister implementation provides the default behavior for + * persisting and querying entities that are mapped to a single database table. + * + * Subclasses can be created to provide custom persisting and querying strategies, + * i.e. spanning multiple tables. + * + * @author Roman Borschel + * @author Giorgio Sironi + * @author Benjamin Eberlei + * @author Alexander + * @since 2.0 + */ +class BasicEntityPersister +{ + /** + * @var array + */ + static private $comparisonMap = array( + Comparison::EQ => '= %s', + Comparison::IS => '= %s', + Comparison::NEQ => '!= %s', + Comparison::GT => '> %s', + Comparison::GTE => '>= %s', + Comparison::LT => '< %s', + Comparison::LTE => '<= %s', + Comparison::IN => 'IN (%s)', + Comparison::NIN => 'NOT IN (%s)', + ); + + /** + * Metadata object that describes the mapping of the mapped entity class. + * + * @var \Doctrine\ORM\Mapping\ClassMetadata + */ + protected $_class; + + /** + * The underlying DBAL Connection of the used EntityManager. + * + * @var \Doctrine\DBAL\Connection $conn + */ + protected $_conn; + + /** + * The database platform. + * + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + protected $_platform; + + /** + * The EntityManager instance. + * + * @var \Doctrine\ORM\EntityManager + */ + protected $_em; + + /** + * Queued inserts. + * + * @var array + */ + protected $_queuedInserts = array(); + + /** + * ResultSetMapping that is used for all queries. Is generated lazily once per request. + * + * TODO: Evaluate Caching in combination with the other cached SQL snippets. + * + * @var Query\ResultSetMapping + */ + protected $_rsm; + + /** + * The map of column names to DBAL mapping types of all prepared columns used + * when INSERTing or UPDATEing an entity. + * + * @var array + * @see _prepareInsertData($entity) + * @see _prepareUpdateData($entity) + */ + protected $_columnTypes = array(); + + /** + * The map of quoted column names. + * + * @var array + * @see _prepareInsertData($entity) + * @see _prepareUpdateData($entity) + */ + protected $quotedColumns = array(); + + /** + * The INSERT SQL statement used for entities handled by this persister. + * This SQL is only generated once per request, if at all. + * + * @var string + */ + private $_insertSql; + + /** + * The SELECT column list SQL fragment used for querying entities by this persister. + * This SQL fragment is only generated once per request, if at all. + * + * @var string + */ + protected $_selectColumnListSql; + + /** + * The JOIN SQL fragement used to eagerly load all many-to-one and one-to-one + * associations configured as FETCH_EAGER, aswell as all inverse one-to-one associations. + * + * @var string + */ + protected $_selectJoinSql; + + /** + * Counter for creating unique SQL table and column aliases. + * + * @var integer + */ + protected $_sqlAliasCounter = 0; + + /** + * Map from class names (FQCN) to the corresponding generated SQL table aliases. + * + * @var array + */ + protected $_sqlTableAliases = array(); + + /** + * The quote strategy. + * + * @var \Doctrine\ORM\Mapping\QuoteStrategy + */ + protected $quoteStrategy; + + /** + * Initializes a new BasicEntityPersister that uses the given EntityManager + * and persists instances of the class described by the given ClassMetadata descriptor. + * + * @param \Doctrine\ORM\EntityManager $em + * @param \Doctrine\ORM\Mapping\ClassMetadata $class + */ + public function __construct(EntityManager $em, ClassMetadata $class) + { + $this->_em = $em; + $this->_class = $class; + $this->_conn = $em->getConnection(); + $this->_platform = $this->_conn->getDatabasePlatform(); + $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); + } + + /** + * @return \Doctrine\ORM\Mapping\ClassMetadata + */ + public function getClassMetadata() + { + return $this->_class; + } + + /** + * Adds an entity to the queued insertions. + * The entity remains queued until {@link executeInserts} is invoked. + * + * @param object $entity The entity to queue for insertion. + */ + public function addInsert($entity) + { + $this->_queuedInserts[spl_object_hash($entity)] = $entity; + } + + /** + * Executes all queued entity insertions and returns any generated post-insert + * identifiers that were created as a result of the insertions. + * + * If no inserts are queued, invoking this method is a NOOP. + * + * @return array An array of any generated post-insert IDs. This will be an empty array + * if the entity class does not use the IDENTITY generation strategy. + */ + public function executeInserts() + { + if ( ! $this->_queuedInserts) { + return; + } + + $postInsertIds = array(); + $idGen = $this->_class->idGenerator; + $isPostInsertId = $idGen->isPostInsertGenerator(); + + $stmt = $this->_conn->prepare($this->_getInsertSQL()); + $tableName = $this->_class->getTableName(); + + foreach ($this->_queuedInserts as $entity) { + $insertData = $this->_prepareInsertData($entity); + + if (isset($insertData[$tableName])) { + $paramIndex = 1; + + foreach ($insertData[$tableName] as $column => $value) { + $stmt->bindValue($paramIndex++, $value, $this->_columnTypes[$column]); + } + } + + $stmt->execute(); + + if ($isPostInsertId) { + $id = $idGen->generate($this->_em, $entity); + $postInsertIds[$id] = $entity; + } else { + $id = $this->_class->getIdentifierValues($entity); + } + + if ($this->_class->isVersioned) { + $this->assignDefaultVersionValue($entity, $id); + } + } + + $stmt->closeCursor(); + $this->_queuedInserts = array(); + + return $postInsertIds; + } + + /** + * Retrieves the default version value which was created + * by the preceding INSERT statement and assigns it back in to the + * entities version field. + * + * @param object $entity + * @param mixed $id + */ + protected function assignDefaultVersionValue($entity, $id) + { + $value = $this->fetchVersionValue($this->_class, $id); + $this->_class->setFieldValue($entity, $this->_class->versionField, $value); + } + + /** + * Fetch the current version value of a versioned entity. + * + * @param \Doctrine\ORM\Mapping\ClassMetadata $versionedClass + * @param mixed $id + * @return mixed + */ + protected function fetchVersionValue($versionedClass, $id) + { + $versionField = $versionedClass->versionField; + $identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->_platform); + + $versionFieldColumnName = $this->quoteStrategy->getColumnName($versionField, $versionedClass, $this->_platform); + + //FIXME: Order with composite keys might not be correct + $sql = 'SELECT ' . $versionFieldColumnName + . ' FROM ' . $this->quoteStrategy->getTableName($versionedClass, $this->_platform) + . ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?'; + $value = $this->_conn->fetchColumn($sql, array_values((array)$id)); + + return Type::getType($versionedClass->fieldMappings[$versionField]['type'])->convertToPHPValue($value, $this->_platform); + } + + /** + * Updates a managed entity. The entity is updated according to its current changeset + * in the running UnitOfWork. If there is no changeset, nothing is updated. + * + * The data to update is retrieved through {@link _prepareUpdateData}. + * Subclasses that override this method are supposed to obtain the update data + * in the same way, through {@link _prepareUpdateData}. + * + * Subclasses are also supposed to take care of versioning when overriding this method, + * if necessary. The {@link _updateTable} method can be used to apply the data retrieved + * from {@_prepareUpdateData} on the target tables, thereby optionally applying versioning. + * + * @param object $entity The entity to update. + */ + public function update($entity) + { + $updateData = $this->_prepareUpdateData($entity); + $tableName = $this->_class->getTableName(); + + if (isset($updateData[$tableName]) && $updateData[$tableName]) { + $this->_updateTable( + $entity, $this->quoteStrategy->getTableName($this->_class, $this->_platform), + $updateData[$tableName], $this->_class->isVersioned + ); + + if ($this->_class->isVersioned) { + $id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity); + $this->assignDefaultVersionValue($entity, $id); + } + } + } + + /** + * Performs an UPDATE statement for an entity on a specific table. + * The UPDATE can optionally be versioned, which requires the entity to have a version field. + * + * @param object $entity The entity object being updated. + * @param string $quotedTableName The quoted name of the table to apply the UPDATE on. + * @param array $updateData The map of columns to update (column => value). + * @param boolean $versioned Whether the UPDATE should be versioned. + */ + protected final function _updateTable($entity, $quotedTableName, array $updateData, $versioned = false) + { + $set = $params = $types = array(); + + foreach ($updateData as $columnName => $value) { + $column = $columnName; + $placeholder = '?'; + + if (isset($this->_class->fieldNames[$columnName])) { + $column = $this->quoteStrategy->getColumnName($this->_class->fieldNames[$columnName], $this->_class, $this->_platform); + + if (isset($this->_class->fieldMappings[$this->_class->fieldNames[$columnName]]['requireSQLConversion'])) { + $type = Type::getType($this->_columnTypes[$columnName]); + $placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform); + } + } else if (isset($this->quotedColumns[$columnName])) { + $column = $this->quotedColumns[$columnName]; + } + + $set[] = $column . ' = ' . $placeholder; + $params[] = $value; + $types[] = $this->_columnTypes[$columnName]; + } + + $where = array(); + $id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity); + + foreach ($this->_class->identifier as $idField) { + if (isset($this->_class->associationMappings[$idField])) { + $targetMapping = $this->_em->getClassMetadata($this->_class->associationMappings[$idField]['targetEntity']); + $where[] = $this->_class->associationMappings[$idField]['joinColumns'][0]['name']; + $params[] = $id[$idField]; + + switch (true) { + case (isset($targetMapping->fieldMappings[$targetMapping->identifier[0]])): + $types[] = $targetMapping->fieldMappings[$targetMapping->identifier[0]]['type']; + break; + + case (isset($targetMapping->associationMappings[$targetMapping->identifier[0]])): + $types[] = $targetMapping->associationMappings[$targetMapping->identifier[0]]['type']; + break; + + default: + throw ORMException::unrecognizedField($targetMapping->identifier[0]); + } + } else { + $where[] = $this->quoteStrategy->getColumnName($idField, $this->_class, $this->_platform); + $params[] = $id[$idField]; + $types[] = $this->_class->fieldMappings[$idField]['type']; + } + } + + if ($versioned) { + $versionField = $this->_class->versionField; + $versionFieldType = $this->_class->fieldMappings[$versionField]['type']; + $versionColumn = $this->quoteStrategy->getColumnName($versionField, $this->_class, $this->_platform); + + if ($versionFieldType == Type::INTEGER) { + $set[] = $versionColumn . ' = ' . $versionColumn . ' + 1'; + } else if ($versionFieldType == Type::DATETIME) { + $set[] = $versionColumn . ' = CURRENT_TIMESTAMP'; + } + + $where[] = $versionColumn; + $params[] = $this->_class->reflFields[$versionField]->getValue($entity); + $types[] = $this->_class->fieldMappings[$versionField]['type']; + } + + $sql = 'UPDATE ' . $quotedTableName + . ' SET ' . implode(', ', $set) + . ' WHERE ' . implode(' = ? AND ', $where) . ' = ?'; + + $result = $this->_conn->executeUpdate($sql, $params, $types); + + if ($versioned && ! $result) { + throw OptimisticLockException::lockFailed($entity); + } + } + + /** + * @todo Add check for platform if it supports foreign keys/cascading. + * @param array $identifier + * @return void + */ + protected function deleteJoinTableRecords($identifier) + { + foreach ($this->_class->associationMappings as $mapping) { + if ($mapping['type'] == ClassMetadata::MANY_TO_MANY) { + // @Todo this only covers scenarios with no inheritance or of the same level. Is there something + // like self-referential relationship between different levels of an inheritance hierachy? I hope not! + $selfReferential = ($mapping['targetEntity'] == $mapping['sourceEntity']); + $otherKeys = array(); + $keys = array(); + + if ( ! $mapping['isOwningSide']) { + $relatedClass = $this->_em->getClassMetadata($mapping['targetEntity']); + $mapping = $relatedClass->associationMappings[$mapping['mappedBy']]; + + foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { + $keys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $relatedClass, $this->_platform); + } + + if ($selfReferential) { + foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { + $otherKeys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $relatedClass, $this->_platform); + } + } + } else { + + foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { + $keys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + } + + if ($selfReferential) { + foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { + $otherKeys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + } + } + } + + if ( ! isset($mapping['isOnDeleteCascade'])) { + + $joinTableName = $this->quoteStrategy->getJoinTableName($mapping, $this->_class, $this->_platform); + + $this->_conn->delete($joinTableName, array_combine($keys, $identifier)); + + if ($selfReferential) { + $this->_conn->delete($joinTableName, array_combine($otherKeys, $identifier)); + } + } + } + } + } + + /** + * Deletes a managed entity. + * + * The entity to delete must be managed and have a persistent identifier. + * The deletion happens instantaneously. + * + * Subclasses may override this method to customize the semantics of entity deletion. + * + * @param object $entity The entity to delete. + */ + public function delete($entity) + { + $identifier = $this->_em->getUnitOfWork()->getEntityIdentifier($entity); + + $this->deleteJoinTableRecords($identifier); + + $id = array_combine($this->quoteStrategy->getIdentifierColumnNames($this->_class, $this->_platform), $identifier); + + $this->_conn->delete($this->quoteStrategy->getTableName($this->_class, $this->_platform), $id); + } + + /** + * Prepares the changeset of an entity for database insertion (UPDATE). + * + * The changeset is obtained from the currently running UnitOfWork. + * + * During this preparation the array that is passed as the second parameter is filled with + * => pairs, grouped by table name. + * + * Example: + * + * array( + * 'foo_table' => array('column1' => 'value1', 'column2' => 'value2', ...), + * 'bar_table' => array('columnX' => 'valueX', 'columnY' => 'valueY', ...), + * ... + * ) + * + * + * @param object $entity The entity for which to prepare the data. + * @return array The prepared data. + */ + protected function _prepareUpdateData($entity) + { + $result = array(); + $uow = $this->_em->getUnitOfWork(); + + if (($versioned = $this->_class->isVersioned) != false) { + $versionField = $this->_class->versionField; + } + + foreach ($uow->getEntityChangeSet($entity) as $field => $change) { + if ($versioned && $versionField == $field) { + continue; + } + + $newVal = $change[1]; + + if (isset($this->_class->associationMappings[$field])) { + $assoc = $this->_class->associationMappings[$field]; + + // Only owning side of x-1 associations can have a FK column. + if ( ! $assoc['isOwningSide'] || ! ($assoc['type'] & ClassMetadata::TO_ONE)) { + continue; + } + + if ($newVal !== null) { + $oid = spl_object_hash($newVal); + + if (isset($this->_queuedInserts[$oid]) || $uow->isScheduledForInsert($newVal)) { + // The associated entity $newVal is not yet persisted, so we must + // set $newVal = null, in order to insert a null value and schedule an + // extra update on the UnitOfWork. + $uow->scheduleExtraUpdate($entity, array( + $field => array(null, $newVal) + )); + $newVal = null; + } + } + + if ($newVal !== null) { + $newValId = $uow->getEntityIdentifier($newVal); + } + + $targetClass = $this->_em->getClassMetadata($assoc['targetEntity']); + $owningTable = $this->getOwningTable($field); + + foreach ($assoc['joinColumns'] as $joinColumn) { + $sourceColumn = $joinColumn['name']; + $targetColumn = $joinColumn['referencedColumnName']; + $quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + + $this->quotedColumns[$sourceColumn] = $quotedColumn; + + if ($newVal === null) { + $result[$owningTable][$sourceColumn] = null; + } else if ($targetClass->containsForeignIdentifier) { + $result[$owningTable][$sourceColumn] = $newValId[$targetClass->getFieldForColumn($targetColumn)]; + } else { + $result[$owningTable][$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]]; + } + + $this->_columnTypes[$sourceColumn] = $targetClass->getTypeOfColumn($targetColumn); + } + } else { + $columnName = $this->_class->columnNames[$field]; + $this->_columnTypes[$columnName] = $this->_class->fieldMappings[$field]['type']; + $result[$this->getOwningTable($field)][$columnName] = $newVal; + } + } + + return $result; + } + + /** + * Prepares the data changeset of a managed entity for database insertion (initial INSERT). + * The changeset of the entity is obtained from the currently running UnitOfWork. + * + * The default insert data preparation is the same as for updates. + * + * @param object $entity The entity for which to prepare the data. + * @return array The prepared data for the tables to update. + * @see _prepareUpdateData + */ + protected function _prepareInsertData($entity) + { + return $this->_prepareUpdateData($entity); + } + + /** + * Gets the name of the table that owns the column the given field is mapped to. + * + * The default implementation in BasicEntityPersister always returns the name + * of the table the entity type of this persister is mapped to, since an entity + * is always persisted to a single table with a BasicEntityPersister. + * + * @param string $fieldName The field name. + * @return string The table name. + */ + public function getOwningTable($fieldName) + { + return $this->_class->getTableName(); + } + + /** + * Loads an entity by a list of field criteria. + * + * @param array $criteria The criteria by which to load the entity. + * @param object $entity The entity to load the data into. If not specified, + * a new entity is created. + * @param $assoc The association that connects the entity to load to another entity, if any. + * @param array $hints Hints for entity creation. + * @param int $lockMode + * @param int $limit Limit number of results + * @return object The loaded and managed entity instance or NULL if the entity can not be found. + * @todo Check identity map? loadById method? Try to guess whether $criteria is the id? + */ + public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = 0, $limit = null) + { + $sql = $this->_getSelectEntitiesSQL($criteria, $assoc, $lockMode, $limit); + list($params, $types) = $this->expandParameters($criteria); + $stmt = $this->_conn->executeQuery($sql, $params, $types); + + if ($entity !== null) { + $hints[Query::HINT_REFRESH] = true; + $hints[Query::HINT_REFRESH_ENTITY] = $entity; + } + + $hydrator = $this->_em->newHydrator($this->_selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + $entities = $hydrator->hydrateAll($stmt, $this->_rsm, $hints); + + return $entities ? $entities[0] : null; + } + + /** + * Loads an entity of this persister's mapped class as part of a single-valued + * association from another entity. + * + * @param array $assoc The association to load. + * @param object $sourceEntity The entity that owns the association (not necessarily the "owning side"). + * @param array $identifier The identifier of the entity to load. Must be provided if + * the association to load represents the owning side, otherwise + * the identifier is derived from the $sourceEntity. + * @return object The loaded and managed entity instance or NULL if the entity can not be found. + */ + public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = array()) + { + if (($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) != false) { + return $foundEntity; + } + + $targetClass = $this->_em->getClassMetadata($assoc['targetEntity']); + + if ($assoc['isOwningSide']) { + $isInverseSingleValued = $assoc['inversedBy'] && ! $targetClass->isCollectionValuedAssociation($assoc['inversedBy']); + + // Mark inverse side as fetched in the hints, otherwise the UoW would + // try to load it in a separate query (remember: to-one inverse sides can not be lazy). + $hints = array(); + + if ($isInverseSingleValued) { + $hints['fetched']["r"][$assoc['inversedBy']] = true; + } + + /* cascade read-only status + if ($this->_em->getUnitOfWork()->isReadOnly($sourceEntity)) { + $hints[Query::HINT_READ_ONLY] = true; + } + */ + + $targetEntity = $this->load($identifier, null, $assoc, $hints); + + // Complete bidirectional association, if necessary + if ($targetEntity !== null && $isInverseSingleValued) { + $targetClass->reflFields[$assoc['inversedBy']]->setValue($targetEntity, $sourceEntity); + } + } else { + $sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']); + $owningAssoc = $targetClass->getAssociationMapping($assoc['mappedBy']); + + // TRICKY: since the association is specular source and target are flipped + foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) { + if ( ! isset($sourceClass->fieldNames[$sourceKeyColumn])) { + throw MappingException::joinColumnMustPointToMappedField( + $sourceClass->name, $sourceKeyColumn + ); + } + + // unset the old value and set the new sql aliased value here. By definition + // unset($identifier[$targetKeyColumn] works here with how UnitOfWork::createEntity() calls this method. + $identifier[$this->_getSQLTableAlias($targetClass->name) . "." . $targetKeyColumn] = + $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity); + + unset($identifier[$targetKeyColumn]); + } + + $targetEntity = $this->load($identifier, null, $assoc); + + if ($targetEntity !== null) { + $targetClass->setFieldValue($targetEntity, $assoc['mappedBy'], $sourceEntity); + } + } + + return $targetEntity; + } + + /** + * Refreshes a managed entity. + * + * @param array $id The identifier of the entity as an associative array from + * column or field names to values. + * @param object $entity The entity to refresh. + */ + public function refresh(array $id, $entity, $lockMode = 0) + { + $sql = $this->_getSelectEntitiesSQL($id, null, $lockMode); + list($params, $types) = $this->expandParameters($id); + $stmt = $this->_conn->executeQuery($sql, $params, $types); + + $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); + $hydrator->hydrateAll($stmt, $this->_rsm, array(Query::HINT_REFRESH => true)); + } + + /** + * Load Entities matching the given Criteria object + * + * @param \Doctrine\Common\Collections\Criteria $criteria + * + * @return array + */ + public function loadCriteria(Criteria $criteria) + { + $orderBy = $criteria->getOrderings(); + $limit = $criteria->getMaxResults(); + $offset = $criteria->getFirstResult(); + + $sql = $this->_getSelectEntitiesSQL($criteria, null, 0, $limit, $offset, $orderBy); + + list($params, $types) = $this->expandCriteriaParameters($criteria); + + $stmt = $this->_conn->executeQuery($sql, $params, $types); + + $hydrator = $this->_em->newHydrator(($this->_selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + + return $hydrator->hydrateAll($stmt, $this->_rsm, array('deferEagerLoads' => true)); + } + + /** + * Expand Criteria Parameters by walking the expressions and grabbing all + * parameters and types from it. + * + * @param \Doctrine\Common\Collections\Criteria $criteria + * + * @return array(array(), array()) + */ + private function expandCriteriaParameters(Criteria $criteria) + { + $expression = $criteria->getWhereExpression(); + + if ($expression === null) { + return array(array(), array()); + } + + $valueVisitor = new SqlValueVisitor(); + $valueVisitor->dispatch($expression); + + list($values, $types) = $valueVisitor->getParamsAndTypes(); + + $sqlValues = array(); + foreach ($values as $value) { + $sqlValues[] = $this->getValue($value); + } + + $sqlTypes = array(); + foreach ($types as $type) { + list($field, $value) = $type; + $sqlTypes[] = $this->getType($field, $value); + } + + return array($sqlValues, $sqlTypes); + } + + /** + * Loads a list of entities by a list of field criteria. + * + * @param array $criteria + * @param array $orderBy + * @param int $limit + * @param int $offset + * @return array + */ + public function loadAll(array $criteria = array(), array $orderBy = null, $limit = null, $offset = null) + { + $sql = $this->_getSelectEntitiesSQL($criteria, null, 0, $limit, $offset, $orderBy); + list($params, $types) = $this->expandParameters($criteria); + $stmt = $this->_conn->executeQuery($sql, $params, $types); + + $hydrator = $this->_em->newHydrator(($this->_selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + + return $hydrator->hydrateAll($stmt, $this->_rsm, array('deferEagerLoads' => true)); + } + + /** + * Get (sliced or full) elements of the given collection. + * + * @param array $assoc + * @param object $sourceEntity + * @param int|null $offset + * @param int|null $limit + * @return array + */ + public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null) + { + $stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit); + + return $this->loadArrayFromStatement($assoc, $stmt); + } + + /** + * Load an array of entities from a given dbal statement. + * + * @param array $assoc + * @param \Doctrine\DBAL\Statement $stmt + * + * @return array + */ + private function loadArrayFromStatement($assoc, $stmt) + { + $hints = array('deferEagerLoads' => true); + + if (isset($assoc['indexBy'])) { + $rsm = clone ($this->_rsm); // this is necessary because the "default rsm" should be changed. + $rsm->addIndexBy('r', $assoc['indexBy']); + } else { + $rsm = $this->_rsm; + } + + $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); + + return $hydrator->hydrateAll($stmt, $rsm, $hints); + } + + /** + * Hydrate a collection from a given dbal statement. + * + * @param array $assoc + * @param \Doctrine\DBAL\Statement $stmt + * @param PersistentCollection $coll + * + * @return array + */ + private function loadCollectionFromStatement($assoc, $stmt, $coll) + { + $hints = array('deferEagerLoads' => true, 'collection' => $coll); + + if (isset($assoc['indexBy'])) { + $rsm = clone ($this->_rsm); // this is necessary because the "default rsm" should be changed. + $rsm->addIndexBy('r', $assoc['indexBy']); + } else { + $rsm = $this->_rsm; + } + + $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); + + return $hydrator->hydrateAll($stmt, $rsm, $hints); + } + + /** + * Loads a collection of entities of a many-to-many association. + * + * @param ManyToManyMapping $assoc The association mapping of the association being loaded. + * @param object $sourceEntity The entity that owns the collection. + * @param PersistentCollection $coll The collection to fill. + * @param int|null $offset + * @param int|null $limit + * @return array + */ + public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll) + { + $stmt = $this->getManyToManyStatement($assoc, $sourceEntity); + + return $this->loadCollectionFromStatement($assoc, $stmt, $coll); + } + + private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null) + { + $criteria = array(); + $sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']); + + if ($assoc['isOwningSide']) { + $quotedJoinTable = $this->quoteStrategy->getJoinTableName($assoc, $sourceClass, $this->_platform); + + foreach ($assoc['joinTable']['joinColumns'] as $joinColumn) { + $relationKeyColumn = $joinColumn['name']; + $sourceKeyColumn = $joinColumn['referencedColumnName']; + $quotedKeyColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $sourceClass, $this->_platform); + + if ($sourceClass->containsForeignIdentifier) { + $field = $sourceClass->getFieldForColumn($sourceKeyColumn); + $value = $sourceClass->reflFields[$field]->getValue($sourceEntity); + + if (isset($sourceClass->associationMappings[$field])) { + $value = $this->_em->getUnitOfWork()->getEntityIdentifier($value); + $value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]]; + } + + $criteria[$quotedJoinTable . "." . $quotedKeyColumn] = $value; + } else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) { + $criteria[$quotedJoinTable . "." . $quotedKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity); + } else { + throw MappingException::joinColumnMustPointToMappedField( + $sourceClass->name, $sourceKeyColumn + ); + } + } + } else { + $owningAssoc = $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']]; + $quotedJoinTable = $this->quoteStrategy->getJoinTableName($owningAssoc, $sourceClass, $this->_platform); + + // TRICKY: since the association is inverted source and target are flipped + foreach ($owningAssoc['joinTable']['inverseJoinColumns'] as $joinColumn) { + $relationKeyColumn = $joinColumn['name']; + $sourceKeyColumn = $joinColumn['referencedColumnName']; + $quotedKeyColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $sourceClass, $this->_platform); + + if ($sourceClass->containsForeignIdentifier) { + $field = $sourceClass->getFieldForColumn($sourceKeyColumn); + $value = $sourceClass->reflFields[$field]->getValue($sourceEntity); + + if (isset($sourceClass->associationMappings[$field])) { + $value = $this->_em->getUnitOfWork()->getEntityIdentifier($value); + $value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]]; + } + + $criteria[$quotedJoinTable . "." . $quotedKeyColumn] = $value; + } else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) { + $criteria[$quotedJoinTable . "." . $quotedKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity); + } else { + throw MappingException::joinColumnMustPointToMappedField( + $sourceClass->name, $sourceKeyColumn + ); + } + } + } + + $sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset); + list($params, $types) = $this->expandParameters($criteria); + + return $this->_conn->executeQuery($sql, $params, $types); + } + + /** + * Gets the SELECT SQL to select one or more entities by a set of field criteria. + * + * @param array|\Doctrine\Common\Collections\Criteria $criteria + * @param AssociationMapping $assoc + * @param string $orderBy + * @param int $lockMode + * @param int $limit + * @param int $offset + * @param array $orderBy + * @return string + * @todo Refactor: _getSelectSQL(...) + */ + protected function _getSelectEntitiesSQL($criteria, $assoc = null, $lockMode = 0, $limit = null, $offset = null, array $orderBy = null) + { + $joinSql = ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) ? $this->_getSelectManyToManyJoinSQL($assoc) : ''; + $conditionSql = ($criteria instanceof Criteria) + ? $this->_getSelectConditionCriteriaSQL($criteria) + : $this->_getSelectConditionSQL($criteria, $assoc); + + $orderBy = ($assoc !== null && isset($assoc['orderBy'])) ? $assoc['orderBy'] : $orderBy; + $orderBySql = $orderBy ? $this->_getOrderBySQL($orderBy, $this->_getSQLTableAlias($this->_class->name)) : ''; + + $lockSql = ''; + + if ($lockMode == LockMode::PESSIMISTIC_READ) { + $lockSql = ' ' . $this->_platform->getReadLockSql(); + } else if ($lockMode == LockMode::PESSIMISTIC_WRITE) { + $lockSql = ' ' . $this->_platform->getWriteLockSql(); + } + + $alias = $this->_getSQLTableAlias($this->_class->name); + + if ($filterSql = $this->generateFilterConditionSQL($this->_class, $alias)) { + if ($conditionSql) { + $conditionSql .= ' AND '; + } + + $conditionSql .= $filterSql; + } + + return $this->_platform->modifyLimitQuery('SELECT ' . $this->_getSelectColumnListSQL() + . $this->_platform->appendLockHint(' FROM ' . $this->quoteStrategy->getTableName($this->_class, $this->_platform) . ' ' + . $alias, $lockMode) + . $this->_selectJoinSql . $joinSql + . ($conditionSql ? ' WHERE ' . $conditionSql : '') + . $orderBySql, $limit, $offset) + . $lockSql; + } + + /** + * Gets the ORDER BY SQL snippet for ordered collections. + * + * @param array $orderBy + * @param string $baseTableAlias + * @return string + */ + protected final function _getOrderBySQL(array $orderBy, $baseTableAlias) + { + $orderBySql = ''; + + foreach ($orderBy as $fieldName => $orientation) { + if ( ! isset($this->_class->fieldMappings[$fieldName])) { + throw ORMException::unrecognizedField($fieldName); + } + + $orientation = strtoupper(trim($orientation)); + if ($orientation != 'ASC' && $orientation != 'DESC') { + throw ORMException::invalidOrientation($this->_class->name, $fieldName); + } + + $tableAlias = isset($this->_class->fieldMappings[$fieldName]['inherited']) ? + $this->_getSQLTableAlias($this->_class->fieldMappings[$fieldName]['inherited']) + : $baseTableAlias; + + $columnName = $this->quoteStrategy->getColumnName($fieldName, $this->_class, $this->_platform); + + $orderBySql .= $orderBySql ? ', ' : ' ORDER BY '; + $orderBySql .= $tableAlias . '.' . $columnName . ' ' . $orientation; + } + + return $orderBySql; + } + + /** + * Gets the SQL fragment with the list of columns to select when querying for + * an entity in this persister. + * + * Subclasses should override this method to alter or change the select column + * list SQL fragment. Note that in the implementation of BasicEntityPersister + * the resulting SQL fragment is generated only once and cached in {@link _selectColumnListSql}. + * Subclasses may or may not do the same. + * + * @return string The SQL fragment. + * @todo Rename: _getSelectColumnsSQL() + */ + protected function _getSelectColumnListSQL() + { + if ($this->_selectColumnListSql !== null) { + return $this->_selectColumnListSql; + } + + $columnList = ''; + $this->_rsm = new Query\ResultSetMapping(); + $this->_rsm->addEntityResult($this->_class->name, 'r'); // r for root + + // Add regular columns to select list + foreach ($this->_class->fieldNames as $field) { + if ($columnList) $columnList .= ', '; + + $columnList .= $this->_getSelectColumnSQL($field, $this->_class); + } + + $this->_selectJoinSql = ''; + $eagerAliasCounter = 0; + + foreach ($this->_class->associationMappings as $assocField => $assoc) { + $assocColumnSQL = $this->_getSelectColumnAssociationSQL($assocField, $assoc, $this->_class); + + if ($assocColumnSQL) { + if ($columnList) $columnList .= ', '; + + $columnList .= $assocColumnSQL; + } + + if ($assoc['type'] & ClassMetadata::TO_ONE && ($assoc['fetch'] == ClassMetadata::FETCH_EAGER || !$assoc['isOwningSide'])) { + $eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']); + + if ($eagerEntity->inheritanceType != ClassMetadata::INHERITANCE_TYPE_NONE) { + continue; // now this is why you shouldn't use inheritance + } + + $assocAlias = 'e' . ($eagerAliasCounter++); + $this->_rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField); + + foreach ($eagerEntity->fieldNames as $field) { + if ($columnList) $columnList .= ', '; + + $columnList .= $this->_getSelectColumnSQL($field, $eagerEntity, $assocAlias); + } + + foreach ($eagerEntity->associationMappings as $assoc2Field => $assoc2) { + $assoc2ColumnSQL = $this->_getSelectColumnAssociationSQL($assoc2Field, $assoc2, $eagerEntity, $assocAlias); + + if ($assoc2ColumnSQL) { + if ($columnList) $columnList .= ', '; + $columnList .= $assoc2ColumnSQL; + } + } + $first = true; + + if ($assoc['isOwningSide']) { + $this->_selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($assoc['joinColumns']); + $this->_selectJoinSql .= ' ' . $this->quoteStrategy->getTableName($eagerEntity, $this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON '; + + $tableAlias = $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias); + foreach ($assoc['joinColumns'] as $joinColumn) { + $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + $targetCol = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->_class, $this->_platform); + + if ( ! $first) { + $this->_selectJoinSql .= ' AND '; + } + $this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = ' + . $tableAlias . '.' . $targetCol; + $first = false; + } + + // Add filter SQL + if ($filterSql = $this->generateFilterConditionSQL($eagerEntity, $tableAlias)) { + $this->_selectJoinSql .= ' AND ' . $filterSql; + } + } else { + $eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']); + $owningAssoc = $eagerEntity->getAssociationMapping($assoc['mappedBy']); + + $this->_selectJoinSql .= ' LEFT JOIN'; + $this->_selectJoinSql .= ' ' . $this->quoteStrategy->getTableName($eagerEntity, $this->_platform) . ' ' + . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) . ' ON '; + + foreach ($owningAssoc['sourceToTargetKeyColumns'] as $sourceCol => $targetCol) { + if ( ! $first) { + $this->_selectJoinSql .= ' AND '; + } + + $this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = ' + . $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol; + $first = false; + } + } + } + } + + $this->_selectColumnListSql = $columnList; + + return $this->_selectColumnListSql; + } + + /** + * Gets the SQL join fragment used when selecting entities from an association. + * + * @param string $field + * @param array $assoc + * @param ClassMetadata $class + * @param string $alias + * + * @return string + */ + protected function _getSelectColumnAssociationSQL($field, $assoc, ClassMetadata $class, $alias = 'r') + { + $columnList = array(); + + if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) { + + foreach ($assoc['joinColumns'] as $joinColumn) { + + $quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + $resultColumnName = $this->getSQLColumnAlias($joinColumn['name']); + $columnList[] = $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) ) + . '.' . $quotedColumn . ' AS ' . $resultColumnName; + + $this->_rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, isset($assoc['id']) && $assoc['id'] === true); + } + } + + return implode(', ', $columnList); + } + + /** + * Gets the SQL join fragment used when selecting entities from a + * many-to-many association. + * + * @param ManyToManyMapping $manyToMany + * @return string + */ + protected function _getSelectManyToManyJoinSQL(array $manyToMany) + { + $conditions = array(); + $association = $manyToMany; + $sourceTableAlias = $this->_getSQLTableAlias($this->_class->name); + + if ( ! $manyToMany['isOwningSide']) { + $targetEntity = $this->_em->getClassMetadata($manyToMany['targetEntity']); + $association = $targetEntity->associationMappings[$manyToMany['mappedBy']]; + } + + $joinTableName = $this->quoteStrategy->getJoinTableName($association, $this->_class, $this->_platform); + $joinColumns = ($manyToMany['isOwningSide']) + ? $association['joinTable']['inverseJoinColumns'] + : $association['joinTable']['joinColumns']; + + foreach ($joinColumns as $joinColumn) { + $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $this->_class, $this->_platform); + $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableName . '.' . $quotedSourceColumn; + } + + return ' INNER JOIN ' . $joinTableName . ' ON ' . implode(' AND ', $conditions); + } + + /** + * Gets the INSERT SQL used by the persister to persist a new entity. + * + * @return string + */ + protected function _getInsertSQL() + { + if ($this->_insertSql === null) { + $insertSql = ''; + $columns = $this->_getInsertColumnList(); + + if (empty($columns)) { + $insertSql = $this->_platform->getEmptyIdentityInsertSQL( + $this->quoteStrategy->getTableName($this->_class, $this->_platform), + $this->quoteStrategy->getColumnName($this->_class->identifier[0], $this->_class, $this->_platform) + ); + } else { + $columns = array_unique($columns); + + $values = array(); + foreach ($columns as $column) { + $placeholder = '?'; + + if (isset($this->_class->fieldNames[$column]) && + isset($this->_columnTypes[$this->_class->fieldNames[$column]]) && + isset($this->_class->fieldMappings[$this->_class->fieldNames[$column]]['requireSQLConversion'])) { + $type = Type::getType($this->_columnTypes[$this->_class->fieldNames[$column]]); + $placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform); + } + + $values[] = $placeholder; + } + + $insertSql = 'INSERT INTO ' . $this->quoteStrategy->getTableName($this->_class, $this->_platform) + . ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $values) . ')'; + } + + $this->_insertSql = $insertSql; + } + + return $this->_insertSql; + } + + /** + * Gets the list of columns to put in the INSERT SQL statement. + * + * Subclasses should override this method to alter or change the list of + * columns placed in the INSERT statements used by the persister. + * + * @return array The list of columns. + */ + protected function _getInsertColumnList() + { + $columns = array(); + + foreach ($this->_class->reflFields as $name => $field) { + if ($this->_class->isVersioned && $this->_class->versionField == $name) { + continue; + } + + if (isset($this->_class->associationMappings[$name])) { + $assoc = $this->_class->associationMappings[$name]; + if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) { + foreach ($assoc['joinColumns'] as $joinColumn) { + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->_class, $this->_platform); + } + } + } else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->_class->identifier[0] != $name) { + $columns[] = $this->quoteStrategy->getColumnName($name, $this->_class, $this->_platform); + $this->_columnTypes[$name] = $this->_class->fieldMappings[$name]['type']; + } + } + + return $columns; + } + + /** + * Gets the SQL snippet of a qualified column name for the given field name. + * + * @param string $field The field name. + * @param ClassMetadata $class The class that declares this field. The table this class is + * mapped to must own the column for the given field. + * @param string $alias + */ + protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r') + { + $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) + . '.' . $this->quoteStrategy->getColumnName($field, $class, $this->_platform); + $columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]); + + $this->_rsm->addFieldResult($alias, $columnAlias, $field); + + if (isset($class->fieldMappings[$field]['requireSQLConversion'])) { + $type = Type::getType($class->getTypeOfField($field)); + $sql = $type->convertToPHPValueSQL($sql, $this->_platform); + } + + return $sql . ' AS ' . $columnAlias; + } + + /** + * Gets the SQL table alias for the given class name. + * + * @param string $className + * @return string The SQL table alias. + * @todo Reconsider. Binding table aliases to class names is not such a good idea. + */ + protected function _getSQLTableAlias($className, $assocName = '') + { + if ($assocName) { + $className .= '#' . $assocName; + } + + if (isset($this->_sqlTableAliases[$className])) { + return $this->_sqlTableAliases[$className]; + } + + $tableAlias = 't' . $this->_sqlAliasCounter++; + + $this->_sqlTableAliases[$className] = $tableAlias; + + return $tableAlias; + } + + /** + * Lock all rows of this entity matching the given criteria with the specified pessimistic lock mode + * + * @param array $criteria + * @param int $lockMode + * @return void + */ + public function lock(array $criteria, $lockMode) + { + $conditionSql = $this->_getSelectConditionSQL($criteria); + + if ($lockMode == LockMode::PESSIMISTIC_READ) { + $lockSql = $this->_platform->getReadLockSql(); + } else if ($lockMode == LockMode::PESSIMISTIC_WRITE) { + $lockSql = $this->_platform->getWriteLockSql(); + } + + $sql = 'SELECT 1 ' + . $this->_platform->appendLockHint($this->getLockTablesSql(), $lockMode) + . ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' ' . $lockSql; + + list($params, $types) = $this->expandParameters($criteria); + + $this->_conn->executeQuery($sql, $params, $types); + } + + /** + * Get the FROM and optionally JOIN conditions to lock the entity managed by this persister. + * + * @return string + */ + protected function getLockTablesSql() + { + return 'FROM ' . $this->quoteStrategy->getTableName($this->_class, $this->_platform) . ' ' + . $this->_getSQLTableAlias($this->_class->name); + } + + /** + * Get the Select Where Condition from a Criteria object. + * + * @param \Doctrine\Common\Collections\Criteria $criteria + * @return string + */ + protected function _getSelectConditionCriteriaSQL(Criteria $criteria) + { + $expression = $criteria->getWhereExpression(); + + if ($expression === null) { + return ''; + } + + $visitor = new SqlExpressionVisitor($this); + + return $visitor->dispatch($expression); + } + + /** + * Get the SQL WHERE condition for matching a field with a given value. + * + * @param string $field + * @param mixed $value + * @param array|null $assoc + * @param string $comparison + * + * @return string + */ + public function getSelectConditionStatementSQL($field, $value, $assoc = null, $comparison = null) + { + $conditionSql = $this->getSelectConditionStatementColumnSQL($field, $assoc); + $placeholder = '?'; + + if (isset($this->_class->fieldMappings[$field]['requireSQLConversion'])) { + $type = Type::getType($this->_class->getTypeOfField($field)); + $placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->_platform); + } + + $conditionSql .= ($comparison === null) + ? ((is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ' . $placeholder)) + : ' ' . sprintf(self::$comparisonMap[$comparison], $placeholder); + + + return $conditionSql; + } + + /** + * Build the left-hand-side of a where condition statement. + * + * @param string $field + * @param array $assoc + * + * @return string + */ + protected function getSelectConditionStatementColumnSQL($field, $assoc = null) + { + switch (true) { + case (isset($this->_class->columnNames[$field])): + $className = (isset($this->_class->fieldMappings[$field]['inherited'])) + ? $this->_class->fieldMappings[$field]['inherited'] + : $this->_class->name; + + return $this->_getSQLTableAlias($className) . '.' . $this->quoteStrategy->getColumnName($field, $this->_class, $this->_platform); + + case (isset($this->_class->associationMappings[$field])): + if ( ! $this->_class->associationMappings[$field]['isOwningSide']) { + throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field); + } + + $className = (isset($this->_class->associationMappings[$field]['inherited'])) + ? $this->_class->associationMappings[$field]['inherited'] + : $this->_class->name; + + return $this->_getSQLTableAlias($className) . '.' . $this->_class->associationMappings[$field]['joinColumns'][0]['name']; + + case ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false): + // very careless developers could potentially open up this normally hidden api for userland attacks, + // therefore checking for spaces and function calls which are not allowed. + + // found a join column condition, not really a "field" + return $field; + } + + throw ORMException::unrecognizedField($field); + } + + /** + * Gets the conditional SQL fragment used in the WHERE clause when selecting + * entities in this persister. + * + * Subclasses are supposed to override this method if they intend to change + * or alter the criteria by which entities are selected. + * + * @param array $criteria + * @param AssociationMapping $assoc + * @return string + */ + protected function _getSelectConditionSQL(array $criteria, $assoc = null) + { + $conditionSql = ''; + + foreach ($criteria as $field => $value) { + $conditionSql .= $conditionSql ? ' AND ' : ''; + $conditionSql .= $this->getSelectConditionStatementSQL($field, $value, $assoc); + } + + return $conditionSql; + } + + /** + * Return an array with (sliced or full list) of elements in the specified collection. + * + * @param array $assoc + * @param object $sourceEntity + * @param int $offset + * @param int $limit + * @return array + */ + public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null) + { + $stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit); + + return $this->loadArrayFromStatement($assoc, $stmt); + } + + /** + * Loads a collection of entities in a one-to-many association. + * + * @param array $assoc + * @param object $sourceEntity + * @param PersistentCollection $coll The collection to load/fill. + * @param int|null $offset + * @param int|null $limit + */ + public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll) + { + $stmt = $this->getOneToManyStatement($assoc, $sourceEntity); + + return $this->loadCollectionFromStatement($assoc, $stmt, $coll); + } + + /** + * Build criteria and execute SQL statement to fetch the one to many entities from. + * + * @param array $assoc + * @param object $sourceEntity + * @param int|null $offset + * @param int|null $limit + * @return \Doctrine\DBAL\Statement + */ + private function getOneToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null) + { + $criteria = array(); + $owningAssoc = $this->_class->associationMappings[$assoc['mappedBy']]; + $sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']); + + $tableAlias = $this->_getSQLTableAlias(isset($owningAssoc['inherited']) ? $owningAssoc['inherited'] : $this->_class->name); + + foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) { + if ($sourceClass->containsForeignIdentifier) { + $field = $sourceClass->getFieldForColumn($sourceKeyColumn); + $value = $sourceClass->reflFields[$field]->getValue($sourceEntity); + + if (isset($sourceClass->associationMappings[$field])) { + $value = $this->_em->getUnitOfWork()->getEntityIdentifier($value); + $value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]]; + } + + $criteria[$tableAlias . "." . $targetKeyColumn] = $value; + } else { + $criteria[$tableAlias . "." . $targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity); + } + } + + $sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset); + list($params, $types) = $this->expandParameters($criteria); + + return $this->_conn->executeQuery($sql, $params, $types); + } + + /** + * Expand the parameters from the given criteria and use the correct binding types if found. + * + * @param array $criteria + * @return array + */ + private function expandParameters($criteria) + { + $params = $types = array(); + + foreach ($criteria as $field => $value) { + if ($value === null) { + continue; // skip null values. + } + + $types[] = $this->getType($field, $value); + $params[] = $this->getValue($value); + } + + return array($params, $types); + } + + /** + * Infer field type to be used by parameter type casting. + * + * @param string $field + * @param mixed $value + * @return integer + */ + private function getType($field, $value) + { + switch (true) { + case (isset($this->_class->fieldMappings[$field])): + $type = $this->_class->fieldMappings[$field]['type']; + break; + + case (isset($this->_class->associationMappings[$field])): + $assoc = $this->_class->associationMappings[$field]; + + if (count($assoc['sourceToTargetKeyColumns']) > 1) { + throw Query\QueryException::associationPathCompositeKeyNotSupported(); + } + + $targetClass = $this->_em->getClassMetadata($assoc['targetEntity']); + $targetColumn = $assoc['joinColumns'][0]['referencedColumnName']; + $type = null; + + if (isset($targetClass->fieldNames[$targetColumn])) { + $type = $targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type']; + } + + break; + + default: + $type = null; + } + if (is_array($value)) { + $type = Type::getType( $type )->getBindingType(); + $type += Connection::ARRAY_PARAM_OFFSET; + } + + return $type; + } + + /** + * Retrieve parameter value + * + * @param mixed $value + * @return mixed + */ + private function getValue($value) + { + if (is_array($value)) { + $newValue = array(); + + foreach ($value as $itemValue) { + $newValue[] = $this->getIndividualValue($itemValue); + } + + return $newValue; + } + + return $this->getIndividualValue($value); + } + + /** + * Retrieve an invidiual parameter value + * + * @param mixed $value + * @return mixed + */ + private function getIndividualValue($value) + { + if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) { + if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) { + $idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value); + } else { + $class = $this->_em->getClassMetadata(get_class($value)); + $idValues = $class->getIdentifierValues($value); + } + + $value = $idValues[key($idValues)]; + } + + return $value; + } + + /** + * Checks whether the given managed entity exists in the database. + * + * @param object $entity + * @return boolean TRUE if the entity exists in the database, FALSE otherwise. + */ + public function exists($entity, array $extraConditions = array()) + { + $criteria = $this->_class->getIdentifierValues($entity); + + if ( ! $criteria) { + return false; + } + + if ($extraConditions) { + $criteria = array_merge($criteria, $extraConditions); + } + + $alias = $this->_getSQLTableAlias($this->_class->name); + + $sql = 'SELECT 1 ' + . $this->getLockTablesSql() + . ' WHERE ' . $this->_getSelectConditionSQL($criteria); + + if ($filterSql = $this->generateFilterConditionSQL($this->_class, $alias)) { + $sql .= ' AND ' . $filterSql; + } + + list($params) = $this->expandParameters($criteria); + + return (bool) $this->_conn->fetchColumn($sql, $params); + } + + /** + * Generates the appropriate join SQL for the given join column. + * + * @param array $joinColumns The join columns definition of an association. + * @return string LEFT JOIN if one of the columns is nullable, INNER JOIN otherwise. + */ + protected function getJoinSQLForJoinColumns($joinColumns) + { + // if one of the join columns is nullable, return left join + foreach ($joinColumns as $joinColumn) { + if ( ! isset($joinColumn['nullable']) || $joinColumn['nullable']) { + return 'LEFT JOIN'; + } + } + + return 'INNER JOIN'; + } + + /** + * Gets an SQL column alias for a column name. + * + * @param string $columnName + * @return string + */ + public function getSQLColumnAlias($columnName) + { + return $this->quoteStrategy->getColumnAlias($columnName, $this->_sqlAliasCounter++, $this->_platform); + } + + /** + * Generates the filter SQL for a given entity and table alias. + * + * @param ClassMetadata $targetEntity Metadata of the target entity. + * @param string $targetTableAlias The table alias of the joined/selected table. + * + * @return string The SQL query part to add to a query. + */ + protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) + { + $filterClauses = array(); + + foreach ($this->_em->getFilters()->getEnabledFilters() as $filter) { + if ('' !== $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) { + $filterClauses[] = '(' . $filterExpr . ')'; + } + } + + $sql = implode(' AND ', $filterClauses); + return $sql ? "(" . $sql . ")" : ""; // Wrap again to avoid "X or Y and FilterConditionSQL" + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/ElementCollectionPersister.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/ElementCollectionPersister.php new file mode 100644 index 0000000..0b0354a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/ElementCollectionPersister.php @@ -0,0 +1,30 @@ +. + */ +namespace Doctrine\ORM\Persisters; + +/** + * Persister for collections of basic elements / value types. + * + * @author robo + * @todo Implementation once support for collections of basic elements (i.e. strings) is added. + */ +abstract class ElementCollectionPersister extends AbstractCollectionPersister +{ + //put your code here +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php new file mode 100644 index 0000000..431b237 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php @@ -0,0 +1,492 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use Doctrine\ORM\ORMException; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Query\ResultSetMapping; + +use Doctrine\DBAL\LockMode; +use Doctrine\DBAL\Types\Type; + +use Doctrine\Common\Collections\Criteria; + +/** + * The joined subclass persister maps a single entity instance to several tables in the + * database as it is defined by the Class Table Inheritance strategy. + * + * @author Roman Borschel + * @author Benjamin Eberlei + * @author Alexander + * @since 2.0 + * @see http://martinfowler.com/eaaCatalog/classTableInheritance.html + */ +class JoinedSubclassPersister extends AbstractEntityInheritancePersister +{ + /** + * Map that maps column names to the table names that own them. + * This is mainly a temporary cache, used during a single request. + * + * @var array + */ + private $_owningTableMap = array(); + + /** + * Map of table to quoted table names. + * + * @var array + */ + private $_quotedTableMap = array(); + + /** + * {@inheritdoc} + */ + protected function _getDiscriminatorColumnTableName() + { + $class = ($this->_class->name !== $this->_class->rootEntityName) + ? $this->_em->getClassMetadata($this->_class->rootEntityName) + : $this->_class; + + return $class->getTableName(); + } + + /** + * This function finds the ClassMetadata instance in an inheritance hierarchy + * that is responsible for enabling versioning. + * + * @return \Doctrine\ORM\Mapping\ClassMetadata + */ + private function _getVersionedClassMetadata() + { + if (isset($this->_class->fieldMappings[$this->_class->versionField]['inherited'])) { + $definingClassName = $this->_class->fieldMappings[$this->_class->versionField]['inherited']; + + return $this->_em->getClassMetadata($definingClassName); + } + + return $this->_class; + } + + /** + * Gets the name of the table that owns the column the given field is mapped to. + * + * @param string $fieldName + * @return string + * @override + */ + public function getOwningTable($fieldName) + { + if (isset($this->_owningTableMap[$fieldName])) { + return $this->_owningTableMap[$fieldName]; + } + + if (isset($this->_class->associationMappings[$fieldName]['inherited'])) { + $cm = $this->_em->getClassMetadata($this->_class->associationMappings[$fieldName]['inherited']); + } else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) { + $cm = $this->_em->getClassMetadata($this->_class->fieldMappings[$fieldName]['inherited']); + } else { + $cm = $this->_class; + } + + $tableName = $cm->getTableName(); + + $this->_owningTableMap[$fieldName] = $tableName; + $this->_quotedTableMap[$tableName] = $this->quoteStrategy->getTableName($cm, $this->_platform); + + return $tableName; + } + + /** + * {@inheritdoc} + */ + public function executeInserts() + { + if ( ! $this->_queuedInserts) { + return; + } + + $postInsertIds = array(); + $idGen = $this->_class->idGenerator; + $isPostInsertId = $idGen->isPostInsertGenerator(); + + // Prepare statement for the root table + $rootClass = ($this->_class->name !== $this->_class->rootEntityName) ? $this->_em->getClassMetadata($this->_class->rootEntityName) : $this->_class; + $rootPersister = $this->_em->getUnitOfWork()->getEntityPersister($rootClass->name); + $rootTableName = $rootClass->getTableName(); + $rootTableStmt = $this->_conn->prepare($rootPersister->_getInsertSQL()); + + // Prepare statements for sub tables. + $subTableStmts = array(); + + if ($rootClass !== $this->_class) { + $subTableStmts[$this->_class->getTableName()] = $this->_conn->prepare($this->_getInsertSQL()); + } + + foreach ($this->_class->parentClasses as $parentClassName) { + $parentClass = $this->_em->getClassMetadata($parentClassName); + $parentTableName = $parentClass->getTableName(); + + if ($parentClass !== $rootClass) { + $parentPersister = $this->_em->getUnitOfWork()->getEntityPersister($parentClassName); + $subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->_getInsertSQL()); + } + } + + // Execute all inserts. For each entity: + // 1) Insert on root table + // 2) Insert on sub tables + foreach ($this->_queuedInserts as $entity) { + $insertData = $this->_prepareInsertData($entity); + + // Execute insert on root table + $paramIndex = 1; + + foreach ($insertData[$rootTableName] as $columnName => $value) { + $rootTableStmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]); + } + + $rootTableStmt->execute(); + + if ($isPostInsertId) { + $id = $idGen->generate($this->_em, $entity); + $postInsertIds[$id] = $entity; + } else { + $id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity); + } + + // Execute inserts on subtables. + // The order doesn't matter because all child tables link to the root table via FK. + foreach ($subTableStmts as $tableName => $stmt) { + $data = isset($insertData[$tableName]) ? $insertData[$tableName] : array(); + $paramIndex = 1; + + foreach ((array) $id as $idName => $idVal) { + $type = isset($this->_columnTypes[$idName]) ? $this->_columnTypes[$idName] : Type::STRING; + + $stmt->bindValue($paramIndex++, $idVal, $type); + } + + foreach ($data as $columnName => $value) { + $stmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]); + } + + $stmt->execute(); + } + } + + $rootTableStmt->closeCursor(); + + foreach ($subTableStmts as $stmt) { + $stmt->closeCursor(); + } + + if ($this->_class->isVersioned) { + $this->assignDefaultVersionValue($entity, $id); + } + + $this->_queuedInserts = array(); + + return $postInsertIds; + } + + /** + * {@inheritdoc} + */ + public function update($entity) + { + $updateData = $this->_prepareUpdateData($entity); + + if (($isVersioned = $this->_class->isVersioned) != false) { + $versionedClass = $this->_getVersionedClassMetadata(); + $versionedTable = $versionedClass->getTableName(); + } + + if ($updateData) { + foreach ($updateData as $tableName => $data) { + $this->_updateTable( + $entity, $this->_quotedTableMap[$tableName], $data, $isVersioned && $versionedTable == $tableName + ); + } + + // Make sure the table with the version column is updated even if no columns on that + // table were affected. + if ($isVersioned && ! isset($updateData[$versionedTable])) { + $this->_updateTable($entity, $this->quoteStrategy->getTableName($versionedClass, $this->_platform), array(), true); + + $id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity); + $this->assignDefaultVersionValue($entity, $id); + } + } + } + + /** + * {@inheritdoc} + */ + public function delete($entity) + { + $identifier = $this->_em->getUnitOfWork()->getEntityIdentifier($entity); + $this->deleteJoinTableRecords($identifier); + + $id = array_combine($this->_class->getIdentifierColumnNames(), $identifier); + + // If the database platform supports FKs, just + // delete the row from the root table. Cascades do the rest. + if ($this->_platform->supportsForeignKeyConstraints()) { + $this->_conn->delete( + $this->quoteStrategy->getTableName($this->_em->getClassMetadata($this->_class->rootEntityName), $this->_platform), $id + ); + } else { + // Delete from all tables individually, starting from this class' table up to the root table. + $this->_conn->delete($this->quoteStrategy->getTableName($this->_class, $this->_platform), $id); + + foreach ($this->_class->parentClasses as $parentClass) { + $this->_conn->delete( + $this->quoteStrategy->getTableName($this->_em->getClassMetadata($parentClass), $this->_platform), $id + ); + } + } + } + + /** + * {@inheritdoc} + */ + protected function _getSelectEntitiesSQL($criteria, $assoc = null, $lockMode = 0, $limit = null, $offset = null, array $orderBy = null) + { + $idColumns = $this->_class->getIdentifierColumnNames(); + $baseTableAlias = $this->_getSQLTableAlias($this->_class->name); + + // Create the column list fragment only once + if ($this->_selectColumnListSql === null) { + + $this->_rsm = new ResultSetMapping(); + $this->_rsm->addEntityResult($this->_class->name, 'r'); + + // Add regular columns + $columnList = ''; + + foreach ($this->_class->fieldMappings as $fieldName => $mapping) { + if ($columnList != '') $columnList .= ', '; + + $columnList .= $this->_getSelectColumnSQL( + $fieldName, + isset($mapping['inherited']) ? $this->_em->getClassMetadata($mapping['inherited']) : $this->_class + ); + } + + // Add foreign key columns + foreach ($this->_class->associationMappings as $assoc2) { + if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE) { + $tableAlias = isset($assoc2['inherited']) ? $this->_getSQLTableAlias($assoc2['inherited']) : $baseTableAlias; + + foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) { + if ($columnList != '') $columnList .= ', '; + + $columnList .= $this->getSelectJoinColumnSQL( + $tableAlias, + $srcColumn, + isset($assoc2['inherited']) ? $assoc2['inherited'] : $this->_class->name + ); + } + } + } + + // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#_processSQLResult). + $discrColumn = $this->_class->discriminatorColumn['name']; + $tableAlias = ($this->_class->rootEntityName == $this->_class->name) ? $baseTableAlias : $this->_getSQLTableAlias($this->_class->rootEntityName); + $columnList .= ', ' . $tableAlias . '.' . $discrColumn; + + $resultColumnName = $this->_platform->getSQLResultCasing($discrColumn); + + $this->_rsm->setDiscriminatorColumn('r', $resultColumnName); + $this->_rsm->addMetaResult('r', $resultColumnName, $discrColumn); + } + + // INNER JOIN parent tables + $joinSql = ''; + + foreach ($this->_class->parentClasses as $parentClassName) { + $parentClass = $this->_em->getClassMetadata($parentClassName); + $tableAlias = $this->_getSQLTableAlias($parentClassName); + $joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->_platform) . ' ' . $tableAlias . ' ON '; + $first = true; + + foreach ($idColumns as $idColumn) { + if ($first) $first = false; else $joinSql .= ' AND '; + + $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn; + } + } + + // OUTER JOIN sub tables + foreach ($this->_class->subClasses as $subClassName) { + $subClass = $this->_em->getClassMetadata($subClassName); + $tableAlias = $this->_getSQLTableAlias($subClassName); + + if ($this->_selectColumnListSql === null) { + // Add subclass columns + foreach ($subClass->fieldMappings as $fieldName => $mapping) { + if (isset($mapping['inherited'])) continue; + + $columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass); + } + + // Add join columns (foreign keys) + foreach ($subClass->associationMappings as $assoc2) { + if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE && ! isset($assoc2['inherited'])) { + foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) { + if ($columnList != '') $columnList .= ', '; + + $columnList .= $this->getSelectJoinColumnSQL( + $tableAlias, + $srcColumn, + isset($assoc2['inherited']) ? $assoc2['inherited'] : $subClass->name + ); + } + } + } + } + + // Add LEFT JOIN + $joinSql .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->_platform) . ' ' . $tableAlias . ' ON '; + $first = true; + + foreach ($idColumns as $idColumn) { + if ($first) $first = false; else $joinSql .= ' AND '; + + $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn; + } + } + + $joinSql .= ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) ? $this->_getSelectManyToManyJoinSQL($assoc) : ''; + + $conditionSql = ($criteria instanceof Criteria) + ? $this->_getSelectConditionCriteriaSQL($criteria) + : $this->_getSelectConditionSQL($criteria, $assoc); + + // If the current class in the root entity, add the filters + if ($filterSql = $this->generateFilterConditionSQL($this->_em->getClassMetadata($this->_class->rootEntityName), $this->_getSQLTableAlias($this->_class->rootEntityName))) { + if ($conditionSql) { + $conditionSql .= ' AND '; + } + + $conditionSql .= $filterSql; + } + + $orderBy = ($assoc !== null && isset($assoc['orderBy'])) ? $assoc['orderBy'] : $orderBy; + $orderBySql = $orderBy ? $this->_getOrderBySQL($orderBy, $baseTableAlias) : ''; + + if ($this->_selectColumnListSql === null) { + $this->_selectColumnListSql = $columnList; + } + + $lockSql = ''; + + if ($lockMode == LockMode::PESSIMISTIC_READ) { + $lockSql = ' ' . $this->_platform->getReadLockSql(); + } else if ($lockMode == LockMode::PESSIMISTIC_WRITE) { + $lockSql = ' ' . $this->_platform->getWriteLockSql(); + } + + return $this->_platform->modifyLimitQuery('SELECT ' . $this->_selectColumnListSql + . ' FROM ' . $this->quoteStrategy->getTableName($this->_class, $this->_platform) . ' ' . $baseTableAlias + . $joinSql + . ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql, $limit, $offset) + . $lockSql; + } + + /** + * Get the FROM and optionally JOIN conditions to lock the entity managed by this persister. + * + * @return string + */ + public function getLockTablesSql() + { + $idColumns = $this->_class->getIdentifierColumnNames(); + $baseTableAlias = $this->_getSQLTableAlias($this->_class->name); + + // INNER JOIN parent tables + $joinSql = ''; + + foreach ($this->_class->parentClasses as $parentClassName) { + $parentClass = $this->_em->getClassMetadata($parentClassName); + $tableAlias = $this->_getSQLTableAlias($parentClassName); + $joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->_platform) . ' ' . $tableAlias . ' ON '; + $first = true; + + foreach ($idColumns as $idColumn) { + if ($first) $first = false; else $joinSql .= ' AND '; + + $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn; + } + } + + return 'FROM ' .$this->quoteStrategy->getTableName($this->_class, $this->_platform) . ' ' . $baseTableAlias . $joinSql; + } + + /* Ensure this method is never called. This persister overrides _getSelectEntitiesSQL directly. */ + protected function _getSelectColumnListSQL() + { + throw new \BadMethodCallException("Illegal invocation of ".__METHOD__."."); + } + + /** {@inheritdoc} */ + protected function _getInsertColumnList() + { + // Identifier columns must always come first in the column list of subclasses. + $columns = $this->_class->parentClasses ? $this->_class->getIdentifierColumnNames() : array(); + + foreach ($this->_class->reflFields as $name => $field) { + if (isset($this->_class->fieldMappings[$name]['inherited']) && ! isset($this->_class->fieldMappings[$name]['id']) + || isset($this->_class->associationMappings[$name]['inherited']) + || ($this->_class->isVersioned && $this->_class->versionField == $name)) { + continue; + } + + if (isset($this->_class->associationMappings[$name])) { + $assoc = $this->_class->associationMappings[$name]; + if ($assoc['type'] & ClassMetadata::TO_ONE && $assoc['isOwningSide']) { + foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) { + $columns[] = $sourceCol; + } + } + } else if ($this->_class->name != $this->_class->rootEntityName || + ! $this->_class->isIdGeneratorIdentity() || $this->_class->identifier[0] != $name) { + $columns[] = $this->quoteStrategy->getColumnName($name, $this->_class, $this->_platform); + } + } + + // Add discriminator column if it is the topmost class. + if ($this->_class->name == $this->_class->rootEntityName) { + $columns[] = $this->_class->discriminatorColumn['name']; + } + + return $columns; + } + + /** + * {@inheritdoc} + */ + protected function assignDefaultVersionValue($entity, $id) + { + $value = $this->fetchVersionValue($this->_getVersionedClassMetadata(), $id); + $this->_class->setFieldValue($entity, $this->_class->versionField, $value); + } + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php new file mode 100644 index 0000000..3f0f1f8 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php @@ -0,0 +1,446 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\PersistentCollection, + Doctrine\ORM\UnitOfWork; + +/** + * Persister for many-to-many collections. + * + * @author Roman Borschel + * @author Guilherme Blanco + * @author Alexander + * @since 2.0 + */ +class ManyToManyPersister extends AbstractCollectionPersister +{ + /** + * {@inheritdoc} + * + * @override + */ + protected function _getDeleteRowSQL(PersistentCollection $coll) + { + $columns = array(); + $mapping = $coll->getMapping(); + $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); + + foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + } + + foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + } + + return 'DELETE FROM ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) + . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; + } + + /** + * {@inheritdoc} + * + * @override + * @internal Order of the parameters must be the same as the order of the columns in + * _getDeleteRowSql. + */ + protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element) + { + return $this->_collectJoinTableColumnParameters($coll, $element); + } + + /** + * {@inheritdoc} + * + * @override + */ + protected function _getUpdateRowSQL(PersistentCollection $coll) + {} + + /** + * {@inheritdoc} + * + * @override + * @internal Order of the parameters must be the same as the order of the columns in + * _getInsertRowSql. + */ + protected function _getInsertRowSQL(PersistentCollection $coll) + { + $columns = array(); + $mapping = $coll->getMapping(); + $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); + $joinTable = $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform); + + foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + } + + foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + } + + return 'INSERT INTO ' . $joinTable . ' (' . implode(', ', $columns) . ')' + . ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')'; + } + + /** + * {@inheritdoc} + * + * @override + * @internal Order of the parameters must be the same as the order of the columns in + * _getInsertRowSql. + */ + protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element) + { + return $this->_collectJoinTableColumnParameters($coll, $element); + } + + /** + * Collects the parameters for inserting/deleting on the join table in the order + * of the join table columns as specified in ManyToManyMapping#joinTableColumns. + * + * @param $coll + * @param $element + * @return array + */ + private function _collectJoinTableColumnParameters(PersistentCollection $coll, $element) + { + $params = array(); + $mapping = $coll->getMapping(); + $isComposite = count($mapping['joinTableColumns']) > 2; + + $identifier1 = $this->_uow->getEntityIdentifier($coll->getOwner()); + $identifier2 = $this->_uow->getEntityIdentifier($element); + + if ($isComposite) { + $class1 = $this->_em->getClassMetadata(get_class($coll->getOwner())); + $class2 = $coll->getTypeClass(); + } + + foreach ($mapping['joinTableColumns'] as $joinTableColumn) { + $isRelationToSource = isset($mapping['relationToSourceKeyColumns'][$joinTableColumn]); + + if ( ! $isComposite) { + $params[] = $isRelationToSource ? array_pop($identifier1) : array_pop($identifier2); + + continue; + } + + if ($isRelationToSource) { + $params[] = $identifier1[$class1->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])]; + + continue; + } + + $params[] = $identifier2[$class2->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]; + } + + return $params; + } + + /** + * {@inheritdoc} + * + * @override + */ + protected function _getDeleteSQL(PersistentCollection $coll) + { + $columns = array(); + $mapping = $coll->getMapping(); + $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); + $joinTable = $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform); + + foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + } + + return 'DELETE FROM ' . $joinTable + . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; + } + + /** + * {@inheritdoc} + * + * @override + * @internal Order of the parameters must be the same as the order of the columns in + * _getDeleteSql. + */ + protected function _getDeleteSQLParameters(PersistentCollection $coll) + { + $identifier = $this->_uow->getEntityIdentifier($coll->getOwner()); + $mapping = $coll->getMapping(); + $params = array(); + + // Optimization for single column identifier + if (count($mapping['relationToSourceKeyColumns']) === 1) { + $params[] = array_pop($identifier); + + return $params; + } + + // Composite identifier + $sourceClass = $this->_em->getClassMetadata(get_class($coll->getOwner())); + + foreach ($mapping['relationToSourceKeyColumns'] as $srcColumn) { + $params[] = $identifier[$sourceClass->fieldNames[$srcColumn]]; + } + + return $params; + } + + /** + * {@inheritdoc} + */ + public function count(PersistentCollection $coll) + { + $conditions = array(); + $params = array(); + $mapping = $coll->getMapping(); + $association = $mapping; + $class = $this->_em->getClassMetadata($mapping['sourceEntity']); + $id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner()); + + if ( ! $mapping['isOwningSide']) { + $targetEntity = $this->_em->getClassMetadata($mapping['targetEntity']); + $association = $targetEntity->associationMappings[$mapping['mappedBy']]; + } + + $joinColumns = ( ! $mapping['isOwningSide']) + ? $association['joinTable']['inverseJoinColumns'] + : $association['joinTable']['joinColumns']; + + foreach ($joinColumns as $joinColumn) { + $columnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + $referencedName = $joinColumn['referencedColumnName']; + $conditions[] = $columnName . ' = ?'; + $params[] = ($class->containsForeignIdentifier) + ? $id[$class->getFieldForColumn($referencedName)] + : $id[$class->fieldNames[$referencedName]]; + } + + $joinTableName = $this->quoteStrategy->getJoinTableName($association, $class, $this->platform); + list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping); + + if ($filterSql) { + $conditions[] = $filterSql; + } + + $sql = 'SELECT COUNT(*)' + . ' FROM ' . $joinTableName . ' t' + . $joinTargetEntitySQL + . ' WHERE ' . implode(' AND ', $conditions); + + return $this->_conn->fetchColumn($sql, $params); + } + + /** + * @param PersistentCollection $coll + * @param int $offset + * @param int $length + * @return array + */ + public function slice(PersistentCollection $coll, $offset, $length = null) + { + $mapping = $coll->getMapping(); + + return $this->_em->getUnitOfWork()->getEntityPersister($mapping['targetEntity'])->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length); + } + + /** + * @param PersistentCollection $coll + * @param object $element + * @return boolean + */ + public function contains(PersistentCollection $coll, $element) + { + $uow = $this->_em->getUnitOfWork(); + + // Shortcut for new entities + $entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW); + + if ($entityState === UnitOfWork::STATE_NEW) { + return false; + } + + // Entity is scheduled for inclusion + if ($entityState === UnitOfWork::STATE_MANAGED && $uow->isScheduledForInsert($element)) { + return false; + } + + list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, $element, true); + + $sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); + + return (bool) $this->_conn->fetchColumn($sql, $params); + } + + /** + * @param PersistentCollection $coll + * @param object $element + * @return boolean + */ + public function removeElement(PersistentCollection $coll, $element) + { + $uow = $this->_em->getUnitOfWork(); + + // shortcut for new entities + $entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW); + + if ($entityState === UnitOfWork::STATE_NEW) { + return false; + } + + // If Entity is scheduled for inclusion, it is not in this collection. + // We can assure that because it would have return true before on array check + if ($entityState === UnitOfWork::STATE_MANAGED && $uow->isScheduledForInsert($element)) { + return false; + } + + list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, $element, false); + + $sql = 'DELETE FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); + + return (bool) $this->_conn->executeUpdate($sql, $params); + } + + /** + * @param \Doctrine\ORM\PersistentCollection $coll + * @param object $element + * @param boolean $addFilters Whether the filter SQL should be included or not. + * @return array + */ + private function getJoinTableRestrictions(PersistentCollection $coll, $element, $addFilters) + { + $uow = $this->_em->getUnitOfWork(); + $mapping = $filterMapping = $coll->getMapping(); + + if ( ! $mapping['isOwningSide']) { + $sourceClass = $this->_em->getClassMetadata($mapping['targetEntity']); + $targetClass = $this->_em->getClassMetadata($mapping['sourceEntity']); + $sourceId = $uow->getEntityIdentifier($element); + $targetId = $uow->getEntityIdentifier($coll->getOwner()); + + $mapping = $sourceClass->associationMappings[$mapping['mappedBy']]; + } else { + $sourceClass = $this->_em->getClassMetadata($mapping['sourceEntity']); + $targetClass = $this->_em->getClassMetadata($mapping['targetEntity']); + $sourceId = $uow->getEntityIdentifier($coll->getOwner()); + $targetId = $uow->getEntityIdentifier($element); + } + + $quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $sourceClass, $this->platform); + $whereClauses = array(); + $params = array(); + + foreach ($mapping['joinTableColumns'] as $joinTableColumn) { + $whereClauses[] = $joinTableColumn . ' = ?'; + + if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) { + $params[] = ($targetClass->containsForeignIdentifier) + ? $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])] + : $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]]; + continue; + } + + // relationToSourceKeyColumns + $params[] = ($sourceClass->containsForeignIdentifier) + ? $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])] + : $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]]; + } + + if ($addFilters) { + list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping); + if ($filterSql) { + $quotedJoinTable .= ' t ' . $joinTargetEntitySQL; + $whereClauses[] = $filterSql; + } + } + + return array($quotedJoinTable, $whereClauses, $params); + } + + /** + * Generates the filter SQL for a given mapping. + * + * This method is not used for actually grabbing the related entities + * but when the extra-lazy collection methods are called on a filtered + * association. This is why besides the many to many table we also + * have to join in the actual entities table leading to additional + * JOIN. + * + * @param array $mapping Array containing mapping information. + * + * @return string The SQL query part to add to a query. + */ + public function getFilterSql($mapping) + { + $targetClass = $this->_em->getClassMetadata($mapping['targetEntity']); + + if ($mapping['isOwningSide']) { + $joinColumns = $mapping['relationToTargetKeyColumns']; + } else { + $mapping = $targetClass->associationMappings[$mapping['mappedBy']]; + $joinColumns = $mapping['relationToSourceKeyColumns']; + } + + $targetClass = $this->_em->getClassMetadata($targetClass->rootEntityName); + + // A join is needed if there is filtering on the target entity + $joinTargetEntitySQL = ''; + if ($filterSql = $this->generateFilterConditionSQL($targetClass, 'te')) { + $joinTargetEntitySQL = ' JOIN ' + . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' te' + . ' ON'; + + $joinTargetEntitySQLClauses = array(); + foreach ($joinColumns as $joinTableColumn => $targetTableColumn) { + $joinTargetEntitySQLClauses[] = ' t.' . $joinTableColumn . ' = ' . 'te.' . $targetTableColumn; + } + + $joinTargetEntitySQL .= implode(' AND ', $joinTargetEntitySQLClauses); + } + + return array($joinTargetEntitySQL, $filterSql); + } + + /** + * Generates the filter SQL for a given entity and table alias. + * + * @param ClassMetadata $targetEntity Metadata of the target entity. + * @param string $targetTableAlias The table alias of the joined/selected table. + * + * @return string The SQL query part to add to a query. + */ + protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) + { + $filterClauses = array(); + + foreach ($this->_em->getFilters()->getEnabledFilters() as $filter) { + if ($filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) { + $filterClauses[] = '(' . $filterExpr . ')'; + } + } + + $sql = implode(' AND ', $filterClauses); + return $sql ? "(" . $sql . ")" : ""; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/OneToManyPersister.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/OneToManyPersister.php new file mode 100644 index 0000000..aa0208f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/OneToManyPersister.php @@ -0,0 +1,212 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use Doctrine\ORM\PersistentCollection, + Doctrine\ORM\UnitOfWork; + +/** + * Persister for one-to-many collections. + * + * @author Roman Borschel + * @author Guilherme Blanco + * @author Alexander + * @since 2.0 + */ +class OneToManyPersister extends AbstractCollectionPersister +{ + /** + * Generates the SQL UPDATE that updates a particular row's foreign + * key to null. + * + * @param PersistentCollection $coll + * @return string + * @override + */ + protected function _getDeleteRowSQL(PersistentCollection $coll) + { + $mapping = $coll->getMapping(); + $class = $this->_em->getClassMetadata($mapping['targetEntity']); + + return 'DELETE FROM ' . $this->quoteStrategy->getTableName($class, $this->platform) + . ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?'; + } + + /** + * {@inheritdoc} + * + */ + protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element) + { + return array_values($this->_uow->getEntityIdentifier($element)); + } + + protected function _getInsertRowSQL(PersistentCollection $coll) + { + return "UPDATE xxx SET foreign_key = yyy WHERE foreign_key = zzz"; + } + + /** + * Gets the SQL parameters for the corresponding SQL statement to insert the given + * element of the given collection into the database. + * + * @param PersistentCollection $coll + * @param mixed $element + */ + protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element) + {} + + /* Not used for OneToManyPersister */ + protected function _getUpdateRowSQL(PersistentCollection $coll) + { + return; + } + + /** + * Generates the SQL UPDATE that updates all the foreign keys to null. + * + * @param PersistentCollection $coll + */ + protected function _getDeleteSQL(PersistentCollection $coll) + { + + } + + /** + * Gets the SQL parameters for the corresponding SQL statement to delete + * the given collection. + * + * @param PersistentCollection $coll + */ + protected function _getDeleteSQLParameters(PersistentCollection $coll) + {} + + /** + * {@inheritdoc} + */ + public function count(PersistentCollection $coll) + { + $mapping = $coll->getMapping(); + $targetClass = $this->_em->getClassMetadata($mapping['targetEntity']); + $sourceClass = $this->_em->getClassMetadata($mapping['sourceEntity']); + $id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner()); + + $whereClauses = array(); + $params = array(); + + foreach ($targetClass->associationMappings[$mapping['mappedBy']]['joinColumns'] as $joinColumn) { + $whereClauses[] = $joinColumn['name'] . ' = ?'; + + $params[] = ($targetClass->containsForeignIdentifier) + ? $id[$sourceClass->getFieldForColumn($joinColumn['referencedColumnName'])] + : $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]]; + } + + $filterTargetClass = $this->_em->getClassMetadata($targetClass->rootEntityName); + foreach ($this->_em->getFilters()->getEnabledFilters() as $filter) { + if ($filterExpr = $filter->addFilterConstraint($filterTargetClass, 't')) { + $whereClauses[] = '(' . $filterExpr . ')'; + } + } + + $sql = 'SELECT count(*)' + . ' FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' t' + . ' WHERE ' . implode(' AND ', $whereClauses); + + return $this->_conn->fetchColumn($sql, $params); + } + + /** + * @param PersistentCollection $coll + * @param int $offset + * @param int $length + * @return \Doctrine\Common\Collections\ArrayCollection + */ + public function slice(PersistentCollection $coll, $offset, $length = null) + { + $mapping = $coll->getMapping(); + $uow = $this->_em->getUnitOfWork(); + $persister = $uow->getEntityPersister($mapping['targetEntity']); + + return $persister->getOneToManyCollection($mapping, $coll->getOwner(), $offset, $length); + } + + /** + * @param PersistentCollection $coll + * @param object $element + * @return boolean + */ + public function contains(PersistentCollection $coll, $element) + { + $mapping = $coll->getMapping(); + $uow = $this->_em->getUnitOfWork(); + + // shortcut for new entities + $entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW); + + if ($entityState === UnitOfWork::STATE_NEW) { + return false; + } + + // Entity is scheduled for inclusion + if ($entityState === UnitOfWork::STATE_MANAGED && $uow->isScheduledForInsert($element)) { + return false; + } + + $persister = $uow->getEntityPersister($mapping['targetEntity']); + + // only works with single id identifier entities. Will throw an + // exception in Entity Persisters if that is not the case for the + // 'mappedBy' field. + $id = current( $uow->getEntityIdentifier($coll->getOwner())); + + return $persister->exists($element, array($mapping['mappedBy'] => $id)); + } + + /** + * @param PersistentCollection $coll + * @param object $element + * @return boolean + */ + public function removeElement(PersistentCollection $coll, $element) + { + $uow = $this->_em->getUnitOfWork(); + + // shortcut for new entities + $entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW); + + if ($entityState === UnitOfWork::STATE_NEW) { + return false; + } + + // If Entity is scheduled for inclusion, it is not in this collection. + // We can assure that because it would have return true before on array check + if ($entityState === UnitOfWork::STATE_MANAGED && $uow->isScheduledForInsert($element)) { + return false; + } + + $mapping = $coll->getMapping(); + $class = $this->_em->getClassMetadata($mapping['targetEntity']); + $sql = 'DELETE FROM ' . $this->quoteStrategy->getTableName($class, $this->platform) + . ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?'; + + return (bool) $this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element)); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SingleTablePersister.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SingleTablePersister.php new file mode 100644 index 0000000..9fedcaa --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SingleTablePersister.php @@ -0,0 +1,163 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\Common\Collections\Criteria; + +/** + * Persister for entities that participate in a hierarchy mapped with the + * SINGLE_TABLE strategy. + * + * @author Roman Borschel + * @author Benjamin Eberlei + * @author Alexander + * @since 2.0 + * @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html + */ +class SingleTablePersister extends AbstractEntityInheritancePersister +{ + /** {@inheritdoc} */ + protected function _getDiscriminatorColumnTableName() + { + return $this->_class->getTableName(); + } + + /** {@inheritdoc} */ + protected function _getSelectColumnListSQL() + { + if ($this->_selectColumnListSql !== null) { + return $this->_selectColumnListSql; + } + + $columnList = parent::_getSelectColumnListSQL(); + + $rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName); + $tableAlias = $this->_getSQLTableAlias($rootClass->name); + + // Append discriminator column + $discrColumn = $this->_class->discriminatorColumn['name']; + $columnList .= ', ' . $tableAlias . '.' . $discrColumn; + + $resultColumnName = $this->_platform->getSQLResultCasing($discrColumn); + + $this->_rsm->setDiscriminatorColumn('r', $resultColumnName); + $this->_rsm->addMetaResult('r', $resultColumnName, $discrColumn); + + // Append subclass columns + foreach ($this->_class->subClasses as $subClassName) { + $subClass = $this->_em->getClassMetadata($subClassName); + + // Regular columns + foreach ($subClass->fieldMappings as $fieldName => $mapping) { + if ( ! isset($mapping['inherited'])) { + $columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass); + } + } + + // Foreign key columns + foreach ($subClass->associationMappings as $assoc) { + if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE && ! isset($assoc['inherited'])) { + foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { + if ($columnList != '') $columnList .= ', '; + + $columnList .= $this->getSelectJoinColumnSQL( + $tableAlias, + $srcColumn, + isset($assoc['inherited']) ? $assoc['inherited'] : $this->_class->name + ); + } + } + } + } + + $this->_selectColumnListSql = $columnList; + return $this->_selectColumnListSql; + } + + /** {@inheritdoc} */ + protected function _getInsertColumnList() + { + $columns = parent::_getInsertColumnList(); + + // Add discriminator column to the INSERT SQL + $columns[] = $this->_class->discriminatorColumn['name']; + + return $columns; + } + + /** {@inheritdoc} */ + protected function _getSQLTableAlias($className, $assocName = '') + { + return parent::_getSQLTableAlias($this->_class->rootEntityName, $assocName); + } + + /** {@inheritdoc} */ + protected function _getSelectConditionSQL(array $criteria, $assoc = null) + { + $conditionSql = parent::_getSelectConditionSQL($criteria, $assoc); + + if ($conditionSql) { + $conditionSql .= ' AND '; + } + + return $conditionSql . $this->_getSelectConditionDiscriminatorValueSQL(); + } + + /** {@inheritdoc} */ + protected function _getSelectConditionCriteriaSQL(Criteria $criteria) + { + $conditionSql = parent::_getSelectConditionCriteriaSQL($criteria); + + if ($conditionSql) { + $conditionSql .= ' AND '; + } + + return $conditionSql . $this->_getSelectConditionDiscriminatorValueSQL(); + } + + protected function _getSelectConditionDiscriminatorValueSQL() + { + $values = array(); + + if ($this->_class->discriminatorValue !== null) { // discriminators can be 0 + $values[] = $this->_conn->quote($this->_class->discriminatorValue); + } + + $discrValues = array_flip($this->_class->discriminatorMap); + + foreach ($this->_class->subClasses as $subclassName) { + $values[] = $this->_conn->quote($discrValues[$subclassName]); + } + + return $this->_getSQLTableAlias($this->_class->name) . '.' . $this->_class->discriminatorColumn['name'] + . ' IN (' . implode(', ', $values) . ')'; + } + + /** {@inheritdoc} */ + protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) + { + // Ensure that the filters are applied to the root entity of the inheritance tree + $targetEntity = $this->_em->getClassMetadata($targetEntity->rootEntityName); + // we dont care about the $targetTableAlias, in a STI there is only one table. + + return parent::generateFilterConditionSQL($targetEntity, $targetTableAlias); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SqlExpressionVisitor.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SqlExpressionVisitor.php new file mode 100644 index 0000000..2fb685f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SqlExpressionVisitor.php @@ -0,0 +1,102 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use Doctrine\Common\Collections\Expr\ExpressionVisitor; +use Doctrine\Common\Collections\Expr\Comparison; +use Doctrine\Common\Collections\Expr\Value; +use Doctrine\Common\Collections\Expr\CompositeExpression; + +/** + * Visit Expressions and generate SQL WHERE conditions from them. + * + * @author Benjamin Eberlei + * @since 2.3 + */ +class SqlExpressionVisitor extends ExpressionVisitor +{ + /** + * @var \Doctrine\ORM\Persisters\BasicEntityPersister + */ + private $persister; + + /** + * @param \Doctrine\ORM\Persisters\BasicEntityPersister $persister + */ + public function __construct(BasicEntityPersister $persister) + { + $this->persister = $persister; + } + + /** + * Convert a comparison expression into the target query language output + * + * @param \Doctrine\Common\Collections\Expr\Comparison $comparison + * + * @return mixed + */ + public function walkComparison(Comparison $comparison) + { + $field = $comparison->getField(); + $value = $comparison->getValue()->getValue(); // shortcut for walkValue() + + return $this->persister->getSelectConditionStatementSQL($field, $value, null, $comparison->getOperator()); + } + + /** + * Convert a composite expression into the target query language output + * + * @param \Doctrine\Common\Collections\Expr\CompositeExpression $expr + * + * @return mixed + */ + public function walkCompositeExpression(CompositeExpression $expr) + { + $expressionList = array(); + + foreach ($expr->getExpressionList() as $child) { + $expressionList[] = $this->dispatch($child); + } + + switch($expr->getType()) { + case CompositeExpression::TYPE_AND: + return '(' . implode(' AND ', $expressionList) . ')'; + + case CompositeExpression::TYPE_OR: + return '(' . implode(' OR ', $expressionList) . ')'; + + default: + throw new \RuntimeException("Unknown composite " . $expr->getType()); + } + } + + /** + * Convert a value expression into the target query language part. + * + * @param \Doctrine\Common\Collections\Expr\Value $value + * + * @return mixed + */ + public function walkValue(Value $value) + { + return '?'; + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SqlValueVisitor.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SqlValueVisitor.php new file mode 100644 index 0000000..aa4d68d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/SqlValueVisitor.php @@ -0,0 +1,100 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use Doctrine\Common\Collections\Expr\ExpressionVisitor; +use Doctrine\Common\Collections\Expr\Comparison; +use Doctrine\Common\Collections\Expr\Value; +use Doctrine\Common\Collections\Expr\CompositeExpression; + +use Doctrine\ORM\Mapping\ClassMetadata; + +use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Connection; + +/** + * Extract the values from a criteria/expression + * + * @author Benjamin Eberlei + */ +class SqlValueVisitor extends ExpressionVisitor +{ + /** + * @var array + */ + private $values = array(); + + /** + * @var array + */ + private $types = array(); + + /** + * Convert a comparison expression into the target query language output + * + * @param \Doctrine\Common\Collections\Expr\Comparison $comparison + * + * @return mixed + */ + public function walkComparison(Comparison $comparison) + { + $value = $comparison->getValue()->getValue(); + $field = $comparison->getField(); + + $this->values[] = $value; + $this->types[] = array($field, $value); + } + + /** + * Convert a composite expression into the target query language output + * + * @param \Doctrine\Common\Collections\Expr\CompositeExpression $expr + * + * @return mixed + */ + public function walkCompositeExpression(CompositeExpression $expr) + { + foreach ($expr->getExpressionList() as $child) { + $this->dispatch($child); + } + } + + /** + * Convert a value expression into the target query language part. + * + * @param \Doctrine\Common\Collections\Expr\Value $value + * + * @return mixed + */ + public function walkValue(Value $value) + { + return; + } + + /** + * Return the Parameters and Types necessary for matching the last visited expression. + * + * @return array + */ + public function getParamsAndTypes() + { + return array($this->values, $this->types); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/UnionSubclassPersister.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/UnionSubclassPersister.php new file mode 100644 index 0000000..ef844a7 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/UnionSubclassPersister.php @@ -0,0 +1,8 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Pessimistic Lock Exception + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @author Benjamin Eberlei + * @author Roman Borschel + */ +class PessimisticLockException extends ORMException +{ + public static function lockFailed() + { + return new self("The pessimistic lock failed."); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Autoloader.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Autoloader.php new file mode 100644 index 0000000..0b4d9a0 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Autoloader.php @@ -0,0 +1,78 @@ +. + */ + +namespace Doctrine\ORM\Proxy; + +/** + * Special Autoloader for Proxy classes because them not being PSR-0 compatible. + * + * @author Benjamin Eberlei + */ +class Autoloader +{ + /** + * Resolve proxy class name to a filename based on the following pattern. + * + * 1. Remove Proxy namespace from class name + * 2. Remove namespace seperators from remaining class name. + * 3. Return PHP filename from proxy-dir with the result from 2. + * + * @param string $proxyDir + * @param string $proxyNamespace + * @param string $className + * @return string + */ + static public function resolveFile($proxyDir, $proxyNamespace, $className) + { + if (0 !== strpos($className, $proxyNamespace)) { + throw ProxyException::notProxyClass($className, $proxyNamespace); + } + + $className = str_replace('\\', '', substr($className, strlen($proxyNamespace) +1)); + return $proxyDir . DIRECTORY_SEPARATOR . $className.'.php'; + } + + /** + * Register and return autoloader callback for the given proxy dir and + * namespace. + * + * @param string $proxyDir + * @param string $proxyNamespace + * @param Closure $notFoundCallback Invoked when the proxy file is not found. + * @return Closure + */ + static public function register($proxyDir, $proxyNamespace, \Closure $notFoundCallback = null) + { + $proxyNamespace = ltrim($proxyNamespace, "\\"); + $autoloader = function($className) use ($proxyDir, $proxyNamespace, $notFoundCallback) { + if (0 === strpos($className, $proxyNamespace)) { + $file = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className); + + if ($notFoundCallback && ! file_exists($file)) { + $notFoundCallback($proxyDir, $proxyNamespace, $className); + } + + require $file; + } + }; + spl_autoload_register($autoloader); + return $autoloader; + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Proxy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Proxy.php new file mode 100644 index 0000000..47cda90 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/Proxy.php @@ -0,0 +1,30 @@ +. + */ + +namespace Doctrine\ORM\Proxy; + +use Doctrine\Common\Persistence\Proxy as BaseProxy; + +/** + * Interface for proxy classes. + * + * @author Roman Borschel + * @since 2.0 + */ +interface Proxy extends BaseProxy {} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyException.php new file mode 100644 index 0000000..4e26d86 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyException.php @@ -0,0 +1,52 @@ +. + */ + +namespace Doctrine\ORM\Proxy; + +/** + * ORM Proxy Exception + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @author Benjamin Eberlei + */ +class ProxyException extends \Doctrine\ORM\ORMException { + + public static function proxyDirectoryRequired() { + return new self("You must configure a proxy directory. See docs for details"); + } + + public static function proxyDirectoryNotWritable() { + return new self("Your proxy directory must be writable."); + } + + public static function proxyNamespaceRequired() { + return new self("You must configure a proxy namespace. See docs for details"); + } + + public static function notProxyClass($className, $proxyNamespace) + { + return new self(sprintf( + "The class %s is not part of the proxy namespace %s", + $className, $proxyNamespace + )); + } + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyFactory.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyFactory.php new file mode 100644 index 0000000..df74207 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyFactory.php @@ -0,0 +1,410 @@ +. + */ + +namespace Doctrine\ORM\Proxy; + +use Doctrine\ORM\EntityManager, + Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\Common\Util\ClassUtils; + +/** + * This factory is used to create proxy objects for entities at runtime. + * + * @author Roman Borschel + * @author Giorgio Sironi + * @since 2.0 + */ +class ProxyFactory +{ + /** The EntityManager this factory is bound to. */ + private $_em; + /** Whether to automatically (re)generate proxy classes. */ + private $_autoGenerate; + /** The namespace that contains all proxy classes. */ + private $_proxyNamespace; + /** The directory that contains all proxy classes. */ + private $_proxyDir; + + /** + * Used to match very simple id methods that don't need + * to be proxied since the identifier is known. + * + * @var string + */ + const PATTERN_MATCH_ID_METHOD = '((public\s)?(function\s{1,}%s\s?\(\)\s{1,})\s{0,}{\s{0,}return\s{0,}\$this->%s;\s{0,}})i'; + + /** + * Initializes a new instance of the ProxyFactory class that is + * connected to the given EntityManager. + * + * @param EntityManager $em The EntityManager the new factory works for. + * @param string $proxyDir The directory to use for the proxy classes. It must exist. + * @param string $proxyNs The namespace to use for the proxy classes. + * @param boolean $autoGenerate Whether to automatically generate proxy classes. + */ + public function __construct(EntityManager $em, $proxyDir, $proxyNs, $autoGenerate = false) + { + if ( ! $proxyDir) { + throw ProxyException::proxyDirectoryRequired(); + } + if ( ! $proxyNs) { + throw ProxyException::proxyNamespaceRequired(); + } + $this->_em = $em; + $this->_proxyDir = $proxyDir; + $this->_autoGenerate = $autoGenerate; + $this->_proxyNamespace = $proxyNs; + } + + /** + * Gets a reference proxy instance for the entity of the given type and identified by + * the given identifier. + * + * @param string $className + * @param mixed $identifier + * @return object + */ + public function getProxy($className, $identifier) + { + $fqn = ClassUtils::generateProxyClassName($className, $this->_proxyNamespace); + + if (! class_exists($fqn, false)) { + $fileName = $this->getProxyFileName($className); + if ($this->_autoGenerate) { + $this->_generateProxyClass($this->_em->getClassMetadata($className), $fileName, self::$_proxyClassTemplate); + } + require $fileName; + } + + $entityPersister = $this->_em->getUnitOfWork()->getEntityPersister($className); + + return new $fqn($entityPersister, $identifier); + } + + /** + * Generate the Proxy file name + * + * @param string $className + * @param string $baseDir Optional base directory for proxy file name generation. + * If not specified, the directory configured on the Configuration of the + * EntityManager will be used by this factory. + * @return string + */ + private function getProxyFileName($className, $baseDir = null) + { + $proxyDir = $baseDir ?: $this->_proxyDir; + + return $proxyDir . DIRECTORY_SEPARATOR . '__CG__' . str_replace('\\', '', $className) . '.php'; + } + + /** + * Generates proxy classes for all given classes. + * + * @param array $classes The classes (ClassMetadata instances) for which to generate proxies. + * @param string $toDir The target directory of the proxy classes. If not specified, the + * directory configured on the Configuration of the EntityManager used + * by this factory is used. + * @return int Number of generated proxies. + */ + public function generateProxyClasses(array $classes, $toDir = null) + { + $proxyDir = $toDir ?: $this->_proxyDir; + $proxyDir = rtrim($proxyDir, DIRECTORY_SEPARATOR); + $num = 0; + + foreach ($classes as $class) { + /* @var $class ClassMetadata */ + if ($class->isMappedSuperclass || $class->reflClass->isAbstract()) { + continue; + } + + $proxyFileName = $this->getProxyFileName($class->name, $proxyDir); + + $this->_generateProxyClass($class, $proxyFileName, self::$_proxyClassTemplate); + $num++; + } + + return $num; + } + + /** + * Generates a proxy class file. + * + * @param ClassMetadata $class Metadata for the original class + * @param string $fileName Filename (full path) for the generated class + * @param string $file The proxy class template data + */ + private function _generateProxyClass(ClassMetadata $class, $fileName, $file) + { + $methods = $this->_generateMethods($class); + $sleepImpl = $this->_generateSleep($class); + $cloneImpl = $class->reflClass->hasMethod('__clone') ? 'parent::__clone();' : ''; // hasMethod() checks case-insensitive + + $placeholders = array( + '', + '', '', + '', '', '' + ); + + $className = ltrim($class->name, '\\'); + $proxyClassName = ClassUtils::generateProxyClassName($class->name, $this->_proxyNamespace); + $parts = explode('\\', strrev($proxyClassName), 2); + $proxyClassNamespace = strrev($parts[1]); + $proxyClassName = strrev($parts[0]); + + $replacements = array( + $proxyClassNamespace, + $proxyClassName, + $className, + $methods, + $sleepImpl, + $cloneImpl + ); + + $file = str_replace($placeholders, $replacements, $file); + + $parentDirectory = dirname($fileName); + + if ( ! is_dir($parentDirectory)) { + if (false === @mkdir($parentDirectory, 0775, true)) { + throw ProxyException::proxyDirectoryNotWritable(); + } + } else if ( ! is_writable($parentDirectory)) { + throw ProxyException::proxyDirectoryNotWritable(); + } + + $tmpFileName = $fileName . '.' . uniqid("", true); + file_put_contents($tmpFileName, $file); + rename($tmpFileName, $fileName); + } + + /** + * Generates the methods of a proxy class. + * + * @param ClassMetadata $class + * @return string The code of the generated methods. + */ + private function _generateMethods(ClassMetadata $class) + { + $methods = ''; + + $methodNames = array(); + foreach ($class->reflClass->getMethods() as $method) { + /* @var $method ReflectionMethod */ + if ($method->isConstructor() || in_array(strtolower($method->getName()), array("__sleep", "__clone")) || isset($methodNames[$method->getName()])) { + continue; + } + $methodNames[$method->getName()] = true; + + if ($method->isPublic() && ! $method->isFinal() && ! $method->isStatic()) { + $methods .= "\n" . ' public function '; + if ($method->returnsReference()) { + $methods .= '&'; + } + $methods .= $method->getName() . '('; + $firstParam = true; + $parameterString = $argumentString = ''; + + foreach ($method->getParameters() as $param) { + if ($firstParam) { + $firstParam = false; + } else { + $parameterString .= ', '; + $argumentString .= ', '; + } + + // We need to pick the type hint class too + if (($paramClass = $param->getClass()) !== null) { + $parameterString .= '\\' . $paramClass->getName() . ' '; + } else if ($param->isArray()) { + $parameterString .= 'array '; + } + + if ($param->isPassedByReference()) { + $parameterString .= '&'; + } + + $parameterString .= '$' . $param->getName(); + $argumentString .= '$' . $param->getName(); + + if ($param->isDefaultValueAvailable()) { + $parameterString .= ' = ' . var_export($param->getDefaultValue(), true); + } + } + + $methods .= $parameterString . ')'; + $methods .= "\n" . ' {' . "\n"; + if ($this->isShortIdentifierGetter($method, $class)) { + $identifier = lcfirst(substr($method->getName(), 3)); + + $cast = in_array($class->fieldMappings[$identifier]['type'], array('integer', 'smallint')) ? '(int) ' : ''; + + $methods .= ' if ($this->__isInitialized__ === false) {' . "\n"; + $methods .= ' return ' . $cast . '$this->_identifier["' . $identifier . '"];' . "\n"; + $methods .= ' }' . "\n"; + } + $methods .= ' $this->__load();' . "\n"; + $methods .= ' return parent::' . $method->getName() . '(' . $argumentString . ');'; + $methods .= "\n" . ' }' . "\n"; + } + } + + return $methods; + } + + /** + * Check if the method is a short identifier getter. + * + * What does this mean? For proxy objects the identifier is already known, + * however accessing the getter for this identifier usually triggers the + * lazy loading, leading to a query that may not be necessary if only the + * ID is interesting for the userland code (for example in views that + * generate links to the entity, but do not display anything else). + * + * @param ReflectionMethod $method + * @param ClassMetadata $class + * @return bool + */ + private function isShortIdentifierGetter($method, ClassMetadata $class) + { + $identifier = lcfirst(substr($method->getName(), 3)); + $cheapCheck = ( + $method->getNumberOfParameters() == 0 && + substr($method->getName(), 0, 3) == "get" && + in_array($identifier, $class->identifier, true) && + $class->hasField($identifier) && + (($method->getEndLine() - $method->getStartLine()) <= 4) + && in_array($class->fieldMappings[$identifier]['type'], array('integer', 'bigint', 'smallint', 'string')) + ); + + if ($cheapCheck) { + $code = file($method->getDeclaringClass()->getFileName()); + $code = trim(implode(" ", array_slice($code, $method->getStartLine() - 1, $method->getEndLine() - $method->getStartLine() + 1))); + + $pattern = sprintf(self::PATTERN_MATCH_ID_METHOD, $method->getName(), $identifier); + + if (preg_match($pattern, $code)) { + return true; + } + } + return false; + } + + /** + * Generates the code for the __sleep method for a proxy class. + * + * @param $class + * @return string + */ + private function _generateSleep(ClassMetadata $class) + { + $sleepImpl = ''; + + if ($class->reflClass->hasMethod('__sleep')) { + $sleepImpl .= "return array_merge(array('__isInitialized__'), parent::__sleep());"; + } else { + $sleepImpl .= "return array('__isInitialized__', "; + $first = true; + + foreach ($class->getReflectionProperties() as $name => $prop) { + if ($first) { + $first = false; + } else { + $sleepImpl .= ', '; + } + + $sleepImpl .= "'" . $name . "'"; + } + + $sleepImpl .= ');'; + } + + return $sleepImpl; + } + + /** Proxy class code template */ + private static $_proxyClassTemplate = +'; + +/** + * THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE. + */ +class extends \ implements \Doctrine\ORM\Proxy\Proxy +{ + private $_entityPersister; + private $_identifier; + public $__isInitialized__ = false; + public function __construct($entityPersister, $identifier) + { + $this->_entityPersister = $entityPersister; + $this->_identifier = $identifier; + } + /** @private */ + public function __load() + { + if (!$this->__isInitialized__ && $this->_entityPersister) { + $this->__isInitialized__ = true; + + if (method_exists($this, "__wakeup")) { + // call this after __isInitialized__to avoid infinite recursion + // but before loading to emulate what ClassMetadata::newInstance() + // provides. + $this->__wakeup(); + } + + if ($this->_entityPersister->load($this->_identifier, $this) === null) { + throw new \Doctrine\ORM\EntityNotFoundException(); + } + unset($this->_entityPersister, $this->_identifier); + } + } + + /** @private */ + public function __isInitialized() + { + return $this->__isInitialized__; + } + + + + public function __sleep() + { + + } + + public function __clone() + { + if (!$this->__isInitialized__ && $this->_entityPersister) { + $this->__isInitialized__ = true; + $class = $this->_entityPersister->getClassMetadata(); + $original = $this->_entityPersister->load($this->_identifier); + if ($original === null) { + throw new \Doctrine\ORM\EntityNotFoundException(); + } + foreach ($class->reflFields as $field => $reflProperty) { + $reflProperty->setValue($this, $reflProperty->getValue($original)); + } + unset($this->_entityPersister, $this->_identifier); + } + + } +}'; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query.php new file mode 100644 index 0000000..2e1b817 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query.php @@ -0,0 +1,626 @@ +. + */ + +namespace Doctrine\ORM; + +use Doctrine\Common\Collections\ArrayCollection; + +use Doctrine\DBAL\LockMode; + +use Doctrine\ORM\Query\Parser; +use Doctrine\ORM\Query\ParserResult; +use Doctrine\ORM\Query\QueryException; + +/** + * A Query object represents a DQL query. + * + * @since 1.0 + * @author Guilherme Blanco + * @author Konsta Vesterinen + * @author Roman Borschel + */ +final class Query extends AbstractQuery +{ + /** + * A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts. + */ + const STATE_CLEAN = 1; + /** + * A query object is in state DIRTY when it has DQL parts that have not yet been + * parsed/processed. This is automatically defined as DIRTY when addDqlQueryPart + * is called. + */ + const STATE_DIRTY = 2; + + /* Query HINTS */ + /** + * The refresh hint turns any query into a refresh query with the result that + * any local changes in entities are overridden with the fetched values. + * + * @var string + */ + const HINT_REFRESH = 'doctrine.refresh'; + + + /** + * Internal hint: is set to the proxy entity that is currently triggered for loading + * + * @var string + */ + const HINT_REFRESH_ENTITY = 'doctrine.refresh.entity'; + + /** + * The forcePartialLoad query hint forces a particular query to return + * partial objects. + * + * @var string + * @todo Rename: HINT_OPTIMIZE + */ + const HINT_FORCE_PARTIAL_LOAD = 'doctrine.forcePartialLoad'; + /** + * The includeMetaColumns query hint causes meta columns like foreign keys and + * discriminator columns to be selected and returned as part of the query result. + * + * This hint does only apply to non-object queries. + * + * @var string + */ + const HINT_INCLUDE_META_COLUMNS = 'doctrine.includeMetaColumns'; + + /** + * An array of class names that implement \Doctrine\ORM\Query\TreeWalker and + * are iterated and executed after the DQL has been parsed into an AST. + * + * @var string + */ + const HINT_CUSTOM_TREE_WALKERS = 'doctrine.customTreeWalkers'; + + /** + * A string with a class name that implements \Doctrine\ORM\Query\TreeWalker + * and is used for generating the target SQL from any DQL AST tree. + * + * @var string + */ + const HINT_CUSTOM_OUTPUT_WALKER = 'doctrine.customOutputWalker'; + + //const HINT_READ_ONLY = 'doctrine.readOnly'; + + /** + * @var string + */ + const HINT_INTERNAL_ITERATION = 'doctrine.internal.iteration'; + + /** + * @var string + */ + const HINT_LOCK_MODE = 'doctrine.lockMode'; + + + /** + * @var integer $_state The current state of this query. + */ + private $_state = self::STATE_CLEAN; + + /** + * @var string $_dql Cached DQL query. + */ + private $_dql = null; + + /** + * @var \Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information. + */ + private $_parserResult; + + /** + * @var integer The first result to return (the "offset"). + */ + private $_firstResult = null; + + /** + * @var integer The maximum number of results to return (the "limit"). + */ + private $_maxResults = null; + + /** + * @var CacheDriver The cache driver used for caching queries. + */ + private $_queryCache; + + /** + * @var boolean Boolean value that indicates whether or not expire the query cache. + */ + private $_expireQueryCache = false; + + /** + * @var int Query Cache lifetime. + */ + private $_queryCacheTTL; + + /** + * @var boolean Whether to use a query cache, if available. Defaults to TRUE. + */ + private $_useQueryCache = true; + + /** + * Initializes a new Query instance. + * + * @param \Doctrine\ORM\EntityManager $entityManager + */ + /*public function __construct(EntityManager $entityManager) + { + parent::__construct($entityManager); + }*/ + + /** + * Gets the SQL query/queries that correspond to this DQL query. + * + * @return mixed The built sql query or an array of all sql queries. + * @override + */ + public function getSQL() + { + return $this->_parse()->getSQLExecutor()->getSQLStatements(); + } + + /** + * Returns the corresponding AST for this DQL query. + * + * @return \Doctrine\ORM\Query\AST\SelectStatement | + * \Doctrine\ORM\Query\AST\UpdateStatement | + * \Doctrine\ORM\Query\AST\DeleteStatement + */ + public function getAST() + { + $parser = new Parser($this); + + return $parser->getAST(); + } + + /** + * Parses the DQL query, if necessary, and stores the parser result. + * + * Note: Populates $this->_parserResult as a side-effect. + * + * @return \Doctrine\ORM\Query\ParserResult + */ + private function _parse() + { + // Return previous parser result if the query and the filter collection are both clean + if ($this->_state === self::STATE_CLEAN && $this->_em->isFiltersStateClean()) { + return $this->_parserResult; + } + + $this->_state = self::STATE_CLEAN; + + // Check query cache. + if ( ! ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver()))) { + $parser = new Parser($this); + + $this->_parserResult = $parser->parse(); + + return $this->_parserResult; + } + + $hash = $this->_getQueryCacheId(); + $cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash); + + if ($cached instanceof ParserResult) { + // Cache hit. + $this->_parserResult = $cached; + + return $this->_parserResult; + } + + // Cache miss. + $parser = new Parser($this); + + $this->_parserResult = $parser->parse(); + + $queryCache->save($hash, $this->_parserResult, $this->_queryCacheTTL); + + return $this->_parserResult; + } + + /** + * {@inheritdoc} + */ + protected function _doExecute() + { + $executor = $this->_parse()->getSqlExecutor(); + + if ($this->_queryCacheProfile) { + $executor->setQueryCacheProfile($this->_queryCacheProfile); + } + + // Prepare parameters + $paramMappings = $this->_parserResult->getParameterMappings(); + + if (count($paramMappings) != count($this->parameters)) { + throw QueryException::invalidParameterNumber(); + } + + list($sqlParams, $types) = $this->processParameterMappings($paramMappings); + + if ($this->_resultSetMapping === null) { + $this->_resultSetMapping = $this->_parserResult->getResultSetMapping(); + } + + return $executor->execute($this->_em->getConnection(), $sqlParams, $types); + } + + /** + * Processes query parameter mappings + * + * @param array $paramMappings + * @return array + */ + private function processParameterMappings($paramMappings) + { + $sqlParams = array(); + $types = array(); + + foreach ($this->parameters as $parameter) { + $key = $parameter->getName(); + + if ( ! isset($paramMappings[$key])) { + throw QueryException::unknownParameter($key); + } + + $value = $this->processParameterValue($parameter->getValue()); + $type = ($parameter->getValue() === $value) + ? $parameter->getType() + : Query\ParameterTypeInferer::inferType($value); + + foreach ($paramMappings[$key] as $position) { + $types[$position] = $type; + } + + $sqlPositions = $paramMappings[$key]; + + // optimized multi value sql positions away for now, + // they are not allowed in DQL anyways. + $value = array($value); + $countValue = count($value); + + for ($i = 0, $l = count($sqlPositions); $i < $l; $i++) { + $sqlParams[$sqlPositions[$i]] = $value[($i % $countValue)]; + } + } + + if (count($sqlParams) != count($types)) { + throw QueryException::parameterTypeMissmatch(); + } + + if ($sqlParams) { + ksort($sqlParams); + $sqlParams = array_values($sqlParams); + + ksort($types); + $types = array_values($types); + } + + return array($sqlParams, $types); + } + + /** + * Defines a cache driver to be used for caching queries. + * + * @param Doctrine_Cache_Interface|null $driver Cache driver + * @return Query This query instance. + */ + public function setQueryCacheDriver($queryCache) + { + $this->_queryCache = $queryCache; + + return $this; + } + + /** + * Defines whether the query should make use of a query cache, if available. + * + * @param boolean $bool + * @return @return Query This query instance. + */ + public function useQueryCache($bool) + { + $this->_useQueryCache = $bool; + + return $this; + } + + /** + * Returns the cache driver used for query caching. + * + * @return CacheDriver The cache driver used for query caching or NULL, if + * this Query does not use query caching. + */ + public function getQueryCacheDriver() + { + if ($this->_queryCache) { + return $this->_queryCache; + } + + return $this->_em->getConfiguration()->getQueryCacheImpl(); + } + + /** + * Defines how long the query cache will be active before expire. + * + * @param integer $timeToLive How long the cache entry is valid + * @return Query This query instance. + */ + public function setQueryCacheLifetime($timeToLive) + { + if ($timeToLive !== null) { + $timeToLive = (int) $timeToLive; + } + + $this->_queryCacheTTL = $timeToLive; + + return $this; + } + + /** + * Retrieves the lifetime of resultset cache. + * + * @return int + */ + public function getQueryCacheLifetime() + { + return $this->_queryCacheTTL; + } + + /** + * Defines if the query cache is active or not. + * + * @param boolean $expire Whether or not to force query cache expiration. + * @return Query This query instance. + */ + public function expireQueryCache($expire = true) + { + $this->_expireQueryCache = $expire; + + return $this; + } + + /** + * Retrieves if the query cache is active or not. + * + * @return bool + */ + public function getExpireQueryCache() + { + return $this->_expireQueryCache; + } + + /** + * @override + */ + public function free() + { + parent::free(); + + $this->_dql = null; + $this->_state = self::STATE_CLEAN; + } + + /** + * Sets a DQL query string. + * + * @param string $dqlQuery DQL Query + * @return \Doctrine\ORM\AbstractQuery + */ + public function setDQL($dqlQuery) + { + if ($dqlQuery !== null) { + $this->_dql = $dqlQuery; + $this->_state = self::STATE_DIRTY; + } + + return $this; + } + + /** + * Returns the DQL query that is represented by this query object. + * + * @return string DQL query + */ + public function getDQL() + { + return $this->_dql; + } + + /** + * Returns the state of this query object + * By default the type is Doctrine_ORM_Query_Abstract::STATE_CLEAN but if it appears any unprocessed DQL + * part, it is switched to Doctrine_ORM_Query_Abstract::STATE_DIRTY. + * + * @see AbstractQuery::STATE_CLEAN + * @see AbstractQuery::STATE_DIRTY + * + * @return integer Return the query state + */ + public function getState() + { + return $this->_state; + } + + /** + * Method to check if an arbitrary piece of DQL exists + * + * @param string $dql Arbitrary piece of DQL to check for + * @return boolean + */ + public function contains($dql) + { + return stripos($this->getDQL(), $dql) === false ? false : true; + } + + /** + * Sets the position of the first result to retrieve (the "offset"). + * + * @param integer $firstResult The first result to return. + * @return Query This query object. + */ + public function setFirstResult($firstResult) + { + $this->_firstResult = $firstResult; + $this->_state = self::STATE_DIRTY; + + return $this; + } + + /** + * Gets the position of the first result the query object was set to retrieve (the "offset"). + * Returns NULL if {@link setFirstResult} was not applied to this query. + * + * @return integer The position of the first result. + */ + public function getFirstResult() + { + return $this->_firstResult; + } + + /** + * Sets the maximum number of results to retrieve (the "limit"). + * + * @param integer $maxResults + * @return Query This query object. + */ + public function setMaxResults($maxResults) + { + $this->_maxResults = $maxResults; + $this->_state = self::STATE_DIRTY; + + return $this; + } + + /** + * Gets the maximum number of results the query object was set to retrieve (the "limit"). + * Returns NULL if {@link setMaxResults} was not applied to this query. + * + * @return integer Maximum number of results. + */ + public function getMaxResults() + { + return $this->_maxResults; + } + + /** + * Executes the query and returns an IterableResult that can be used to incrementally + * iterated over the result. + * + * @param \Doctrine\Common\Collections\ArrayCollection|array $parameters The query parameters. + * @param integer $hydrationMode The hydration mode to use. + * @return \Doctrine\ORM\Internal\Hydration\IterableResult + */ + public function iterate($parameters = null, $hydrationMode = self::HYDRATE_OBJECT) + { + $this->setHint(self::HINT_INTERNAL_ITERATION, true); + + return parent::iterate($parameters, $hydrationMode); + } + + /** + * {@inheritdoc} + */ + public function setHint($name, $value) + { + $this->_state = self::STATE_DIRTY; + + return parent::setHint($name, $value); + } + + /** + * {@inheritdoc} + */ + public function setHydrationMode($hydrationMode) + { + $this->_state = self::STATE_DIRTY; + + return parent::setHydrationMode($hydrationMode); + } + + /** + * Set the lock mode for this Query. + * + * @see \Doctrine\DBAL\LockMode + * @param int $lockMode + * @return Query + */ + public function setLockMode($lockMode) + { + if (in_array($lockMode, array(LockMode::PESSIMISTIC_READ, LockMode::PESSIMISTIC_WRITE))) { + if ( ! $this->_em->getConnection()->isTransactionActive()) { + throw TransactionRequiredException::transactionRequired(); + } + } + + $this->setHint(self::HINT_LOCK_MODE, $lockMode); + + return $this; + } + + /** + * Get the current lock mode for this query. + * + * @return int + */ + public function getLockMode() + { + $lockMode = $this->getHint(self::HINT_LOCK_MODE); + + if ( ! $lockMode) { + return LockMode::NONE; + } + + return $lockMode; + } + + /** + * Generate a cache id for the query cache - reusing the Result-Cache-Id generator. + * + * The query cache + * + * @return string + */ + protected function _getQueryCacheId() + { + ksort($this->_hints); + + return md5( + $this->getDql() . var_export($this->_hints, true) . + ($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') . + '&firstResult=' . $this->_firstResult . '&maxResult=' . $this->_maxResults . + '&hydrationMode='.$this->_hydrationMode.'DOCTRINE_QUERY_CACHE_SALT' + ); + } + + /** + * Cleanup Query resource when clone is called. + * + * @return void + */ + public function __clone() + { + parent::__clone(); + + $this->_state = self::STATE_DIRTY; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ASTException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ASTException.php new file mode 100644 index 0000000..4633322 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ASTException.php @@ -0,0 +1,33 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +use Doctrine\ORM\Query\QueryException; + +/** + * Base exception class for AST exceptions. + */ +class ASTException extends QueryException +{ + public static function noDispatchForNode($node) + { + return new self("Double-dispatch for node " . get_class($node) . " is not supported."); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/AggregateExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/AggregateExpression.php new file mode 100644 index 0000000..ec91ada --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/AggregateExpression.php @@ -0,0 +1,49 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Description of AggregateExpression + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class AggregateExpression extends Node +{ + public $functionName; + public $pathExpression; + public $isDistinct = false; // Some aggregate expressions support distinct, eg COUNT + + public function __construct($functionName, $pathExpression, $isDistinct) + { + $this->functionName = $functionName; + $this->pathExpression = $pathExpression; + $this->isDistinct = $isDistinct; + } + + public function dispatch($walker) + { + return $walker->walkAggregateExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticExpression.php new file mode 100644 index 0000000..55a6b06 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticExpression.php @@ -0,0 +1,51 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ArithmeticExpression extends Node +{ + public $simpleArithmeticExpression; + public $subselect; + + public function isSimpleArithmeticExpression() + { + return (bool) $this->simpleArithmeticExpression; + } + + public function isSubselect() + { + return (bool) $this->subselect; + } + + public function dispatch($walker) + { + return $walker->walkArithmeticExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php new file mode 100644 index 0000000..8d595ef --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php @@ -0,0 +1,64 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ArithmeticFactor extends Node +{ + /** + * @var ArithmeticPrimary + */ + public $arithmeticPrimary; + + /** + * @var null|boolean NULL represents no sign, TRUE means positive and FALSE means negative sign + */ + public $sign; + + public function __construct($arithmeticPrimary, $sign = null) + { + $this->arithmeticPrimary = $arithmeticPrimary; + $this->sign = $sign; + } + + public function isPositiveSigned() + { + return $this->sign === true; + } + + public function isNegativeSigned() + { + return $this->sign === false; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkArithmeticFactor($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php new file mode 100644 index 0000000..ced25e9 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}* + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ArithmeticTerm extends Node +{ + public $arithmeticFactors; + + public function __construct(array $arithmeticFactors) + { + $this->arithmeticFactors = $arithmeticFactors; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkArithmeticTerm($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/BetweenExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/BetweenExpression.php new file mode 100644 index 0000000..83ba6ca --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/BetweenExpression.php @@ -0,0 +1,51 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Description of BetweenExpression + * + + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class BetweenExpression extends Node +{ + public $expression; + public $leftBetweenExpression; + public $rightBetweenExpression; + public $not; + + public function __construct($expr, $leftExpr, $rightExpr) + { + $this->expression = $expr; + $this->leftBetweenExpression = $leftExpr; + $this->rightBetweenExpression = $rightExpr; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkBetweenExpression($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/CoalesceExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/CoalesceExpression.php new file mode 100644 index 0000000..731d45e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/CoalesceExpression.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")" + * + * @since 2.1 + * + * @link www.doctrine-project.org + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class CoalesceExpression extends Node +{ + public $scalarExpressions = array(); + + + public function __construct(array $scalarExpressions) + { + $this->scalarExpressions = $scalarExpressions; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkCoalesceExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/CollectionMemberExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/CollectionMemberExpression.php new file mode 100644 index 0000000..b8c7b53 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/CollectionMemberExpression.php @@ -0,0 +1,49 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class CollectionMemberExpression extends Node +{ + public $entityExpression; + public $collectionValuedPathExpression; + public $not; + + public function __construct($entityExpr, $collValuedPathExpr) + { + $this->entityExpression = $entityExpr; + $this->collectionValuedPathExpression = $collValuedPathExpr; + } + + public function dispatch($walker) + { + return $walker->walkCollectionMemberExpression($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ComparisonExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ComparisonExpression.php new file mode 100644 index 0000000..d3105a1 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ComparisonExpression.php @@ -0,0 +1,54 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) | + * StringExpression ComparisonOperator (StringExpression | QuantifiedExpression) | + * BooleanExpression ("=" | "<>" | "!=") (BooleanExpression | QuantifiedExpression) | + * EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) | + * DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) | + * EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression) + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ComparisonExpression extends Node +{ + public $leftExpression; + public $rightExpression; + public $operator; + + public function __construct($leftExpr, $operator, $rightExpr) + { + $this->leftExpression = $leftExpr; + $this->rightExpression = $rightExpr; + $this->operator = $operator; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkComparisonExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalExpression.php new file mode 100644 index 0000000..c302aa2 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalExpression.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}* + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConditionalExpression extends Node +{ + public $conditionalTerms = array(); + + public function __construct(array $conditionalTerms) + { + $this->conditionalTerms = $conditionalTerms; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkConditionalExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalFactor.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalFactor.php new file mode 100644 index 0000000..b17089b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalFactor.php @@ -0,0 +1,46 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * ConditionalFactor ::= ["NOT"] ConditionalPrimary + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConditionalFactor extends Node +{ + public $not = false; + public $conditionalPrimary; + + public function __construct($conditionalPrimary) + { + $this->conditionalPrimary = $conditionalPrimary; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkConditionalFactor($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php new file mode 100644 index 0000000..8a7c0b7 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php @@ -0,0 +1,51 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConditionalPrimary extends Node +{ + public $simpleConditionalExpression; + public $conditionalExpression; + + public function isSimpleConditionalExpression() + { + return (bool) $this->simpleConditionalExpression; + } + + public function isConditionalExpression() + { + return (bool) $this->conditionalExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkConditionalPrimary($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalTerm.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalTerm.php new file mode 100644 index 0000000..d24defc --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ConditionalTerm.php @@ -0,0 +1,44 @@ +. + */ +namespace Doctrine\ORM\Query\AST; + +/** + * ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}* + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConditionalTerm extends Node +{ + public $conditionalFactors = array(); + + public function __construct(array $conditionalFactors) + { + $this->conditionalFactors = $conditionalFactors; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkConditionalTerm($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/DeleteClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/DeleteClause.php new file mode 100644 index 0000000..a05e52f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/DeleteClause.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] AliasIdentificationVariable] + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class DeleteClause extends Node +{ + public $abstractSchemaName; + public $aliasIdentificationVariable; + + public function __construct($abstractSchemaName) + { + $this->abstractSchemaName = $abstractSchemaName; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkDeleteClause($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/DeleteStatement.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/DeleteStatement.php new file mode 100644 index 0000000..f6e8cb3 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/DeleteStatement.php @@ -0,0 +1,46 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * DeleteStatement = DeleteClause [WhereClause] + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class DeleteStatement extends Node +{ + public $deleteClause; + public $whereClause; + + public function __construct($deleteClause) + { + $this->deleteClause = $deleteClause; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkDeleteStatement($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/EmptyCollectionComparisonExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/EmptyCollectionComparisonExpression.php new file mode 100644 index 0000000..fbe504c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/EmptyCollectionComparisonExpression.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EmptyCollectionComparisonExpression extends Node +{ + public $expression; + public $not; + + public function __construct($expression) + { + $this->expression = $expression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkEmptyCollectionComparisonExpression($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ExistsExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ExistsExpression.php new file mode 100644 index 0000000..94ee55d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/ExistsExpression.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ExistsExpression extends Node +{ + public $not; + public $subselect; + + public function __construct($subselect) + { + $this->subselect = $subselect; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkExistsExpression($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/FromClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/FromClause.php new file mode 100644 index 0000000..32c7a73 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/FromClause.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration} + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class FromClause extends Node +{ + public $identificationVariableDeclarations = array(); + + public function __construct(array $identificationVariableDeclarations) + { + $this->identificationVariableDeclarations = $identificationVariableDeclarations; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkFromClause($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php new file mode 100644 index 0000000..d771f05 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php @@ -0,0 +1,62 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "ABS" "(" SimpleArithmeticExpression ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class AbsFunction extends FunctionNode +{ + public $simpleArithmeticExpression; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return 'ABS(' . $sqlWalker->walkSimpleArithmeticExpression( + $this->simpleArithmeticExpression + ) . ')'; + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php new file mode 100644 index 0000000..0e5edd5 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php @@ -0,0 +1,63 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")" + * + * + * @link www.doctrine-project.org + * @since 2.2 + * @author Fabio B. Silva + */ +class BitAndFunction extends FunctionNode +{ + public $firstArithmetic; + public $secondArithmetic; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + $platform = $sqlWalker->getConnection()->getDatabasePlatform(); + return $platform->getBitAndComparisonExpression( + $this->firstArithmetic->dispatch($sqlWalker), + $this->secondArithmetic->dispatch($sqlWalker) + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->firstArithmetic = $parser->ArithmeticPrimary(); + $parser->match(Lexer::T_COMMA); + $this->secondArithmetic = $parser->ArithmeticPrimary(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php new file mode 100644 index 0000000..1d9c2df --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php @@ -0,0 +1,63 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")" + * + * + * @link www.doctrine-project.org + * @since 2.2 + * @author Fabio B. Silva + */ +class BitOrFunction extends FunctionNode +{ + public $firstArithmetic; + public $secondArithmetic; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + $platform = $sqlWalker->getConnection()->getDatabasePlatform(); + return $platform->getBitOrComparisonExpression( + $this->firstArithmetic->dispatch($sqlWalker), + $this->secondArithmetic->dispatch($sqlWalker) + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->firstArithmetic = $parser->ArithmeticPrimary(); + $parser->match(Lexer::T_COMMA); + $this->secondArithmetic = $parser->ArithmeticPrimary(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/ConcatFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/ConcatFunction.php new file mode 100644 index 0000000..39ecd2d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/ConcatFunction.php @@ -0,0 +1,67 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "CONCAT" "(" StringPrimary "," StringPrimary ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class ConcatFunction extends FunctionNode +{ + public $firstStringPrimary; + public $secondStringPriamry; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + $platform = $sqlWalker->getConnection()->getDatabasePlatform(); + return $platform->getConcatExpression( + $sqlWalker->walkStringPrimary($this->firstStringPrimary), + $sqlWalker->walkStringPrimary($this->secondStringPrimary) + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->firstStringPrimary = $parser->StringPrimary(); + $parser->match(Lexer::T_COMMA); + $this->secondStringPrimary = $parser->StringPrimary(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php new file mode 100644 index 0000000..8e8ce1c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php @@ -0,0 +1,54 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "CURRENT_DATE" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class CurrentDateFunction extends FunctionNode +{ + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return $sqlWalker->getConnection()->getDatabasePlatform()->getCurrentDateSQL(); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php new file mode 100644 index 0000000..4bab247 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php @@ -0,0 +1,54 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "CURRENT_TIME" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class CurrentTimeFunction extends FunctionNode +{ + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return $sqlWalker->getConnection()->getDatabasePlatform()->getCurrentTimeSQL(); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimestampFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimestampFunction.php new file mode 100644 index 0000000..8a9b418 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimestampFunction.php @@ -0,0 +1,54 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "CURRENT_TIMESTAMP" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class CurrentTimestampFunction extends FunctionNode +{ + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return $sqlWalker->getConnection()->getDatabasePlatform()->getCurrentTimestampSQL(); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php new file mode 100644 index 0000000..bf56785 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php @@ -0,0 +1,77 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; +use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\Parser; +use Doctrine\ORM\Query\QueryException; + +/** + * "DATE_ADD" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Benjamin Eberlei + */ +class DateAddFunction extends FunctionNode +{ + public $firstDateExpression = null; + public $intervalExpression = null; + public $unit = null; + + public function getSql(SqlWalker $sqlWalker) + { + switch (strtolower($this->unit->value)) { + case 'day': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddDaysExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); + + case 'month': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddMonthExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); + + default: + throw QueryException::semanticalError( + 'DATE_ADD() only supports units of type day and month.' + ); + } + } + + public function parse(Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->firstDateExpression = $parser->ArithmeticPrimary(); + $parser->match(Lexer::T_COMMA); + $this->intervalExpression = $parser->ArithmeticPrimary(); + $parser->match(Lexer::T_COMMA); + $this->unit = $parser->StringPrimary(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateDiffFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateDiffFunction.php new file mode 100644 index 0000000..f21b9a0 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateDiffFunction.php @@ -0,0 +1,58 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; +use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\Parser; + +/** + * "DATE_DIFF" "(" ArithmeticPrimary "," ArithmeticPrimary ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + */ +class DateDiffFunction extends FunctionNode +{ + public $date1; + public $date2; + + public function getSql(SqlWalker $sqlWalker) + { + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateDiffExpression( + $this->date1->dispatch($sqlWalker), + $this->date2->dispatch($sqlWalker) + ); + } + + public function parse(Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->date1 = $parser->ArithmeticPrimary(); + $parser->match(Lexer::T_COMMA); + $this->date2 = $parser->ArithmeticPrimary(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php new file mode 100644 index 0000000..0cc0730 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php @@ -0,0 +1,57 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\QueryException; + +/** + * "DATE_ADD(date1, interval, unit)" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Benjamin Eberlei + */ +class DateSubFunction extends DateAddFunction +{ + public function getSql(SqlWalker $sqlWalker) + { + switch (strtolower($this->unit->value)) { + case 'day': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubDaysExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); + + case 'month': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubMonthExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); + + default: + throw QueryException::semanticalError( + 'DATE_SUB() only supports units of type day and month.' + ); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/FunctionNode.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/FunctionNode.php new file mode 100644 index 0000000..bd8b607 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/FunctionNode.php @@ -0,0 +1,52 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\AST\Node; + +/** + * Abtract Function Node. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +abstract class FunctionNode extends Node +{ + public $name; + + public function __construct($name) + { + $this->name = $name; + } + + abstract public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker); + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkFunction($this); + } + + abstract public function parse(\Doctrine\ORM\Query\Parser $parser); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php new file mode 100644 index 0000000..2733399 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php @@ -0,0 +1,67 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "IDENTITY" "(" SingleValuedAssociationPathExpression ")" + * + * + * @link www.doctrine-project.org + * @since 2.2 + * @author Guilherme Blanco + * @author Benjamin Eberlei + */ +class IdentityFunction extends FunctionNode +{ + public $pathExpression; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + $dqlAlias = $this->pathExpression->identificationVariable; + $assocField = $this->pathExpression->field; + + $qComp = $sqlWalker->getQueryComponent($dqlAlias); + $class = $qComp['metadata']; + $assoc = $class->associationMappings[$assocField]; + + $tableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); + + return $tableAlias . '.' . reset($assoc['targetToSourceKeyColumns']);; + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->pathExpression = $parser->SingleValuedAssociationPathExpression(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LengthFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LengthFunction.php new file mode 100644 index 0000000..9c6f770 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LengthFunction.php @@ -0,0 +1,62 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "LENGTH" "(" StringPrimary ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class LengthFunction extends FunctionNode +{ + public $stringPrimary; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return $sqlWalker->getConnection()->getDatabasePlatform()->getLengthExpression( + $sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary) + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->stringPrimary = $parser->StringPrimary(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LocateFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LocateFunction.php new file mode 100644 index 0000000..a189082 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LocateFunction.php @@ -0,0 +1,81 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class LocateFunction extends FunctionNode +{ + public $firstStringPrimary; + public $secondStringPrimary; + public $simpleArithmeticExpression = false; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + + return $sqlWalker->getConnection()->getDatabasePlatform()->getLocateExpression( + $sqlWalker->walkStringPrimary($this->secondStringPrimary), // its the other way around in platform + $sqlWalker->walkStringPrimary($this->firstStringPrimary), + (($this->simpleArithmeticExpression) + ? $sqlWalker->walkSimpleArithmeticExpression($this->simpleArithmeticExpression) + : false + ) + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->firstStringPrimary = $parser->StringPrimary(); + + $parser->match(Lexer::T_COMMA); + + $this->secondStringPrimary = $parser->StringPrimary(); + + $lexer = $parser->getLexer(); + if ($lexer->isNextToken(Lexer::T_COMMA)) { + $parser->match(Lexer::T_COMMA); + + $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); + } + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LowerFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LowerFunction.php new file mode 100644 index 0000000..12c6745 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/LowerFunction.php @@ -0,0 +1,62 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "LOWER" "(" StringPrimary ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class LowerFunction extends FunctionNode +{ + public $stringPrimary; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return $sqlWalker->getConnection()->getDatabasePlatform()->getLowerExpression( + $sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary) + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->stringPrimary = $parser->StringPrimary(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php new file mode 100644 index 0000000..27d252e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php @@ -0,0 +1,68 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class ModFunction extends FunctionNode +{ + public $firstSimpleArithmeticExpression; + public $secondSimpleArithmeticExpression; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return $sqlWalker->getConnection()->getDatabasePlatform()->getModExpression( + $sqlWalker->walkSimpleArithmeticExpression($this->firstSimpleArithmeticExpression), + $sqlWalker->walkSimpleArithmeticExpression($this->secondSimpleArithmeticExpression) + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); + + $parser->match(Lexer::T_COMMA); + + $this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php new file mode 100644 index 0000000..bffff29 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SizeFunction.php @@ -0,0 +1,121 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "SIZE" "(" CollectionValuedPathExpression ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class SizeFunction extends FunctionNode +{ + public $collectionPathExpression; + + /** + * @override + * @todo If the collection being counted is already joined, the SQL can be simpler (more efficient). + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + $platform = $sqlWalker->getEntityManager()->getConnection()->getDatabasePlatform(); + $quoteStrategy = $sqlWalker->getEntityManager()->getConfiguration()->getQuoteStrategy(); + $dqlAlias = $this->collectionPathExpression->identificationVariable; + $assocField = $this->collectionPathExpression->field; + + $qComp = $sqlWalker->getQueryComponent($dqlAlias); + $class = $qComp['metadata']; + $assoc = $class->associationMappings[$assocField]; + $sql = 'SELECT COUNT(*) FROM '; + + if ($assoc['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY) { + $targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']); + $targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->getTableName()); + $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); + + $sql .= $quoteStrategy->getTableName($targetClass, $platform) . ' ' . $targetTableAlias . ' WHERE '; + + $owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']]; + + $first = true; + + foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) { + if ($first) $first = false; else $sql .= ' AND '; + + $sql .= $targetTableAlias . '.' . $sourceColumn + . ' = ' + . $sourceTableAlias . '.' . $quoteStrategy->getColumnName($class->fieldNames[$targetColumn], $class, $platform); + } + } else { // many-to-many + $targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']); + + $owningAssoc = $assoc['isOwningSide'] ? $assoc : $targetClass->associationMappings[$assoc['mappedBy']]; + $joinTable = $owningAssoc['joinTable']; + + // SQL table aliases + $joinTableAlias = $sqlWalker->getSQLTableAlias($joinTable['name']); + $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); + + // join to target table + $sql .= $quoteStrategy->getJoinTableName($owningAssoc, $targetClass, $platform) . ' ' . $joinTableAlias . ' WHERE '; + + $joinColumns = $assoc['isOwningSide'] + ? $joinTable['joinColumns'] + : $joinTable['inverseJoinColumns']; + + $first = true; + + foreach ($joinColumns as $joinColumn) { + if ($first) $first = false; else $sql .= ' AND '; + + $sourceColumnName = $quoteStrategy->getColumnName( + $class->fieldNames[$joinColumn['referencedColumnName']], $class, $platform + ); + + $sql .= $joinTableAlias . '.' . $joinColumn['name'] + . ' = ' + . $sourceTableAlias . '.' . $sourceColumnName; + } + } + + return '(' . $sql . ')'; + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->collectionPathExpression = $parser->CollectionValuedPathExpression(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php new file mode 100644 index 0000000..cf8c27b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php @@ -0,0 +1,62 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "SQRT" "(" SimpleArithmeticExpression ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class SqrtFunction extends FunctionNode +{ + public $simpleArithmeticExpression; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return $sqlWalker->getConnection()->getDatabasePlatform()->getSqrtExpression( + $sqlWalker->walkSimpleArithmeticExpression($this->simpleArithmeticExpression) + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php new file mode 100644 index 0000000..6f3dfbe --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php @@ -0,0 +1,82 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class SubstringFunction extends FunctionNode +{ + public $stringPrimary; + public $firstSimpleArithmeticExpression; + public $secondSimpleArithmeticExpression = null; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + $optionalSecondSimpleArithmeticExpression = null; + if ($this->secondSimpleArithmeticExpression !== null) { + $optionalSecondSimpleArithmeticExpression = $sqlWalker->walkSimpleArithmeticExpression($this->secondSimpleArithmeticExpression); + } + + return $sqlWalker->getConnection()->getDatabasePlatform()->getSubstringExpression( + $sqlWalker->walkStringPrimary($this->stringPrimary), + $sqlWalker->walkSimpleArithmeticExpression($this->firstSimpleArithmeticExpression), + $optionalSecondSimpleArithmeticExpression + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->stringPrimary = $parser->StringPrimary(); + + $parser->match(Lexer::T_COMMA); + + $this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); + + $lexer = $parser->getLexer(); + if ($lexer->isNextToken(Lexer::T_COMMA)) { + $parser->match(Lexer::T_COMMA); + + $this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression(); + } + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/TrimFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/TrimFunction.php new file mode 100644 index 0000000..0c60ab0 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/TrimFunction.php @@ -0,0 +1,100 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; +use Doctrine\DBAL\Platforms\AbstractPlatform; + +/** + * "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class TrimFunction extends FunctionNode +{ + public $leading; + public $trailing; + public $both; + public $trimChar = false; + public $stringPrimary; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + $pos = AbstractPlatform::TRIM_UNSPECIFIED; + if ($this->leading) { + $pos = AbstractPlatform::TRIM_LEADING; + } else if ($this->trailing) { + $pos = AbstractPlatform::TRIM_TRAILING; + } else if ($this->both) { + $pos = AbstractPlatform::TRIM_BOTH; + } + + return $sqlWalker->getConnection()->getDatabasePlatform()->getTrimExpression( + $sqlWalker->walkStringPrimary($this->stringPrimary), + $pos, + ($this->trimChar != false) ? $sqlWalker->getConnection()->quote($this->trimChar) : false + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $lexer = $parser->getLexer(); + + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + if (strcasecmp('leading', $lexer->lookahead['value']) === 0) { + $parser->match(Lexer::T_LEADING); + $this->leading = true; + } else if (strcasecmp('trailing', $lexer->lookahead['value']) === 0) { + $parser->match(Lexer::T_TRAILING); + $this->trailing = true; + } else if (strcasecmp('both', $lexer->lookahead['value']) === 0) { + $parser->match(Lexer::T_BOTH); + $this->both = true; + } + + if ($lexer->isNextToken(Lexer::T_STRING)) { + $parser->match(Lexer::T_STRING); + $this->trimChar = $lexer->token['value']; + } + + if ($this->leading || $this->trailing || $this->both || $this->trimChar) { + $parser->match(Lexer::T_FROM); + } + + $this->stringPrimary = $parser->StringPrimary(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/UpperFunction.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/UpperFunction.php new file mode 100644 index 0000000..26c8f0d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Functions/UpperFunction.php @@ -0,0 +1,62 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "UPPER" "(" StringPrimary ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class UpperFunction extends FunctionNode +{ + public $stringPrimary; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return $sqlWalker->getConnection()->getDatabasePlatform()->getUpperExpression( + $sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary) + ); + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + + $this->stringPrimary = $parser->StringPrimary(); + + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/GeneralCaseExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/GeneralCaseExpression.php new file mode 100644 index 0000000..ee4b418 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/GeneralCaseExpression.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END" + * + * @since 2.2 + * + * @link www.doctrine-project.org + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GeneralCaseExpression extends Node +{ + public $whenClauses = array(); + public $elseScalarExpression = null; + + public function __construct(array $whenClauses, $elseScalarExpression) + { + $this->whenClauses = $whenClauses; + $this->elseScalarExpression = $elseScalarExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkGeneralCaseExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/GroupByClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/GroupByClause.php new file mode 100644 index 0000000..06350f0 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/GroupByClause.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Description of GroupByClause + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GroupByClause extends Node +{ + public $groupByItems = array(); + + public function __construct(array $groupByItems) + { + $this->groupByItems = $groupByItems; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkGroupByClause($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/HavingClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/HavingClause.php new file mode 100644 index 0000000..971e919 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/HavingClause.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Description of HavingClause + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class HavingClause extends Node +{ + public $conditionalExpression; + + public function __construct($conditionalExpression) + { + $this->conditionalExpression = $conditionalExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkHavingClause($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php new file mode 100644 index 0000000..6bbdaaa --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php @@ -0,0 +1,49 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}* + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class IdentificationVariableDeclaration extends Node +{ + public $rangeVariableDeclaration = null; + public $indexBy = null; + public $joins = array(); + + public function __construct($rangeVariableDecl, $indexBy, array $joins) + { + $this->rangeVariableDeclaration = $rangeVariableDecl; + $this->indexBy = $indexBy; + $this->joins = $joins; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkIdentificationVariableDeclaration($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InExpression.php new file mode 100644 index 0000000..39501a4 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InExpression.php @@ -0,0 +1,48 @@ +. + */ +namespace Doctrine\ORM\Query\AST; + +/** + * InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (Literal {"," Literal}* | Subselect) ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class InExpression extends Node +{ + public $not; + public $expression; + public $literals = array(); + public $subselect; + + public function __construct($expression) + { + $this->expression = $expression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkInExpression($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/IndexBy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/IndexBy.php new file mode 100644 index 0000000..08e9e6a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/IndexBy.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class IndexBy extends Node +{ + public $simpleStateFieldPathExpression = null; + + public function __construct($simpleStateFieldPathExpression) + { + $this->simpleStateFieldPathExpression = $simpleStateFieldPathExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkIndexBy($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InputParameter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InputParameter.php new file mode 100644 index 0000000..d575df7 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InputParameter.php @@ -0,0 +1,55 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Description of InputParameter + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class InputParameter extends Node +{ + public $isNamed; + public $name; + + /** + * @param string $value + */ + public function __construct($value) + { + if (strlen($value) == 1) { + throw \Doctrine\ORM\Query\QueryException::invalidParameterFormat($value); + } + + $param = substr($value, 1); + $this->isNamed = ! is_numeric($param); + $this->name = $param; + } + + public function dispatch($walker) + { + return $walker->walkInputParameter($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php new file mode 100644 index 0000000..c022cd6 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php @@ -0,0 +1,49 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")") + * InstanceOfParameter ::= AbstractSchemaName | InputParameter + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class InstanceOfExpression extends Node +{ + public $not; + public $identificationVariable; + public $value; + + public function __construct($identVariable) + { + $this->identificationVariable = $identVariable; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkInstanceOfExpression($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Join.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Join.php new file mode 100644 index 0000000..6724f9e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Join.php @@ -0,0 +1,52 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression + * ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression] + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Join extends Node +{ + const JOIN_TYPE_LEFT = 1; + const JOIN_TYPE_LEFTOUTER = 2; + const JOIN_TYPE_INNER = 3; + + public $joinType = self::JOIN_TYPE_INNER; + public $joinAssociationDeclaration = null; + public $conditionalExpression = null; + + public function __construct($joinType, $joinAssociationDeclaration) + { + $this->joinType = $joinType; + $this->joinAssociationDeclaration = $joinAssociationDeclaration; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkJoin($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinAssociationDeclaration.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinAssociationDeclaration.php new file mode 100644 index 0000000..8e97353 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinAssociationDeclaration.php @@ -0,0 +1,46 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable + * + * @link www.doctrine-project.org + * @since 2.3 + * @author Guilherme Blanco + */ +class JoinAssociationDeclaration extends Node +{ + public $joinAssociationPathExpression; + public $aliasIdentificationVariable; + public $indexBy; + + public function __construct($joinAssociationPathExpression, $aliasIdentificationVariable, $indexBy) + { + $this->joinAssociationPathExpression = $joinAssociationPathExpression; + $this->aliasIdentificationVariable = $aliasIdentificationVariable; + $this->indexBy = $indexBy; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkJoinAssociationDeclaration($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinAssociationPathExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinAssociationPathExpression.php new file mode 100644 index 0000000..57bd052 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinAssociationPathExpression.php @@ -0,0 +1,46 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * JoinAssociationPathExpression ::= IdentificationVariable "." (SingleValuedAssociationField | CollectionValuedAssociationField) + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class JoinAssociationPathExpression extends Node +{ + public $identificationVariable; + public $associationField; + + public function __construct($identificationVariable, $associationField) + { + $this->identificationVariable = $identificationVariable; + $this->associationField = $associationField; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkPathExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinClassPathExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinClassPathExpression.php new file mode 100644 index 0000000..d6e6e2f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/JoinClassPathExpression.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * JoinClassPathExpression ::= AbstractSchemaName ["AS"] AliasIdentificationVariable + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.3 + * @author Alexander + */ +class JoinClassPathExpression extends Node +{ + public $abstractSchemaName; + public $aliasIdentificationVariable; + + public function __construct($abstractSchemaName, $aliasIdentificationVar) + { + $this->abstractSchemaName = $abstractSchemaName; + $this->aliasIdentificationVariable = $aliasIdentificationVar; + } + + public function dispatch($walker) + { + return $sqlWalker->walkJoinPathExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/LikeExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/LikeExpression.php new file mode 100644 index 0000000..68f8635 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/LikeExpression.php @@ -0,0 +1,49 @@ +. + */ +namespace Doctrine\ORM\Query\AST; + +/** + * LikeExpression ::= StringExpression ["NOT"] "LIKE" string ["ESCAPE" char] + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class LikeExpression extends Node +{ + public $not; + public $stringExpression; + public $stringPattern; + public $escapeChar; + + public function __construct($stringExpression, $stringPattern, $escapeChar = null) + { + $this->stringExpression = $stringExpression; + $this->stringPattern = $stringPattern; + $this->escapeChar = $escapeChar; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkLikeExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Literal.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Literal.php new file mode 100644 index 0000000..26337cb --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Literal.php @@ -0,0 +1,41 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +class Literal extends Node +{ + const STRING = 1; + const BOOLEAN = 2; + const NUMERIC = 3; + + public $type; + public $value; + + public function __construct($type, $value) + { + $this->type = $type; + $this->value = $value; + } + + public function dispatch($walker) + { + return $walker->walkLiteral($this); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Node.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Node.php new file mode 100644 index 0000000..d50e0d0 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Node.php @@ -0,0 +1,95 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Abstract class of an AST node + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +abstract class Node +{ + /** + * Double-dispatch method, supposed to dispatch back to the walker. + * + * Implementation is not mandatory for all nodes. + * + * @param $walker + */ + public function dispatch($walker) + { + throw ASTException::noDispatchForNode($this); + } + + /** + * Dumps the AST Node into a string representation for information purpose only + * + * @return string + */ + public function __toString() + { + return $this->dump($this); + } + + public function dump($obj) + { + static $ident = 0; + + $str = ''; + + if ($obj instanceof Node) { + $str .= get_class($obj) . '(' . PHP_EOL; + $props = get_object_vars($obj); + + foreach ($props as $name => $prop) { + $ident += 4; + $str .= str_repeat(' ', $ident) . '"' . $name . '": ' + . $this->dump($prop) . ',' . PHP_EOL; + $ident -= 4; + } + + $str .= str_repeat(' ', $ident) . ')'; + } else if (is_array($obj)) { + $ident += 4; + $str .= 'array('; + $some = false; + + foreach ($obj as $k => $v) { + $str .= PHP_EOL . str_repeat(' ', $ident) . '"' + . $k . '" => ' . $this->dump($v) . ','; + $some = true; + } + + $ident -= 4; + $str .= ($some ? PHP_EOL . str_repeat(' ', $ident) : '') . ')'; + } else if (is_object($obj)) { + $str .= 'instanceof(' . get_class($obj) . ')'; + } else { + $str .= var_export($obj, true); + } + + return $str; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/NullComparisonExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/NullComparisonExpression.php new file mode 100644 index 0000000..d0fb8bf --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/NullComparisonExpression.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class NullComparisonExpression extends Node +{ + public $not; + public $expression; + + public function __construct($expression) + { + $this->expression = $expression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkNullComparisonExpression($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/NullIfExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/NullIfExpression.php new file mode 100644 index 0000000..2c85ddd --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/NullIfExpression.php @@ -0,0 +1,49 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * NullIfExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")" + * + * @since 2.1 + * + * @link www.doctrine-project.org + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class NullIfExpression extends Node +{ + public $firstExpression; + + public $secondExpression; + + public function __construct($firstExpression, $secondExpression) + { + $this->firstExpression = $firstExpression; + $this->secondExpression = $secondExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkNullIfExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/OrderByClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/OrderByClause.php new file mode 100644 index 0000000..311a9ed --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/OrderByClause.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}* + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class OrderByClause extends Node +{ + public $orderByItems = array(); + + public function __construct(array $orderByItems) + { + $this->orderByItems = $orderByItems; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkOrderByClause($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/OrderByItem.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/OrderByItem.php new file mode 100644 index 0000000..5d48077 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/OrderByItem.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * OrderByItem ::= (ResultVariable | StateFieldPathExpression) ["ASC" | "DESC"] + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class OrderByItem extends Node +{ + public $expression; + public $type; + + public function __construct($expression) + { + $this->expression = $expression; + } + + public function isAsc() + { + return strtoupper($this->type) == 'ASC'; + } + + public function isDesc() + { + return strtoupper($this->type) == 'DESC'; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkOrderByItem($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/PartialObjectExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/PartialObjectExpression.php new file mode 100644 index 0000000..8a0e0d0 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/PartialObjectExpression.php @@ -0,0 +1,32 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +class PartialObjectExpression extends Node +{ + public $identificationVariable; + public $partialFieldSet; + + public function __construct($identificationVariable, array $partialFieldSet) + { + $this->identificationVariable = $identificationVariable; + $this->partialFieldSet = $partialFieldSet; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/PathExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/PathExpression.php new file mode 100644 index 0000000..1b27742 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/PathExpression.php @@ -0,0 +1,58 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression + * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression + * StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression + * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField + * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField + * StateField ::= {EmbeddedClassStateField "."}* SimpleStateField + * SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField + * + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class PathExpression extends Node +{ + const TYPE_COLLECTION_VALUED_ASSOCIATION = 2; + const TYPE_SINGLE_VALUED_ASSOCIATION = 4; + const TYPE_STATE_FIELD = 8; + + public $type; + public $expectedType; + public $identificationVariable; + public $field; + + public function __construct($expectedType, $identificationVariable, $field = null) + { + $this->expectedType = $expectedType; + $this->identificationVariable = $identificationVariable; + $this->field = $field; + } + + public function dispatch($walker) + { + return $walker->walkPathExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/QuantifiedExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/QuantifiedExpression.php new file mode 100644 index 0000000..64a764e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/QuantifiedExpression.php @@ -0,0 +1,64 @@ +. + */ +namespace Doctrine\ORM\Query\AST; + +/** + * QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class QuantifiedExpression extends Node +{ + public $type; + public $subselect; + + public function __construct($subselect) + { + $this->subselect = $subselect; + } + + public function isAll() + { + return strtoupper($this->type) == 'ALL'; + } + + public function isAny() + { + return strtoupper($this->type) == 'ANY'; + } + + public function isSome() + { + return strtoupper($this->type) == 'SOME'; + } + + /** + * @override + */ + public function dispatch($sqlWalker) + { + return $sqlWalker->walkQuantifiedExpression($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php new file mode 100644 index 0000000..facd0bb --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class RangeVariableDeclaration extends Node +{ + public $abstractSchemaName; + public $aliasIdentificationVariable; + + public function __construct($abstractSchemaName, $aliasIdentificationVar) + { + $this->abstractSchemaName = $abstractSchemaName; + $this->aliasIdentificationVariable = $aliasIdentificationVar; + } + + public function dispatch($walker) + { + return $walker->walkRangeVariableDeclaration($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectClause.php new file mode 100644 index 0000000..be76a4f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectClause.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SelectClause = "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression} + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SelectClause extends Node +{ + public $isDistinct; + public $selectExpressions = array(); + + public function __construct(array $selectExpressions, $isDistinct) + { + $this->isDistinct = $isDistinct; + $this->selectExpressions = $selectExpressions; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSelectClause($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectExpression.php new file mode 100644 index 0000000..14ca850 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectExpression.php @@ -0,0 +1,50 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SelectExpression ::= IdentificationVariable ["." "*"] | StateFieldPathExpression | + * (AggregateExpression | "(" Subselect ")") [["AS"] ["HIDDEN"] FieldAliasIdentificationVariable] + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SelectExpression extends Node +{ + public $expression; + public $fieldIdentificationVariable; + public $hiddenAliasResultVariable; + + public function __construct($expression, $fieldIdentificationVariable, $hiddenAliasResultVariable = false) + { + $this->expression = $expression; + $this->fieldIdentificationVariable = $fieldIdentificationVariable; + $this->hiddenAliasResultVariable = $hiddenAliasResultVariable; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSelectExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectStatement.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectStatement.php new file mode 100644 index 0000000..d91d26f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SelectStatement.php @@ -0,0 +1,50 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SelectStatement = SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SelectStatement extends Node +{ + public $selectClause; + public $fromClause; + public $whereClause; + public $groupByClause; + public $havingClause; + public $orderByClause; + + public function __construct($selectClause, $fromClause) { + $this->selectClause = $selectClause; + $this->fromClause = $fromClause; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSelectStatement($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleArithmeticExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleArithmeticExpression.php new file mode 100644 index 0000000..8d91c9b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleArithmeticExpression.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}* + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SimpleArithmeticExpression extends Node +{ + public $arithmeticTerms = array(); + + public function __construct(array $arithmeticTerms) + { + $this->arithmeticTerms = $arithmeticTerms; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSimpleArithmeticExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleCaseExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleCaseExpression.php new file mode 100644 index 0000000..bd593ee --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleCaseExpression.php @@ -0,0 +1,50 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END" + * + * @since 2.2 + * + * @link www.doctrine-project.org + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SimpleCaseExpression extends Node +{ + public $caseOperand = null; + public $simpleWhenClauses = array(); + public $elseScalarExpression = null; + + public function __construct($caseOperand, array $simpleWhenClauses, $elseScalarExpression) + { + $this->caseOperand = $caseOperand; + $this->simpleWhenClauses = $simpleWhenClauses; + $this->elseScalarExpression = $elseScalarExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSimpleCaseExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php new file mode 100644 index 0000000..95a6198 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SimpleSelectClause extends Node +{ + public $isDistinct = false; + public $simpleSelectExpression; + + public function __construct($simpleSelectExpression, $isDistinct) + { + $this->simpleSelectExpression = $simpleSelectExpression; + $this->isDistinct = $isDistinct; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSimpleSelectClause($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php new file mode 100644 index 0000000..25e927e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php @@ -0,0 +1,47 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SimpleSelectExpression ::= StateFieldPathExpression | IdentificationVariable + * | (AggregateExpression [["AS"] FieldAliasIdentificationVariable]) + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SimpleSelectExpression extends Node +{ + public $expression; + public $fieldIdentificationVariable; + + public function __construct($expression) + { + $this->expression = $expression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSimpleSelectExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleWhenClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleWhenClause.php new file mode 100644 index 0000000..fabe449 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SimpleWhenClause.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression + * + * @since 2.2 + * + * @link www.doctrine-project.org + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SimpleWhenClause extends Node +{ + public $caseScalarExpression = null; + public $thenScalarExpression = null; + + public function __construct($caseScalarExpression, $thenScalarExpression) + { + $this->caseScalarExpression = $caseScalarExpression; + $this->thenScalarExpression = $thenScalarExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkWhenClauseExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Subselect.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Subselect.php new file mode 100644 index 0000000..46c0e96 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/Subselect.php @@ -0,0 +1,51 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Subselect extends Node +{ + public $simpleSelectClause; + public $subselectFromClause; + public $whereClause; + public $groupByClause; + public $havingClause; + public $orderByClause; + + public function __construct($simpleSelectClause, $subselectFromClause) + { + $this->simpleSelectClause = $simpleSelectClause; + $this->subselectFromClause = $subselectFromClause; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSubselect($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SubselectFromClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SubselectFromClause.php new file mode 100644 index 0000000..3a6b547 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/SubselectFromClause.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}* + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SubselectFromClause extends Node +{ + public $identificationVariableDeclarations = array(); + + public function __construct(array $identificationVariableDeclarations) + { + $this->identificationVariableDeclarations = $identificationVariableDeclarations; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSubselectFromClause($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateClause.php new file mode 100644 index 0000000..4188cf5 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateClause.php @@ -0,0 +1,49 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] AliasIdentificationVariable] "SET" UpdateItem {"," UpdateItem}* + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class UpdateClause extends Node +{ + public $abstractSchemaName; + public $aliasIdentificationVariable; + public $updateItems = array(); + + public function __construct($abstractSchemaName, array $updateItems) + { + $this->abstractSchemaName = $abstractSchemaName; + $this->updateItems = $updateItems; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkUpdateClause($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateItem.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateItem.php new file mode 100644 index 0000000..2a13391 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateItem.php @@ -0,0 +1,50 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * UpdateItem ::= [IdentificationVariable "."] {StateField | SingleValuedAssociationField} "=" NewValue + * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary | + * EnumPrimary | SimpleEntityExpression | "NULL" + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class UpdateItem extends Node +{ + public $pathExpression; + public $newValue; + + public function __construct($pathExpression, $newValue) + { + $this->pathExpression = $pathExpression; + $this->newValue = $newValue; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkUpdateItem($this); + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateStatement.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateStatement.php new file mode 100644 index 0000000..9e25d83 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/UpdateStatement.php @@ -0,0 +1,45 @@ +. + */ +namespace Doctrine\ORM\Query\AST; + +/** + * UpdateStatement = UpdateClause [WhereClause] + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class UpdateStatement extends Node +{ + public $updateClause; + public $whereClause; + + public function __construct($updateClause) + { + $this->updateClause = $updateClause; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkUpdateStatement($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/WhenClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/WhenClause.php new file mode 100644 index 0000000..ca91f57 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/WhenClause.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression + * + * @since 2.2 + * + * @link www.doctrine-project.org + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class WhenClause extends Node +{ + public $caseConditionExpression = null; + public $thenScalarExpression = null; + + public function __construct($caseConditionExpression, $thenScalarExpression) + { + $this->caseConditionExpression = $caseConditionExpression; + $this->thenScalarExpression = $thenScalarExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkWhenClauseExpression($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/WhereClause.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/WhereClause.php new file mode 100644 index 0000000..0b9f160 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/AST/WhereClause.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * WhereClause ::= "WHERE" ConditionalExpression + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class WhereClause extends Node +{ + public $conditionalExpression; + + public function __construct($conditionalExpression) + { + $this->conditionalExpression = $conditionalExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkWhereClause($this); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php new file mode 100644 index 0000000..d20905a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php @@ -0,0 +1,70 @@ +. + */ + +namespace Doctrine\ORM\Query\Exec; + +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Cache\QueryCacheProfile; + +/** + * Base class for SQL statement executors. + * + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @todo Rename: AbstractSQLExecutor + */ +abstract class AbstractSqlExecutor +{ + /** + * @var array + */ + protected $_sqlStatements; + + /** + * @var QueryCacheProfile + */ + protected $queryCacheProfile; + + /** + * Gets the SQL statements that are executed by the executor. + * + * @return array All the SQL update statements. + */ + public function getSqlStatements() + { + return $this->_sqlStatements; + } + + public function setQueryCacheProfile(QueryCacheProfile $qcp) + { + $this->queryCacheProfile = $qcp; + } + + /** + * Executes all sql statements. + * + * @param \Doctrine\DBAL\Connection $conn The database connection that is used to execute the queries. + * @param array $params The parameters. + * @param array $types The parameter types. + * @return \Doctrine\DBAL\Driver\Statement + */ + abstract public function execute(Connection $conn, array $params, array $types); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php new file mode 100644 index 0000000..d40b37e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php @@ -0,0 +1,133 @@ +. + */ + +namespace Doctrine\ORM\Query\Exec; + +use Doctrine\DBAL\Connection, + Doctrine\ORM\Query\AST; + +/** + * Executes the SQL statements for bulk DQL DELETE statements on classes in + * Class Table Inheritance (JOINED). + * + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + */ +class MultiTableDeleteExecutor extends AbstractSqlExecutor +{ + private $_createTempTableSql; + private $_dropTempTableSql; + private $_insertSql; + + /** + * Initializes a new MultiTableDeleteExecutor. + * + * @param Node $AST The root AST node of the DQL query. + * @param SqlWalker $sqlWalker The walker used for SQL generation from the AST. + * @internal Any SQL construction and preparation takes place in the constructor for + * best performance. With a query cache the executor will be cached. + */ + public function __construct(AST\Node $AST, $sqlWalker) + { + $em = $sqlWalker->getEntityManager(); + $conn = $em->getConnection(); + $platform = $conn->getDatabasePlatform(); + $quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); + + $primaryClass = $em->getClassMetadata($AST->deleteClause->abstractSchemaName); + $primaryDqlAlias = $AST->deleteClause->aliasIdentificationVariable; + $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); + + $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); + $idColumnNames = $rootClass->getIdentifierColumnNames(); + $idColumnList = implode(', ', $idColumnNames); + + // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() + $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $primaryDqlAlias); + + $this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')' + . ' SELECT t0.' . implode(', t0.', $idColumnNames); + + $rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $primaryDqlAlias); + $fromClause = new AST\FromClause(array(new AST\IdentificationVariableDeclaration($rangeDecl, null, array()))); + $this->_insertSql .= $sqlWalker->walkFromClause($fromClause); + + // Append WHERE clause, if there is one. + if ($AST->whereClause) { + $this->_insertSql .= $sqlWalker->walkWhereClause($AST->whereClause); + } + + // 2. Create ID subselect statement used in DELETE ... WHERE ... IN (subselect) + $idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable; + + // 3. Create and store DELETE statements + $classNames = array_merge($primaryClass->parentClasses, array($primaryClass->name), $primaryClass->subClasses); + foreach (array_reverse($classNames) as $className) { + $tableName = $quoteStrategy->getTableName($em->getClassMetadata($className), $platform); + $this->_sqlStatements[] = 'DELETE FROM ' . $tableName + . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')'; + } + + // 4. Store DDL for temporary identifier table. + $columnDefinitions = array(); + foreach ($idColumnNames as $idColumnName) { + $columnDefinitions[$idColumnName] = array( + 'notnull' => true, + 'type' => \Doctrine\DBAL\Types\Type::getType($rootClass->getTypeOfColumn($idColumnName)) + ); + } + $this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' + . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; + $this->_dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable); + } + + /** + * {@inheritDoc} + */ + public function execute(Connection $conn, array $params, array $types) + { + $numDeleted = 0; + + // Create temporary id table + $conn->executeUpdate($this->_createTempTableSql); + + try { + // Insert identifiers + $numDeleted = $conn->executeUpdate($this->_insertSql, $params, $types); + + // Execute DELETE statements + foreach ($this->_sqlStatements as $sql) { + $conn->executeUpdate($sql); + } + } catch (\Exception $exception) { + // FAILURE! Drop temporary table to avoid possible collisions + $conn->executeUpdate($this->_dropTempTableSql); + + // Re-throw exception + throw $exception; + } + + // Drop temporary table + $conn->executeUpdate($this->_dropTempTableSql); + + return $numDeleted; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php new file mode 100644 index 0000000..7dc3fed --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php @@ -0,0 +1,195 @@ +. + */ + +namespace Doctrine\ORM\Query\Exec; + +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Types\Type; + +use Doctrine\ORM\Query\ParameterTypeInferer; +use Doctrine\ORM\Query\AST; + +/** + * Executes the SQL statements for bulk DQL UPDATE statements on classes in + * Class Table Inheritance (JOINED). + * + * @author Roman Borschel + * @since 2.0 + */ +class MultiTableUpdateExecutor extends AbstractSqlExecutor +{ + private $_createTempTableSql; + private $_dropTempTableSql; + private $_insertSql; + private $_sqlParameters = array(); + private $_numParametersInUpdateClause = 0; + + /** + * Initializes a new MultiTableUpdateExecutor. + * + * @param Node $AST The root AST node of the DQL query. + * @param SqlWalker $sqlWalker The walker used for SQL generation from the AST. + * @internal Any SQL construction and preparation takes place in the constructor for + * best performance. With a query cache the executor will be cached. + */ + public function __construct(AST\Node $AST, $sqlWalker) + { + $em = $sqlWalker->getEntityManager(); + $conn = $em->getConnection(); + $platform = $conn->getDatabasePlatform(); + $quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); + + $updateClause = $AST->updateClause; + $primaryClass = $sqlWalker->getEntityManager()->getClassMetadata($updateClause->abstractSchemaName); + $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); + + $updateItems = $updateClause->updateItems; + + $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); + $idColumnNames = $rootClass->getIdentifierColumnNames(); + $idColumnList = implode(', ', $idColumnNames); + + // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() + $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $updateClause->aliasIdentificationVariable); + + $this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')' + . ' SELECT t0.' . implode(', t0.', $idColumnNames); + + $rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $updateClause->aliasIdentificationVariable); + $fromClause = new AST\FromClause(array(new AST\IdentificationVariableDeclaration($rangeDecl, null, array()))); + + $this->_insertSql .= $sqlWalker->walkFromClause($fromClause); + + // 2. Create ID subselect statement used in UPDATE ... WHERE ... IN (subselect) + $idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable; + + // 3. Create and store UPDATE statements + $classNames = array_merge($primaryClass->parentClasses, array($primaryClass->name), $primaryClass->subClasses); + $i = -1; + + foreach (array_reverse($classNames) as $className) { + $affected = false; + $class = $em->getClassMetadata($className); + $updateSql = 'UPDATE ' . $quoteStrategy->getTableName($class, $platform) . ' SET '; + + foreach ($updateItems as $updateItem) { + $field = $updateItem->pathExpression->field; + + if (isset($class->fieldMappings[$field]) && ! isset($class->fieldMappings[$field]['inherited']) || + isset($class->associationMappings[$field]) && ! isset($class->associationMappings[$field]['inherited'])) { + $newValue = $updateItem->newValue; + + if ( ! $affected) { + $affected = true; + ++$i; + } else { + $updateSql .= ', '; + } + + $updateSql .= $sqlWalker->walkUpdateItem($updateItem); + + //FIXME: parameters can be more deeply nested. traverse the tree. + //FIXME (URGENT): With query cache the parameter is out of date. Move to execute() stage. + if ($newValue instanceof AST\InputParameter) { + $parameterName = $newValue->name; + $parameter = $sqlWalker->getQuery()->getParameter($parameterName); + + $value = $sqlWalker->getQuery()->processParameterValue($parameter->getValue()); + $type = ($parameter->getValue() === $value) + ? $parameter->getType() + : ParameterTypeInferer::inferType($value); + + $this->_sqlParameters[$i]['parameters'][] = $value; + $this->_sqlParameters[$i]['types'][] = $type; + + ++$this->_numParametersInUpdateClause; + } + } + } + + if ($affected) { + $this->_sqlStatements[$i] = $updateSql . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')'; + } + } + + // Append WHERE clause to insertSql, if there is one. + if ($AST->whereClause) { + $this->_insertSql .= $sqlWalker->walkWhereClause($AST->whereClause); + } + + // 4. Store DDL for temporary identifier table. + $columnDefinitions = array(); + + foreach ($idColumnNames as $idColumnName) { + $columnDefinitions[$idColumnName] = array( + 'notnull' => true, + 'type' => Type::getType($rootClass->getTypeOfColumn($idColumnName)) + ); + } + + $this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' + . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; + + $this->_dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable); + } + + /** + * {@inheritDoc} + */ + public function execute(Connection $conn, array $params, array $types) + { + $numUpdated = 0; + + // Create temporary id table + $conn->executeUpdate($this->_createTempTableSql); + + try { + // Insert identifiers. Parameters from the update clause are cut off. + $numUpdated = $conn->executeUpdate( + $this->_insertSql, + array_slice($params, $this->_numParametersInUpdateClause), + array_slice($types, $this->_numParametersInUpdateClause) + ); + + // Execute UPDATE statements + for ($i=0, $count=count($this->_sqlStatements); $i<$count; ++$i) { + $parameters = array(); + $types = array(); + + if (isset($this->_sqlParameters[$i])) { + $parameters = isset($this->_sqlParameters[$i]['parameters']) ? $this->_sqlParameters[$i]['parameters'] : array(); + $types = isset($this->_sqlParameters[$i]['types']) ? $this->_sqlParameters[$i]['types'] : array(); + } + + $conn->executeUpdate($this->_sqlStatements[$i], $parameters, $types); + } + } catch (\Exception $exception) { + // FAILURE! Drop temporary table to avoid possible collisions + $conn->executeUpdate($this->_dropTempTableSql); + + // Re-throw exception + throw $exception; + } + + // Drop temporary table + $conn->executeUpdate($this->_dropTempTableSql); + + return $numUpdated; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/SingleSelectExecutor.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/SingleSelectExecutor.php new file mode 100644 index 0000000..61ae2fa --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/SingleSelectExecutor.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\ORM\Query\Exec; + +use Doctrine\DBAL\Connection, + Doctrine\ORM\Query\AST\SelectStatement, + Doctrine\ORM\Query\SqlWalker; + +/** + * Executor that executes the SQL statement for simple DQL SELECT statements. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @author Roman Borschel + * @link www.doctrine-project.org + * @since 2.0 + */ +class SingleSelectExecutor extends AbstractSqlExecutor +{ + public function __construct(SelectStatement $AST, SqlWalker $sqlWalker) + { + $this->_sqlStatements = $sqlWalker->walkSelectStatement($AST); + } + + /** + * {@inheritDoc} + */ + public function execute(Connection $conn, array $params, array $types) + { + return $conn->executeQuery($this->_sqlStatements, $params, $types, $this->queryCacheProfile); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/SingleTableDeleteUpdateExecutor.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/SingleTableDeleteUpdateExecutor.php new file mode 100644 index 0000000..b9bfd6f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Exec/SingleTableDeleteUpdateExecutor.php @@ -0,0 +1,53 @@ +. + */ + +namespace Doctrine\ORM\Query\Exec; + +use Doctrine\DBAL\Connection, + Doctrine\ORM\Query\AST; + +/** + * Executor that executes the SQL statements for DQL DELETE/UPDATE statements on classes + * that are mapped to a single table. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @author Roman Borschel + * @link www.doctrine-project.org + * @since 2.0 + * @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor. + */ +class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor +{ + public function __construct(AST\Node $AST, $sqlWalker) + { + if ($AST instanceof AST\UpdateStatement) { + $this->_sqlStatements = $sqlWalker->walkUpdateStatement($AST); + } else if ($AST instanceof AST\DeleteStatement) { + $this->_sqlStatements = $sqlWalker->walkDeleteStatement($AST); + } + } + + /** + * {@inheritDoc} + */ + public function execute(Connection $conn, array $params, array $types) + { + return $conn->executeUpdate($this->_sqlStatements, $params, $types); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr.php new file mode 100644 index 0000000..5ffedba --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr.php @@ -0,0 +1,595 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * This class is used to generate DQL expressions via a set of PHP static functions + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + * @todo Rename: ExpressionBuilder + */ +class Expr +{ + /** + * Creates a conjunction of the given boolean expressions. + * + * Example: + * + * [php] + * // (u.type = ?1) AND (u.role = ?2) + * $expr->andX($expr->eq('u.type', ':1'), $expr->eq('u.role', ':2')); + * + * @param \Doctrine\ORM\Query\Expr\Comparison | + * \Doctrine\ORM\Query\Expr\Func | + * \Doctrine\ORM\Query\Expr\Orx + * $x Optional clause. Defaults = null, but requires at least one defined when converting to string. + * @return Expr\Andx + */ + public function andX($x = null) + { + return new Expr\Andx(func_get_args()); + } + + /** + * Creates a disjunction of the given boolean expressions. + * + * Example: + * + * [php] + * // (u.type = ?1) OR (u.role = ?2) + * $q->where($q->expr()->orX('u.type = ?1', 'u.role = ?2')); + * + * @param mixed $x Optional clause. Defaults = null, but requires + * at least one defined when converting to string. + * @return Expr\Orx + */ + public function orX($x = null) + { + return new Expr\Orx(func_get_args()); + } + + /** + * Creates an ASCending order expression. + * + * @param $sort + * @return Expr\OrderBy + */ + public function asc($expr) + { + return new Expr\OrderBy($expr, 'ASC'); + } + + /** + * Creates a DESCending order expression. + * + * @param $sort + * @return Expr\OrderBy + */ + public function desc($expr) + { + return new Expr\OrderBy($expr, 'DESC'); + } + + /** + * Creates an equality comparison expression with the given arguments. + * + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a = . Example: + * + * [php] + * // u.id = ?1 + * $expr->eq('u.id', '?1'); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Comparison + */ + public function eq($x, $y) + { + return new Expr\Comparison($x, Expr\Comparison::EQ, $y); + } + + /** + * Creates an instance of Expr\Comparison, with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a <> . Example: + * + * [php] + * // u.id <> ?1 + * $q->where($q->expr()->neq('u.id', '?1')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Comparison + */ + public function neq($x, $y) + { + return new Expr\Comparison($x, Expr\Comparison::NEQ, $y); + } + + /** + * Creates an instance of Expr\Comparison, with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a < . Example: + * + * [php] + * // u.id < ?1 + * $q->where($q->expr()->lt('u.id', '?1')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Comparison + */ + public function lt($x, $y) + { + return new Expr\Comparison($x, Expr\Comparison::LT, $y); + } + + /** + * Creates an instance of Expr\Comparison, with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a <= . Example: + * + * [php] + * // u.id <= ?1 + * $q->where($q->expr()->lte('u.id', '?1')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Comparison + */ + public function lte($x, $y) + { + return new Expr\Comparison($x, Expr\Comparison::LTE, $y); + } + + /** + * Creates an instance of Expr\Comparison, with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a > . Example: + * + * [php] + * // u.id > ?1 + * $q->where($q->expr()->gt('u.id', '?1')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Comparison + */ + public function gt($x, $y) + { + return new Expr\Comparison($x, Expr\Comparison::GT, $y); + } + + /** + * Creates an instance of Expr\Comparison, with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a >= . Example: + * + * [php] + * // u.id >= ?1 + * $q->where($q->expr()->gte('u.id', '?1')); + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Comparison + */ + public function gte($x, $y) + { + return new Expr\Comparison($x, Expr\Comparison::GTE, $y); + } + + /** + * Creates an instance of AVG() function, with the given argument. + * + * @param mixed $x Argument to be used in AVG() function. + * @return Expr\Func + */ + public function avg($x) + { + return new Expr\Func('AVG', array($x)); + } + + /** + * Creates an instance of MAX() function, with the given argument. + * + * @param mixed $x Argument to be used in MAX() function. + * @return Expr\Func + */ + public function max($x) + { + return new Expr\Func('MAX', array($x)); + } + + /** + * Creates an instance of MIN() function, with the given argument. + * + * @param mixed $x Argument to be used in MIN() function. + * @return Expr\Func + */ + public function min($x) + { + return new Expr\Func('MIN', array($x)); + } + + /** + * Creates an instance of COUNT() function, with the given argument. + * + * @param mixed $x Argument to be used in COUNT() function. + * @return Expr\Func + */ + public function count($x) + { + return new Expr\Func('COUNT', array($x)); + } + + /** + * Creates an instance of COUNT(DISTINCT) function, with the given argument. + * + * @param mixed $x Argument to be used in COUNT(DISTINCT) function. + * @return string + */ + public function countDistinct($x) + { + return 'COUNT(DISTINCT ' . implode(', ', func_get_args()) . ')'; + } + + /** + * Creates an instance of EXISTS() function, with the given DQL Subquery. + * + * @param mixed $subquery DQL Subquery to be used in EXISTS() function. + * @return Expr\Func + */ + public function exists($subquery) + { + return new Expr\Func('EXISTS', array($subquery)); + } + + /** + * Creates an instance of ALL() function, with the given DQL Subquery. + * + * @param mixed $subquery DQL Subquery to be used in ALL() function. + * @return Expr\Func + */ + public function all($subquery) + { + return new Expr\Func('ALL', array($subquery)); + } + + /** + * Creates a SOME() function expression with the given DQL subquery. + * + * @param mixed $subquery DQL Subquery to be used in SOME() function. + * @return Expr\Func + */ + public function some($subquery) + { + return new Expr\Func('SOME', array($subquery)); + } + + /** + * Creates an ANY() function expression with the given DQL subquery. + * + * @param mixed $subquery DQL Subquery to be used in ANY() function. + * @return Expr\Func + */ + public function any($subquery) + { + return new Expr\Func('ANY', array($subquery)); + } + + /** + * Creates a negation expression of the given restriction. + * + * @param mixed $restriction Restriction to be used in NOT() function. + * @return Expr\Func + */ + public function not($restriction) + { + return new Expr\Func('NOT', array($restriction)); + } + + /** + * Creates an ABS() function expression with the given argument. + * + * @param mixed $x Argument to be used in ABS() function. + * @return Expr\Func + */ + public function abs($x) + { + return new Expr\Func('ABS', array($x)); + } + + /** + * Creates a product mathematical expression with the given arguments. + * + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a * . Example: + * + * [php] + * // u.salary * u.percentAnualSalaryIncrease + * $q->expr()->prod('u.salary', 'u.percentAnualSalaryIncrease') + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Math + */ + public function prod($x, $y) + { + return new Expr\Math($x, '*', $y); + } + + /** + * Creates a difference mathematical expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a - . Example: + * + * [php] + * // u.monthlySubscriptionCount - 1 + * $q->expr()->diff('u.monthlySubscriptionCount', '1') + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Math + */ + public function diff($x, $y) + { + return new Expr\Math($x, '-', $y); + } + + /** + * Creates a sum mathematical expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a + . Example: + * + * [php] + * // u.numChildren + 1 + * $q->expr()->diff('u.numChildren', '1') + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Math + */ + public function sum($x, $y) + { + return new Expr\Math($x, '+', $y); + } + + /** + * Creates a quotient mathematical expression with the given arguments. + * First argument is considered the left expression and the second is the right expression. + * When converted to string, it will generated a / . Example: + * + * [php] + * // u.total / u.period + * $expr->quot('u.total', 'u.period') + * + * @param mixed $x Left expression + * @param mixed $y Right expression + * @return Expr\Math + */ + public function quot($x, $y) + { + return new Expr\Math($x, '/', $y); + } + + /** + * Creates a SQRT() function expression with the given argument. + * + * @param mixed $x Argument to be used in SQRT() function. + * @return Expr\Func + */ + public function sqrt($x) + { + return new Expr\Func('SQRT', array($x)); + } + + /** + * Creates an IN() expression with the given arguments. + * + * @param string $x Field in string format to be restricted by IN() function + * @param mixed $y Argument to be used in IN() function. + * @return Expr\Func + */ + public function in($x, $y) + { + if (is_array($y)) { + foreach ($y as &$literal) { + if ( ! ($literal instanceof Expr\Literal)) { + $literal = $this->_quoteLiteral($literal); + } + } + } + return new Expr\Func($x . ' IN', (array) $y); + } + + /** + * Creates a NOT IN() expression with the given arguments. + * + * @param string $x Field in string format to be restricted by NOT IN() function + * @param mixed $y Argument to be used in NOT IN() function. + * @return Expr\Func + */ + public function notIn($x, $y) + { + if (is_array($y)) { + foreach ($y as &$literal) { + if ( ! ($literal instanceof Expr\Literal)) { + $literal = $this->_quoteLiteral($literal); + } + } + } + return new Expr\Func($x . ' NOT IN', (array) $y); + } + + /** + * Creates an IS NULL expression with the given arguments. + * + * @param string $x Field in string format to be restricted by IS NULL + * @return string + */ + public function isNull($x) + { + return $x . ' IS NULL'; + } + + /** + * Creates an IS NOT NULL expression with the given arguments. + * + * @param string $x Field in string format to be restricted by IS NOT NULL + * @return string + */ + public function isNotNull($x) + { + return $x . ' IS NOT NULL'; + } + + /** + * Creates a LIKE() comparison expression with the given arguments. + * + * @param string $x Field in string format to be inspected by LIKE() comparison. + * @param mixed $y Argument to be used in LIKE() comparison. + * @return Expr\Comparison + */ + public function like($x, $y) + { + return new Expr\Comparison($x, 'LIKE', $y); + } + + /** + * Creates a CONCAT() function expression with the given arguments. + * + * @param mixed $x First argument to be used in CONCAT() function. + * @param mixed $x Second argument to be used in CONCAT() function. + * @return Expr\Func + */ + public function concat($x, $y) + { + return new Expr\Func('CONCAT', array($x, $y)); + } + + /** + * Creates a SUBSTRING() function expression with the given arguments. + * + * @param mixed $x Argument to be used as string to be cropped by SUBSTRING() function. + * @param integer $from Initial offset to start cropping string. May accept negative values. + * @param integer $len Length of crop. May accept negative values. + * @return Expr\Func + */ + public function substring($x, $from, $len = null) + { + $args = array($x, $from); + if (null !== $len) { + $args[] = $len; + } + return new Expr\Func('SUBSTRING', $args); + } + + /** + * Creates a LOWER() function expression with the given argument. + * + * @param mixed $x Argument to be used in LOWER() function. + * @return Expr\Func A LOWER function expression. + */ + public function lower($x) + { + return new Expr\Func('LOWER', array($x)); + } + + /** + * Creates an UPPER() function expression with the given argument. + * + * @param mixed $x Argument to be used in UPPER() function. + * @return Expr\Func An UPPER function expression. + */ + public function upper($x) + { + return new Expr\Func('UPPER', array($x)); + } + + /** + * Creates a LENGTH() function expression with the given argument. + * + * @param mixed $x Argument to be used as argument of LENGTH() function. + * @return Expr\Func A LENGTH function expression. + */ + public function length($x) + { + return new Expr\Func('LENGTH', array($x)); + } + + /** + * Creates a literal expression of the given argument. + * + * @param mixed $literal Argument to be converted to literal. + * @return Expr\Literal + */ + public function literal($literal) + { + return new Expr\Literal($this->_quoteLiteral($literal)); + } + + /** + * Quotes a literal value, if necessary, according to the DQL syntax. + * + * @param mixed $literal The literal value. + * @return string + */ + private function _quoteLiteral($literal) + { + if (is_numeric($literal) && !is_string($literal)) { + return (string) $literal; + } else if (is_bool($literal)) { + return $literal ? "true" : "false"; + } else { + return "'" . str_replace("'", "''", $literal) . "'"; + } + } + + /** + * Creates an instance of BETWEEN() function, with the given argument. + * + * @param mixed $val Valued to be inspected by range values. + * @param integer $x Starting range value to be used in BETWEEN() function. + * @param integer $y End point value to be used in BETWEEN() function. + * @return Expr\Func A BETWEEN expression. + */ + public function between($val, $x, $y) + { + return $val . ' BETWEEN ' . $x . ' AND ' . $y; + } + + /** + * Creates an instance of TRIM() function, with the given argument. + * + * @param mixed $x Argument to be used as argument of TRIM() function. + * @return Expr\Func a TRIM expression. + */ + public function trim($x) + { + return new Expr\Func('TRIM', $x); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Andx.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Andx.php new file mode 100644 index 0000000..10b5e8e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Andx.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for building DQL and parts + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Andx extends Composite +{ + /** + * @var string + */ + protected $separator = ' AND '; + + /** + * @var array + */ + protected $allowedClasses = array( + 'Doctrine\ORM\Query\Expr\Comparison', + 'Doctrine\ORM\Query\Expr\Func', + 'Doctrine\ORM\Query\Expr\Orx', + 'Doctrine\ORM\Query\Expr\Andx', + ); + + /** + * @return array + */ + public function getParts() + { + return $this->parts; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Base.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Base.php new file mode 100644 index 0000000..a2bc98c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Base.php @@ -0,0 +1,121 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Abstract base Expr class for building DQL parts + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +abstract class Base +{ + /** + * @var string + */ + protected $preSeparator = '('; + + /** + * @var string + */ + protected $separator = ', '; + + /** + * @var string + */ + protected $postSeparator = ')'; + + /** + * @var array + */ + protected $allowedClasses = array(); + + /** + * @var array + */ + protected $parts = array(); + + /** + * @param array $args + */ + public function __construct($args = array()) + { + $this->addMultiple($args); + } + + /** + * @param array $args + * @return Base + */ + public function addMultiple($args = array()) + { + foreach ((array) $args as $arg) { + $this->add($arg); + } + + return $this; + } + + /** + * @param mixed $arg + * @return Base + */ + public function add($arg) + { + if ( $arg !== null || ($arg instanceof self && $arg->count() > 0) ) { + // If we decide to keep Expr\Base instances, we can use this check + if ( ! is_string($arg)) { + $class = get_class($arg); + + if ( ! in_array($class, $this->allowedClasses)) { + throw new \InvalidArgumentException("Expression of type '$class' not allowed in this context."); + } + } + + $this->parts[] = $arg; + } + + return $this; + } + + /** + * @return integer + */ + public function count() + { + return count($this->parts); + } + + /** + * @return string + */ + public function __toString() + { + if ($this->count() == 1) { + return (string) $this->parts[0]; + } + + return $this->preSeparator . implode($this->separator, $this->parts) . $this->postSeparator; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Comparison.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Comparison.php new file mode 100644 index 0000000..52070df --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Comparison.php @@ -0,0 +1,101 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for DQL comparison expressions + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Comparison +{ + const EQ = '='; + const NEQ = '<>'; + const LT = '<'; + const LTE = '<='; + const GT = '>'; + const GTE = '>='; + + /** + * @var mixed + */ + protected $leftExpr; + + /** + * @var string + */ + protected $operator; + + /** + * @var mixed + */ + protected $rightExpr; + + /** + * Creates a comparison expression with the given arguments. + * + * @param mixed $leftExpr + * @param string $operator + * @param mixed $rightExpr + */ + public function __construct($leftExpr, $operator, $rightExpr) + { + $this->leftExpr = $leftExpr; + $this->operator = $operator; + $this->rightExpr = $rightExpr; + } + + /** + * @return mixed + */ + public function getLeftExpr() + { + return $this->leftExpr; + } + + /** + * @return string + */ + public function getOperator() + { + return $this->operator; + } + + /** + * @return mixed + */ + public function getRightExpr() + { + return $this->rightExpr; + } + + /** + * @return string + */ + public function __toString() + { + return $this->leftExpr . ' ' . $this->operator . ' ' . $this->rightExpr; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Composite.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Composite.php new file mode 100644 index 0000000..cc0e0e8 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Composite.php @@ -0,0 +1,72 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for building DQL and parts + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Composite extends Base +{ + /** + * @return string + */ + public function __toString() + { + if ($this->count() === 1) { + return (string) $this->parts[0]; + } + + $components = array(); + + foreach ($this->parts as $part) { + $components[] = $this->processQueryPart($part); + } + + return implode($this->separator, $components); + } + + + /** + * @param string $part + * @return string + */ + private function processQueryPart($part) + { + $queryPart = (string) $part; + + if (is_object($part) && $part instanceof self && $part->count() > 1) { + return $this->preSeparator . $queryPart . $this->postSeparator; + } + + // Fixes DDC-1237: User may have added a where item containing nested expression (with "OR" or "AND") + if (stripos($queryPart, ' OR ') !== false || stripos($queryPart, ' AND ') !== false) { + return $this->preSeparator . $queryPart . $this->postSeparator; + } + + return $queryPart; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/From.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/From.php new file mode 100644 index 0000000..3a37703 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/From.php @@ -0,0 +1,93 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for DQL from + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class From +{ + /** + * @var string + */ + protected $from; + + /** + * @var string + */ + protected $alias; + + /** + * @var string + */ + protected $indexBy; + + /** + * @param string $from The class name. + * @param string $alias The alias of the class. + * @param string $indexBy The index for the from. + */ + public function __construct($from, $alias, $indexBy = null) + { + $this->from = $from; + $this->alias = $alias; + $this->indexBy = $indexBy; + } + + /** + * @return string + */ + public function getFrom() + { + return $this->from; + } + + /** + * @return string + */ + public function getAlias() + { + return $this->alias; + } + + /** + * @return string + */ + public function getIndexBy() + { + return $this->indexBy; + } + + /** + * @return string + */ + public function __toString() + { + return $this->from . ' ' . $this->alias . + ($this->indexBy ? ' INDEX BY ' . $this->indexBy : ''); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Func.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Func.php new file mode 100644 index 0000000..6917dd2 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Func.php @@ -0,0 +1,79 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for generating DQL functions + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Func +{ + /** + * @var string + */ + protected $name; + + /** + * @var array + */ + protected $arguments; + + /** + * Creates a function, with the given argument. + * + * @param string $name + * @param array $arguments + */ + public function __construct($name, $arguments) + { + $this->name = $name; + $this->arguments = (array) $arguments; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return array + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * @return string + */ + public function __toString() + { + return $this->name . '(' . implode(', ', $this->arguments) . ')'; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/GroupBy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/GroupBy.php new file mode 100644 index 0000000..40bb838 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/GroupBy.php @@ -0,0 +1,51 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for building DQL Group By parts + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GroupBy extends Base +{ + /** + * @var string + */ + protected $preSeparator = ''; + + /** + * @var string + */ + protected $postSeparator = ''; + + /** + * @return array + */ + public function getParts() + { + return $this->parts; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Join.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Join.php new file mode 100644 index 0000000..41f454f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Join.php @@ -0,0 +1,147 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for DQL from + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Join +{ + const INNER_JOIN = 'INNER'; + const LEFT_JOIN = 'LEFT'; + + const ON = 'ON'; + const WITH = 'WITH'; + + /** + * @var string + */ + protected $joinType; + + /** + * @var string + */ + protected $join; + + /** + * @var string + */ + protected $alias; + + /** + * @var string + */ + protected $conditionType; + + /** + * @var string + */ + protected $condition; + + /** + * @var string + */ + protected $indexBy; + + /** + * @param string $joinType The condition type constant. Either INNER_JOIN or LEFT_JOIN. + * @param string $join The relationship to join + * @param string $alias The alias of the join + * @param string $conditionType The condition type constant. Either ON or WITH. + * @param string $condition The condition for the join + * @param string $indexBy The index for the join + */ + public function __construct($joinType, $join, $alias = null, $conditionType = null, $condition = null, $indexBy = null) + { + $this->joinType = $joinType; + $this->join = $join; + $this->alias = $alias; + $this->conditionType = $conditionType; + $this->condition = $condition; + $this->indexBy = $indexBy; + } + + /** + * @return string + */ + public function getJoinType() + { + return $this->joinType; + } + + /** + * @return string + */ + public function getJoin() + { + return $this->join; + } + + /** + * @return string + */ + public function getAlias() + { + return $this->alias; + } + + /** + * @return string + */ + public function getConditionType() + { + return $this->conditionType; + } + + /** + * @return string + */ + public function getCondition() + { + return $this->condition; + } + + /** + * @return string + */ + public function getIndexBy() + { + return $this->indexBy; + } + + + /** + * @return string + */ + public function __toString() + { + return strtoupper($this->joinType) . ' JOIN ' . $this->join + . ($this->alias ? ' ' . $this->alias : '') + . ($this->condition ? ' ' . strtoupper($this->conditionType) . ' ' . $this->condition : '') + . ($this->indexBy ? ' INDEX BY ' . $this->indexBy : ''); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Literal.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Literal.php new file mode 100644 index 0000000..991b044 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Literal.php @@ -0,0 +1,52 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for generating DQL functions + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Literal extends Base +{ + /** + * @var string + */ + protected $preSeparator = ''; + + /** + * @var string + */ + protected $postSeparator = ''; + + /** + * @return array + */ + public function getParts() + { + return $this->parts; + } + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Math.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Math.php new file mode 100644 index 0000000..a41c848 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Math.php @@ -0,0 +1,108 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for DQL math statements + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Math +{ + /** + * @var mixed + */ + protected $leftExpr; + + /** + * @var string + */ + protected $operator; + + /** + * @var mixed + */ + protected $rightExpr; + + /** + * Creates a mathematical expression with the given arguments. + * + * @param mixed $leftExpr + * @param string $operator + * @param mixed $rightExpr + */ + public function __construct($leftExpr, $operator, $rightExpr) + { + $this->leftExpr = $leftExpr; + $this->operator = $operator; + $this->rightExpr = $rightExpr; + } + + /** + * @return mixed + */ + public function getLeftExpr() + { + return $this->leftExpr; + } + + /** + * @return string + */ + public function getOperator() + { + return $this->operator; + } + + /** + * @return mixed + */ + public function getRightExpr() + { + return $this->rightExpr; + } + + /** + * @return string + */ + public function __toString() + { + // Adjusting Left Expression + $leftExpr = (string) $this->leftExpr; + + if ($this->leftExpr instanceof Math) { + $leftExpr = '(' . $leftExpr . ')'; + } + + // Adjusting Right Expression + $rightExpr = (string) $this->rightExpr; + + if ($this->rightExpr instanceof Math) { + $rightExpr = '(' . $rightExpr . ')'; + } + + return $leftExpr . ' ' . $this->operator . ' ' . $rightExpr; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/OrderBy.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/OrderBy.php new file mode 100644 index 0000000..e0e7ffc --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/OrderBy.php @@ -0,0 +1,103 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for building DQL Order By parts + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class OrderBy +{ + /** + * @var string + */ + protected $preSeparator = ''; + + /** + * @var string + */ + protected $separator = ', '; + + /** + * @var string + */ + protected $postSeparator = ''; + + /** + * @var array + */ + protected $allowedClasses = array(); + + /** + * @var array + */ + protected $parts = array(); + + /** + * @param string $sort + * @param string $order + */ + public function __construct($sort = null, $order = null) + { + if ($sort) { + $this->add($sort, $order); + } + } + + /** + * @param string $sort + * @param string $order + */ + public function add($sort, $order = null) + { + $order = ! $order ? 'ASC' : $order; + $this->parts[] = $sort . ' '. $order; + } + + /** + * @return integer + */ + public function count() + { + return count($this->parts); + } + + /** + * @return array + */ + public function getParts() + { + return $this->parts; + } + + /** + * @return string + */ + public function __tostring() + { + return $this->preSeparator . implode($this->separator, $this->parts) . $this->postSeparator; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Orx.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Orx.php new file mode 100644 index 0000000..caecba6 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Orx.php @@ -0,0 +1,56 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for building DQL OR clauses + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Orx extends Composite +{ + /** + * @var string + */ + protected $separator = ' OR '; + + /** + * @var array + */ + protected $allowedClasses = array( + 'Doctrine\ORM\Query\Expr\Comparison', + 'Doctrine\ORM\Query\Expr\Func', + 'Doctrine\ORM\Query\Expr\Andx', + 'Doctrine\ORM\Query\Expr\Orx', + ); + + /** + * @return array + */ + public function getParts() + { + return $this->parts; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Select.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Select.php new file mode 100644 index 0000000..804d797 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Expr/Select.php @@ -0,0 +1,58 @@ +. + */ + +namespace Doctrine\ORM\Query\Expr; + +/** + * Expression class for building DQL select statements + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Select extends Base +{ + /** + * @var string + */ + protected $preSeparator = ''; + + /** + * @var string + */ + protected $postSeparator = ''; + + /** + * @var array + */ + protected $allowedClasses = array( + 'Doctrine\ORM\Query\Expr\Func' + ); + + /** + * @return array + */ + public function getParts() + { + return $this->parts; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Filter/SQLFilter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Filter/SQLFilter.php new file mode 100644 index 0000000..5d6692b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Filter/SQLFilter.php @@ -0,0 +1,122 @@ +. + */ + +namespace Doctrine\ORM\Query\Filter; + +use Doctrine\ORM\EntityManager, + Doctrine\ORM\Mapping\ClassMetaData, + Doctrine\ORM\Query\ParameterTypeInferer; + +/** + * The base class that user defined filters should extend. + * + * Handles the setting and escaping of parameters. + * + * @author Alexander + * @author Benjamin Eberlei + * @abstract + */ +abstract class SQLFilter +{ + /** + * The entity manager. + * @var EntityManager + */ + private $em; + + /** + * Parameters for the filter. + * @var array + */ + private $parameters; + + /** + * Constructs the SQLFilter object. + * + * @param EntityManager $em The EM + */ + final public function __construct(EntityManager $em) + { + $this->em = $em; + } + + /** + * Sets a parameter that can be used by the filter. + * + * @param string $name Name of the parameter. + * @param string $value Value of the parameter. + * @param string $type The parameter type. If specified, the given value will be run through + * the type conversion of this type. This is usually not needed for + * strings and numeric types. + * + * @return SQLFilter The current SQL filter. + */ + final public function setParameter($name, $value, $type = null) + { + if (null === $type) { + $type = ParameterTypeInferer::inferType($value); + } + + $this->parameters[$name] = array('value' => $value, 'type' => $type); + + // Keep the parameters sorted for the hash + ksort($this->parameters); + + // The filter collection of the EM is now dirty + $this->em->getFilters()->setFiltersStateDirty(); + + return $this; + } + + /** + * Gets a parameter to use in a query. + * + * The function is responsible for the right output escaping to use the + * value in a query. + * + * @param string $name Name of the parameter. + * + * @return string The SQL escaped parameter to use in a query. + */ + final public function getParameter($name) + { + if (!isset($this->parameters[$name])) { + throw new \InvalidArgumentException("Parameter '" . $name . "' does not exist."); + } + + return $this->em->getConnection()->quote($this->parameters[$name]['value'], $this->parameters[$name]['type']); + } + + /** + * Returns as string representation of the SQLFilter parameters (the state). + * + * @return string String representation of the SQLFilter. + */ + final public function __toString() + { + return serialize($this->parameters); + } + + /** + * Gets the SQL query part to add to a query. + * + * @return string The constraint SQL if there is available, empty string otherwise + */ + abstract public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/FilterCollection.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/FilterCollection.php new file mode 100644 index 0000000..fc47eb1 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/FilterCollection.php @@ -0,0 +1,198 @@ +. + */ + +namespace Doctrine\ORM\Query; + +use Doctrine\ORM\Configuration, + Doctrine\ORM\EntityManager; + +/** + * Collection class for all the query filters. + * + * @author Alexander + */ +class FilterCollection +{ + /* Filter STATES */ + /** + * A filter object is in CLEAN state when it has no changed parameters. + */ + const FILTERS_STATE_CLEAN = 1; + + /** + * A filter object is in DIRTY state when it has changed parameters. + */ + const FILTERS_STATE_DIRTY = 2; + + /** + * The used Configuration. + * + * @var Doctrine\ORM\Configuration + */ + private $config; + + /** + * The EntityManager that "owns" this FilterCollection instance. + * + * @var Doctrine\ORM\EntityManager + */ + private $em; + + /** + * Instances of enabled filters. + * + * @var array + */ + private $enabledFilters = array(); + + /** + * @var string The filter hash from the last time the query was parsed. + */ + private $filterHash; + + /** + * @var integer $state The current state of this filter + */ + private $filtersState = self::FILTERS_STATE_CLEAN; + + /** + * Constructor. + * + * @param EntityManager $em + */ + public function __construct(EntityManager $em) + { + $this->em = $em; + $this->config = $em->getConfiguration(); + } + + /** + * Get all the enabled filters. + * + * @return array The enabled filters. + */ + public function getEnabledFilters() + { + return $this->enabledFilters; + } + + /** + * Enables a filter from the collection. + * + * @param string $name Name of the filter. + * + * @throws \InvalidArgumentException If the filter does not exist. + * + * @return SQLFilter The enabled filter. + */ + public function enable($name) + { + if (null === $filterClass = $this->config->getFilterClassName($name)) { + throw new \InvalidArgumentException("Filter '" . $name . "' does not exist."); + } + + if (!isset($this->enabledFilters[$name])) { + $this->enabledFilters[$name] = new $filterClass($this->em); + + // Keep the enabled filters sorted for the hash + ksort($this->enabledFilters); + + // Now the filter collection is dirty + $this->filtersState = self::FILTERS_STATE_DIRTY; + } + + return $this->enabledFilters[$name]; + } + + /** + * Disables a filter. + * + * @param string $name Name of the filter. + * + * @return SQLFilter The disabled filter. + * + * @throws \InvalidArgumentException If the filter does not exist. + */ + public function disable($name) + { + // Get the filter to return it + $filter = $this->getFilter($name); + + unset($this->enabledFilters[$name]); + + // Now the filter collection is dirty + $this->filtersState = self::FILTERS_STATE_DIRTY; + + return $filter; + } + + /** + * Get an enabled filter from the collection. + * + * @param string $name Name of the filter. + * + * @return SQLFilter The filter. + * + * @throws \InvalidArgumentException If the filter is not enabled. + */ + public function getFilter($name) + { + if (!isset($this->enabledFilters[$name])) { + throw new \InvalidArgumentException("Filter '" . $name . "' is not enabled."); + } + + return $this->enabledFilters[$name]; + } + + /** + * @return boolean True, if the filter collection is clean. + */ + public function isClean() + { + return self::FILTERS_STATE_CLEAN === $this->filtersState; + } + + /** + * Generates a string of currently enabled filters to use for the cache id. + * + * @return string + */ + public function getHash() + { + // If there are only clean filters, the previous hash can be returned + if (self::FILTERS_STATE_CLEAN === $this->filtersState) { + return $this->filterHash; + } + + $filterHash = ''; + foreach ($this->enabledFilters as $name => $filter) { + $filterHash .= $name . $filter; + } + + return $filterHash; + } + + /** + * Set the filter state to dirty. + */ + public function setFiltersStateDirty() + { + $this->filtersState = self::FILTERS_STATE_DIRTY; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Lexer.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Lexer.php new file mode 100644 index 0000000..beafa7d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Lexer.php @@ -0,0 +1,206 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * Scans a DQL query for tokens. + * + * @author Guilherme Blanco + * @author Janne Vanhala + * @author Roman Borschel + * @since 2.0 + */ +class Lexer extends \Doctrine\Common\Lexer +{ + // All tokens that are not valid identifiers must be < 100 + const T_NONE = 1; + const T_INTEGER = 2; + const T_STRING = 3; + const T_INPUT_PARAMETER = 4; + const T_FLOAT = 5; + const T_CLOSE_PARENTHESIS = 6; + const T_OPEN_PARENTHESIS = 7; + const T_COMMA = 8; + const T_DIVIDE = 9; + const T_DOT = 10; + const T_EQUALS = 11; + const T_GREATER_THAN = 12; + const T_LOWER_THAN = 13; + const T_MINUS = 14; + const T_MULTIPLY = 15; + const T_NEGATE = 16; + const T_PLUS = 17; + const T_OPEN_CURLY_BRACE = 18; + const T_CLOSE_CURLY_BRACE = 19; + + // All tokens that are also identifiers should be >= 100 + const T_IDENTIFIER = 100; + const T_ALL = 101; + const T_AND = 102; + const T_ANY = 103; + const T_AS = 104; + const T_ASC = 105; + const T_AVG = 106; + const T_BETWEEN = 107; + const T_BOTH = 108; + const T_BY = 109; + const T_CASE = 110; + const T_COALESCE = 111; + const T_COUNT = 112; + const T_DELETE = 113; + const T_DESC = 114; + const T_DISTINCT = 115; + const T_ELSE = 116; + const T_EMPTY = 117; + const T_END = 118; + const T_ESCAPE = 119; + const T_EXISTS = 120; + const T_FALSE = 121; + const T_FROM = 122; + const T_GROUP = 123; + const T_HAVING = 124; + const T_HIDDEN = 125; + const T_IN = 126; + const T_INDEX = 127; + const T_INNER = 128; + const T_INSTANCE = 129; + const T_IS = 130; + const T_JOIN = 131; + const T_LEADING = 132; + const T_LEFT = 133; + const T_LIKE = 134; + const T_MAX = 135; + const T_MEMBER = 136; + const T_MIN = 137; + const T_NOT = 138; + const T_NULL = 139; + const T_NULLIF = 140; + const T_OF = 141; + const T_OR = 142; + const T_ORDER = 143; + const T_OUTER = 144; + const T_SELECT = 145; + const T_SET = 146; + const T_SOME = 147; + const T_SUM = 148; + const T_THEN = 149; + const T_TRAILING = 150; + const T_TRUE = 151; + const T_UPDATE = 152; + const T_WHEN = 153; + const T_WHERE = 154; + const T_WITH = 155; + const T_PARTIAL = 156; + + /** + * Creates a new query scanner object. + * + * @param string $input a query string + */ + public function __construct($input) + { + $this->setInput($input); + } + + /** + * @inheritdoc + */ + protected function getCatchablePatterns() + { + return array( + '[a-z_\\\][a-z0-9_\:\\\]*[a-z0-9_]{1}', + '(?:[0-9]+(?:[\.][0-9]+)*)(?:e[+-]?[0-9]+)?', + "'(?:[^']|'')*'", + '\?[0-9]*|:[a-z]{1}[a-z0-9_]{0,}' + ); + } + + /** + * @inheritdoc + */ + protected function getNonCatchablePatterns() + { + return array('\s+', '(.)'); + } + + /** + * @inheritdoc + */ + protected function getType(&$value) + { + $type = self::T_NONE; + + switch (true) { + // Recognize numeric values + case (is_numeric($value)): + if (strpos($value, '.') !== false || stripos($value, 'e') !== false) { + return self::T_FLOAT; + } + + return self::T_INTEGER; + + // Recognize quoted strings + case ($value[0] === "'"): + $value = str_replace("''", "'", substr($value, 1, strlen($value) - 2)); + + return self::T_STRING; + + // Recognize identifiers + case (ctype_alpha($value[0]) || $value[0] === '_'): + $name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($value); + + if (defined($name)) { + $type = constant($name); + + if ($type > 100) { + return $type; + } + } + + return self::T_IDENTIFIER; + + // Recognize input parameters + case ($value[0] === '?' || $value[0] === ':'): + return self::T_INPUT_PARAMETER; + + // Recognize symbols + case ($value === '.'): return self::T_DOT; + case ($value === ','): return self::T_COMMA; + case ($value === '('): return self::T_OPEN_PARENTHESIS; + case ($value === ')'): return self::T_CLOSE_PARENTHESIS; + case ($value === '='): return self::T_EQUALS; + case ($value === '>'): return self::T_GREATER_THAN; + case ($value === '<'): return self::T_LOWER_THAN; + case ($value === '+'): return self::T_PLUS; + case ($value === '-'): return self::T_MINUS; + case ($value === '*'): return self::T_MULTIPLY; + case ($value === '/'): return self::T_DIVIDE; + case ($value === '!'): return self::T_NEGATE; + case ($value === '{'): return self::T_OPEN_CURLY_BRACE; + case ($value === '}'): return self::T_CLOSE_CURLY_BRACE; + + // Default + default: + // Do nothing + } + + return $type; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parameter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parameter.php new file mode 100644 index 0000000..57813cb --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parameter.php @@ -0,0 +1,101 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * Define a Query Parameter + * + * @link www.doctrine-project.org + * @since 2.3 + * @author Guilherme Blanco + */ +class Parameter +{ + /** + * @var string Parameter name + */ + private $name; + + /** + * @var mixed Parameter value + */ + private $value; + + /** + * @var mixed Parameter type + */ + private $type; + + /** + * Constructor. + * + * @param string $name Parameter name + * @param mixed $value Parameter value + * @param mixed $type Parameter type + */ + public function __construct($name, $value, $type = null) + { + $this->name = trim($name, ':'); + + $this->setValue($value, $type); + } + + /** + * Retrieve the Parameter name. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Retrieve the Parameter value. + * + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + /** + * Retrieve the Parameter type. + * + * @return mixed + */ + public function getType() + { + return $this->type; + } + + /** + * Define the Parameter value. + * + * @param mixed $value Parameter value + * @param mixed $type Parameter type + */ + public function setValue($value, $type = null) + { + $this->value = $value; + $this->type = $type ?: ParameterTypeInferer::inferType($value); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ParameterTypeInferer.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ParameterTypeInferer.php new file mode 100644 index 0000000..45a0aab --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ParameterTypeInferer.php @@ -0,0 +1,65 @@ +. + */ + +namespace Doctrine\ORM\Query; + +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Types\Type; + +/** + * Provides an enclosed support for parameter infering. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ParameterTypeInferer +{ + /** + * Infer type of a given value, returning a compatible constant: + * - Type (\Doctrine\DBAL\Types\Type::*) + * - Connection (\Doctrine\DBAL\Connection::PARAM_*) + * + * @param mixed $value Parameter value + * + * @return mixed Parameter type constant + */ + public static function inferType($value) + { + if (is_integer($value)) { + return Type::INTEGER; + } + + if ($value instanceof \DateTime) { + return Type::DATETIME; + } + + if (is_array($value)) { + return is_integer(current($value)) + ? Connection::PARAM_INT_ARRAY + : Connection::PARAM_STR_ARRAY; + } + + return \PDO::PARAM_STR; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php new file mode 100644 index 0000000..1e1919d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php @@ -0,0 +1,3132 @@ +. + */ + +namespace Doctrine\ORM\Query; + +use Doctrine\ORM\Query; +use Doctrine\ORM\Mapping\ClassMetadata; + +/** + * An LL(*) recursive-descent parser for the context-free grammar of the Doctrine Query Language. + * Parses a DQL query, reports any errors in it, and generates an AST. + * + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Janne Vanhala + */ +class Parser +{ + /** READ-ONLY: Maps BUILT-IN string function names to AST class names. */ + private static $_STRING_FUNCTIONS = array( + 'concat' => 'Doctrine\ORM\Query\AST\Functions\ConcatFunction', + 'substring' => 'Doctrine\ORM\Query\AST\Functions\SubstringFunction', + 'trim' => 'Doctrine\ORM\Query\AST\Functions\TrimFunction', + 'lower' => 'Doctrine\ORM\Query\AST\Functions\LowerFunction', + 'upper' => 'Doctrine\ORM\Query\AST\Functions\UpperFunction', + 'identity' => 'Doctrine\ORM\Query\AST\Functions\IdentityFunction', + ); + + /** READ-ONLY: Maps BUILT-IN numeric function names to AST class names. */ + private static $_NUMERIC_FUNCTIONS = array( + 'length' => 'Doctrine\ORM\Query\AST\Functions\LengthFunction', + 'locate' => 'Doctrine\ORM\Query\AST\Functions\LocateFunction', + 'abs' => 'Doctrine\ORM\Query\AST\Functions\AbsFunction', + 'sqrt' => 'Doctrine\ORM\Query\AST\Functions\SqrtFunction', + 'mod' => 'Doctrine\ORM\Query\AST\Functions\ModFunction', + 'size' => 'Doctrine\ORM\Query\AST\Functions\SizeFunction', + 'date_diff' => 'Doctrine\ORM\Query\AST\Functions\DateDiffFunction', + 'bit_and' => 'Doctrine\ORM\Query\AST\Functions\BitAndFunction', + 'bit_or' => 'Doctrine\ORM\Query\AST\Functions\BitOrFunction', + ); + + /** READ-ONLY: Maps BUILT-IN datetime function names to AST class names. */ + private static $_DATETIME_FUNCTIONS = array( + 'current_date' => 'Doctrine\ORM\Query\AST\Functions\CurrentDateFunction', + 'current_time' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimeFunction', + 'current_timestamp' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimestampFunction', + 'date_add' => 'Doctrine\ORM\Query\AST\Functions\DateAddFunction', + 'date_sub' => 'Doctrine\ORM\Query\AST\Functions\DateSubFunction', + ); + + /** + * Expressions that were encountered during parsing of identifiers and expressions + * and still need to be validated. + */ + private $_deferredIdentificationVariables = array(); + private $_deferredPartialObjectExpressions = array(); + private $_deferredPathExpressions = array(); + private $_deferredResultVariables = array(); + + /** + * The lexer. + * + * @var \Doctrine\ORM\Query\Lexer + */ + private $_lexer; + + /** + * The parser result. + * + * @var \Doctrine\ORM\Query\ParserResult + */ + private $_parserResult; + + /** + * The EntityManager. + * + * @var EnityManager + */ + private $_em; + + /** + * The Query to parse. + * + * @var Query + */ + private $_query; + + /** + * Map of declared query components in the parsed query. + * + * @var array + */ + private $_queryComponents = array(); + + /** + * Keeps the nesting level of defined ResultVariables + * + * @var integer + */ + private $_nestingLevel = 0; + + /** + * Any additional custom tree walkers that modify the AST. + * + * @var array + */ + private $_customTreeWalkers = array(); + + /** + * The custom last tree walker, if any, that is responsible for producing the output. + * + * @var TreeWalker + */ + private $_customOutputWalker; + + /** + * @var array + */ + private $_identVariableExpressions = array(); + + /** + * Check if a function is internally defined. Used to prevent overwriting + * of built-in functions through user-defined functions. + * + * @param string $functionName + * @return bool + */ + static public function isInternalFunction($functionName) + { + $functionName = strtolower($functionName); + + return isset(self::$_STRING_FUNCTIONS[$functionName]) + || isset(self::$_DATETIME_FUNCTIONS[$functionName]) + || isset(self::$_NUMERIC_FUNCTIONS[$functionName]); + } + + /** + * Creates a new query parser object. + * + * @param Query $query The Query to parse. + */ + public function __construct(Query $query) + { + $this->_query = $query; + $this->_em = $query->getEntityManager(); + $this->_lexer = new Lexer($query->getDql()); + $this->_parserResult = new ParserResult(); + } + + /** + * Sets a custom tree walker that produces output. + * This tree walker will be run last over the AST, after any other walkers. + * + * @param string $className + */ + public function setCustomOutputTreeWalker($className) + { + $this->_customOutputWalker = $className; + } + + /** + * Adds a custom tree walker for modifying the AST. + * + * @param string $className + */ + public function addCustomTreeWalker($className) + { + $this->_customTreeWalkers[] = $className; + } + + /** + * Gets the lexer used by the parser. + * + * @return \Doctrine\ORM\Query\Lexer + */ + public function getLexer() + { + return $this->_lexer; + } + + /** + * Gets the ParserResult that is being filled with information during parsing. + * + * @return \Doctrine\ORM\Query\ParserResult + */ + public function getParserResult() + { + return $this->_parserResult; + } + + /** + * Gets the EntityManager used by the parser. + * + * @return EntityManager + */ + public function getEntityManager() + { + return $this->_em; + } + + /** + * Parse and build AST for the given Query. + * + * @return \Doctrine\ORM\Query\AST\SelectStatement | + * \Doctrine\ORM\Query\AST\UpdateStatement | + * \Doctrine\ORM\Query\AST\DeleteStatement + */ + public function getAST() + { + // Parse & build AST + $AST = $this->QueryLanguage(); + + // Process any deferred validations of some nodes in the AST. + // This also allows post-processing of the AST for modification purposes. + $this->_processDeferredIdentificationVariables(); + + if ($this->_deferredPartialObjectExpressions) { + $this->_processDeferredPartialObjectExpressions(); + } + + if ($this->_deferredPathExpressions) { + $this->_processDeferredPathExpressions($AST); + } + + if ($this->_deferredResultVariables) { + $this->_processDeferredResultVariables(); + } + + $this->_processRootEntityAliasSelected(); + + // TODO: Is there a way to remove this? It may impact the mixed hydration resultset a lot! + $this->fixIdentificationVariableOrder($AST); + + return $AST; + } + + /** + * Attempts to match the given token with the current lookahead token. + * + * If they match, updates the lookahead token; otherwise raises a syntax + * error. + * + * @param int token type + * @return void + * @throws QueryException If the tokens dont match. + */ + public function match($token) + { + $lookaheadType = $this->_lexer->lookahead['type']; + + // short-circuit on first condition, usually types match + if ($lookaheadType !== $token && $token !== Lexer::T_IDENTIFIER && $lookaheadType <= Lexer::T_IDENTIFIER) { + $this->syntaxError($this->_lexer->getLiteral($token)); + } + + $this->_lexer->moveNext(); + } + + /** + * Free this parser enabling it to be reused + * + * @param boolean $deep Whether to clean peek and reset errors + * @param integer $position Position to reset + */ + public function free($deep = false, $position = 0) + { + // WARNING! Use this method with care. It resets the scanner! + $this->_lexer->resetPosition($position); + + // Deep = true cleans peek and also any previously defined errors + if ($deep) { + $this->_lexer->resetPeek(); + } + + $this->_lexer->token = null; + $this->_lexer->lookahead = null; + } + + /** + * Parses a query string. + * + * @return ParserResult + */ + public function parse() + { + $AST = $this->getAST(); + + if (($customWalkers = $this->_query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) { + $this->_customTreeWalkers = $customWalkers; + } + + if (($customOutputWalker = $this->_query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER)) !== false) { + $this->_customOutputWalker = $customOutputWalker; + } + + // Run any custom tree walkers over the AST + if ($this->_customTreeWalkers) { + $treeWalkerChain = new TreeWalkerChain($this->_query, $this->_parserResult, $this->_queryComponents); + + foreach ($this->_customTreeWalkers as $walker) { + $treeWalkerChain->addTreeWalker($walker); + } + + switch (true) { + case ($AST instanceof AST\UpdateStatement): + $treeWalkerChain->walkUpdateStatement($AST); + break; + + case ($AST instanceof AST\DeleteStatement): + $treeWalkerChain->walkDeleteStatement($AST); + break; + + case ($AST instanceof AST\SelectStatement): + default: + $treeWalkerChain->walkSelectStatement($AST); + } + } + + $outputWalkerClass = $this->_customOutputWalker ?: __NAMESPACE__ . '\SqlWalker'; + $outputWalker = new $outputWalkerClass($this->_query, $this->_parserResult, $this->_queryComponents); + + // Assign an SQL executor to the parser result + $this->_parserResult->setSqlExecutor($outputWalker->getExecutor($AST)); + + return $this->_parserResult; + } + + /** + * Fix order of identification variables. + * + * They have to appear in the select clause in the same order as the + * declarations (from ... x join ... y join ... z ...) appear in the query + * as the hydration process relies on that order for proper operation. + * + * @param AST\SelectStatement|AST\DeleteStatement|AST\UpdateStatement $AST + * @return void + */ + private function fixIdentificationVariableOrder($AST) + { + if (count($this->_identVariableExpressions) <= 1) { + return; + } + + foreach ($this->_queryComponents as $dqlAlias => $qComp) { + if ( ! isset($this->_identVariableExpressions[$dqlAlias])) { + continue; + } + + $expr = $this->_identVariableExpressions[$dqlAlias]; + $key = array_search($expr, $AST->selectClause->selectExpressions); + + unset($AST->selectClause->selectExpressions[$key]); + + $AST->selectClause->selectExpressions[] = $expr; + } + } + + /** + * Generates a new syntax error. + * + * @param string $expected Expected string. + * @param array $token Got token. + * + * @throws \Doctrine\ORM\Query\QueryException + */ + public function syntaxError($expected = '', $token = null) + { + if ($token === null) { + $token = $this->_lexer->lookahead; + } + + $tokenPos = (isset($token['position'])) ? $token['position'] : '-1'; + + $message = "line 0, col {$tokenPos}: Error: "; + $message .= ($expected !== '') ? "Expected {$expected}, got " : 'Unexpected '; + $message .= ($this->_lexer->lookahead === null) ? 'end of string.' : "'{$token['value']}'"; + + throw QueryException::syntaxError($message, QueryException::dqlError($this->_query->getDQL())); + } + + /** + * Generates a new semantical error. + * + * @param string $message Optional message. + * @param array $token Optional token. + * + * @throws \Doctrine\ORM\Query\QueryException + */ + public function semanticalError($message = '', $token = null) + { + if ($token === null) { + $token = $this->_lexer->lookahead; + } + + // Minimum exposed chars ahead of token + $distance = 12; + + // Find a position of a final word to display in error string + $dql = $this->_query->getDql(); + $length = strlen($dql); + $pos = $token['position'] + $distance; + $pos = strpos($dql, ' ', ($length > $pos) ? $pos : $length); + $length = ($pos !== false) ? $pos - $token['position'] : $distance; + + $tokenPos = (isset($token['position']) && $token['position'] > 0) ? $token['position'] : '-1'; + $tokenStr = substr($dql, $token['position'], $length); + + // Building informative message + $message = 'line 0, col ' . $tokenPos . " near '" . $tokenStr . "': Error: " . $message; + + throw QueryException::semanticalError($message, QueryException::dqlError($this->_query->getDQL())); + } + + /** + * Peek beyond the matched closing parenthesis and return the first token after that one. + * + * @param boolean $resetPeek Reset peek after finding the closing parenthesis + * @return array + */ + private function _peekBeyondClosingParenthesis($resetPeek = true) + { + $token = $this->_lexer->peek(); + $numUnmatched = 1; + + while ($numUnmatched > 0 && $token !== null) { + switch ($token['type']) { + case Lexer::T_OPEN_PARENTHESIS: + ++$numUnmatched; + break; + + case Lexer::T_CLOSE_PARENTHESIS: + --$numUnmatched; + break; + + default: + // Do nothing + } + + $token = $this->_lexer->peek(); + } + + if ($resetPeek) { + $this->_lexer->resetPeek(); + } + + return $token; + } + + /** + * Checks if the given token indicates a mathematical operator. + * + * @return boolean TRUE if the token is a mathematical operator, FALSE otherwise. + */ + private function _isMathOperator($token) + { + return in_array($token['type'], array(Lexer::T_PLUS, Lexer::T_MINUS, Lexer::T_DIVIDE, Lexer::T_MULTIPLY)); + } + + /** + * Checks if the next-next (after lookahead) token starts a function. + * + * @return boolean TRUE if the next-next tokens start a function, FALSE otherwise. + */ + private function _isFunction() + { + $peek = $this->_lexer->peek(); + $nextpeek = $this->_lexer->peek(); + + $this->_lexer->resetPeek(); + + // We deny the COUNT(SELECT * FROM User u) here. COUNT won't be considered a function + return ($peek['type'] === Lexer::T_OPEN_PARENTHESIS && $nextpeek['type'] !== Lexer::T_SELECT); + } + + /** + * Checks whether the given token type indicates an aggregate function. + * + * @return boolean TRUE if the token type is an aggregate function, FALSE otherwise. + */ + private function _isAggregateFunction($tokenType) + { + return in_array($tokenType, array(Lexer::T_AVG, Lexer::T_MIN, Lexer::T_MAX, Lexer::T_SUM, Lexer::T_COUNT)); + } + + /** + * Checks whether the current lookahead token of the lexer has the type T_ALL, T_ANY or T_SOME. + * + * @return boolean + */ + private function _isNextAllAnySome() + { + return in_array($this->_lexer->lookahead['type'], array(Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME)); + } + + /** + * Validates that the given IdentificationVariable is semantically correct. + * It must exist in query components list. + * + * @return void + */ + private function _processDeferredIdentificationVariables() + { + foreach ($this->_deferredIdentificationVariables as $deferredItem) { + $identVariable = $deferredItem['expression']; + + // Check if IdentificationVariable exists in queryComponents + if ( ! isset($this->_queryComponents[$identVariable])) { + $this->semanticalError( + "'$identVariable' is not defined.", $deferredItem['token'] + ); + } + + $qComp = $this->_queryComponents[$identVariable]; + + // Check if queryComponent points to an AbstractSchemaName or a ResultVariable + if ( ! isset($qComp['metadata'])) { + $this->semanticalError( + "'$identVariable' does not point to a Class.", $deferredItem['token'] + ); + } + + // Validate if identification variable nesting level is lower or equal than the current one + if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) { + $this->semanticalError( + "'$identVariable' is used outside the scope of its declaration.", $deferredItem['token'] + ); + } + } + } + + /** + * Validates that the given PartialObjectExpression is semantically correct. + * It must exist in query components list. + * + * @return void + */ + private function _processDeferredPartialObjectExpressions() + { + foreach ($this->_deferredPartialObjectExpressions as $deferredItem) { + $expr = $deferredItem['expression']; + $class = $this->_queryComponents[$expr->identificationVariable]['metadata']; + + foreach ($expr->partialFieldSet as $field) { + if (isset($class->fieldMappings[$field])) { + continue; + } + + $this->semanticalError( + "There is no mapped field named '$field' on class " . $class->name . ".", $deferredItem['token'] + ); + } + + if (array_intersect($class->identifier, $expr->partialFieldSet) != $class->identifier) { + $this->semanticalError( + "The partial field selection of class " . $class->name . " must contain the identifier.", + $deferredItem['token'] + ); + } + } + } + + /** + * Validates that the given ResultVariable is semantically correct. + * It must exist in query components list. + * + * @return void + */ + private function _processDeferredResultVariables() + { + foreach ($this->_deferredResultVariables as $deferredItem) { + $resultVariable = $deferredItem['expression']; + + // Check if ResultVariable exists in queryComponents + if ( ! isset($this->_queryComponents[$resultVariable])) { + $this->semanticalError( + "'$resultVariable' is not defined.", $deferredItem['token'] + ); + } + + $qComp = $this->_queryComponents[$resultVariable]; + + // Check if queryComponent points to an AbstractSchemaName or a ResultVariable + if ( ! isset($qComp['resultVariable'])) { + $this->semanticalError( + "'$resultVariable' does not point to a ResultVariable.", $deferredItem['token'] + ); + } + + // Validate if identification variable nesting level is lower or equal than the current one + if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) { + $this->semanticalError( + "'$resultVariable' is used outside the scope of its declaration.", $deferredItem['token'] + ); + } + } + } + + /** + * Validates that the given PathExpression is semantically correct for grammar rules: + * + * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression + * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression + * StateFieldPathExpression ::= IdentificationVariable "." StateField + * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField + * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField + * + * @param array $deferredItem + * @param mixed $AST + */ + private function _processDeferredPathExpressions($AST) + { + foreach ($this->_deferredPathExpressions as $deferredItem) { + $pathExpression = $deferredItem['expression']; + + $qComp = $this->_queryComponents[$pathExpression->identificationVariable]; + $class = $qComp['metadata']; + + if (($field = $pathExpression->field) === null) { + $field = $pathExpression->field = $class->identifier[0]; + } + + // Check if field or association exists + if ( ! isset($class->associationMappings[$field]) && ! isset($class->fieldMappings[$field])) { + $this->semanticalError( + 'Class ' . $class->name . ' has no field or association named ' . $field, + $deferredItem['token'] + ); + } + + $fieldType = AST\PathExpression::TYPE_STATE_FIELD; + + if (isset($class->associationMappings[$field])) { + $assoc = $class->associationMappings[$field]; + + $fieldType = ($assoc['type'] & ClassMetadata::TO_ONE) + ? AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION + : AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION; + } + + // Validate if PathExpression is one of the expected types + $expectedType = $pathExpression->expectedType; + + if ( ! ($expectedType & $fieldType)) { + // We need to recognize which was expected type(s) + $expectedStringTypes = array(); + + // Validate state field type + if ($expectedType & AST\PathExpression::TYPE_STATE_FIELD) { + $expectedStringTypes[] = 'StateFieldPathExpression'; + } + + // Validate single valued association (*-to-one) + if ($expectedType & AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION) { + $expectedStringTypes[] = 'SingleValuedAssociationField'; + } + + // Validate single valued association (*-to-many) + if ($expectedType & AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION) { + $expectedStringTypes[] = 'CollectionValuedAssociationField'; + } + + // Build the error message + $semanticalError = 'Invalid PathExpression. '; + $semanticalError .= (count($expectedStringTypes) == 1) + ? 'Must be a ' . $expectedStringTypes[0] . '.' + : implode(' or ', $expectedStringTypes) . ' expected.'; + + $this->semanticalError($semanticalError, $deferredItem['token']); + } + + // We need to force the type in PathExpression + $pathExpression->type = $fieldType; + } + } + + private function _processRootEntityAliasSelected() + { + if ( ! count($this->_identVariableExpressions)) { + return; + } + + $foundRootEntity = false; + + foreach ($this->_identVariableExpressions as $dqlAlias => $expr) { + if (isset($this->_queryComponents[$dqlAlias]) && $this->_queryComponents[$dqlAlias]['parent'] === null) { + $foundRootEntity = true; + } + } + + if ( ! $foundRootEntity) { + $this->semanticalError('Cannot select entity through identification variables without choosing at least one root entity alias.'); + } + } + + /** + * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement + * + * @return \Doctrine\ORM\Query\AST\SelectStatement | + * \Doctrine\ORM\Query\AST\UpdateStatement | + * \Doctrine\ORM\Query\AST\DeleteStatement + */ + public function QueryLanguage() + { + $this->_lexer->moveNext(); + + switch ($this->_lexer->lookahead['type']) { + case Lexer::T_SELECT: + $statement = $this->SelectStatement(); + break; + + case Lexer::T_UPDATE: + $statement = $this->UpdateStatement(); + break; + + case Lexer::T_DELETE: + $statement = $this->DeleteStatement(); + break; + + default: + $this->syntaxError('SELECT, UPDATE or DELETE'); + break; + } + + // Check for end of string + if ($this->_lexer->lookahead !== null) { + $this->syntaxError('end of string'); + } + + return $statement; + } + + /** + * SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] + * + * @return \Doctrine\ORM\Query\AST\SelectStatement + */ + public function SelectStatement() + { + $selectStatement = new AST\SelectStatement($this->SelectClause(), $this->FromClause()); + + $selectStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; + $selectStatement->groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null; + $selectStatement->havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null; + $selectStatement->orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null; + + return $selectStatement; + } + + /** + * UpdateStatement ::= UpdateClause [WhereClause] + * + * @return \Doctrine\ORM\Query\AST\UpdateStatement + */ + public function UpdateStatement() + { + $updateStatement = new AST\UpdateStatement($this->UpdateClause()); + + $updateStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; + + return $updateStatement; + } + + /** + * DeleteStatement ::= DeleteClause [WhereClause] + * + * @return \Doctrine\ORM\Query\AST\DeleteStatement + */ + public function DeleteStatement() + { + $deleteStatement = new AST\DeleteStatement($this->DeleteClause()); + + $deleteStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; + + return $deleteStatement; + } + + /** + * IdentificationVariable ::= identifier + * + * @return string + */ + public function IdentificationVariable() + { + $this->match(Lexer::T_IDENTIFIER); + + $identVariable = $this->_lexer->token['value']; + + $this->_deferredIdentificationVariables[] = array( + 'expression' => $identVariable, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $this->_lexer->token, + ); + + return $identVariable; + } + + /** + * AliasIdentificationVariable = identifier + * + * @return string + */ + public function AliasIdentificationVariable() + { + $this->match(Lexer::T_IDENTIFIER); + + $aliasIdentVariable = $this->_lexer->token['value']; + $exists = isset($this->_queryComponents[$aliasIdentVariable]); + + if ($exists) { + $this->semanticalError("'$aliasIdentVariable' is already defined.", $this->_lexer->token); + } + + return $aliasIdentVariable; + } + + /** + * AbstractSchemaName ::= identifier + * + * @return string + */ + public function AbstractSchemaName() + { + $this->match(Lexer::T_IDENTIFIER); + + $schemaName = ltrim($this->_lexer->token['value'], '\\'); + + if (strrpos($schemaName, ':') !== false) { + list($namespaceAlias, $simpleClassName) = explode(':', $schemaName); + + $schemaName = $this->_em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName; + } + + $exists = class_exists($schemaName, true); + + if ( ! $exists) { + $this->semanticalError("Class '$schemaName' is not defined.", $this->_lexer->token); + } + + return $schemaName; + } + + /** + * AliasResultVariable ::= identifier + * + * @return string + */ + public function AliasResultVariable() + { + $this->match(Lexer::T_IDENTIFIER); + + $resultVariable = $this->_lexer->token['value']; + $exists = isset($this->_queryComponents[$resultVariable]); + + if ($exists) { + $this->semanticalError("'$resultVariable' is already defined.", $this->_lexer->token); + } + + return $resultVariable; + } + + /** + * ResultVariable ::= identifier + * + * @return string + */ + public function ResultVariable() + { + $this->match(Lexer::T_IDENTIFIER); + + $resultVariable = $this->_lexer->token['value']; + + // Defer ResultVariable validation + $this->_deferredResultVariables[] = array( + 'expression' => $resultVariable, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $this->_lexer->token, + ); + + return $resultVariable; + } + + /** + * JoinAssociationPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField) + * + * @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression + */ + public function JoinAssociationPathExpression() + { + $identVariable = $this->IdentificationVariable(); + + if ( ! isset($this->_queryComponents[$identVariable])) { + $this->semanticalError( + 'Identification Variable ' . $identVariable .' used in join path expression but was not defined before.' + ); + } + + $this->match(Lexer::T_DOT); + $this->match(Lexer::T_IDENTIFIER); + + $field = $this->_lexer->token['value']; + + // Validate association field + $qComp = $this->_queryComponents[$identVariable]; + $class = $qComp['metadata']; + + if ( ! $class->hasAssociation($field)) { + $this->semanticalError('Class ' . $class->name . ' has no association named ' . $field); + } + + return new AST\JoinAssociationPathExpression($identVariable, $field); + } + + /** + * Parses an arbitrary path expression and defers semantical validation + * based on expected types. + * + * PathExpression ::= IdentificationVariable "." identifier + * + * @param integer $expectedTypes + * @return \Doctrine\ORM\Query\AST\PathExpression + */ + public function PathExpression($expectedTypes) + { + $identVariable = $this->IdentificationVariable(); + $field = null; + + if ($this->_lexer->isNextToken(Lexer::T_DOT)) { + $this->match(Lexer::T_DOT); + $this->match(Lexer::T_IDENTIFIER); + + $field = $this->_lexer->token['value']; + } + + // Creating AST node + $pathExpr = new AST\PathExpression($expectedTypes, $identVariable, $field); + + // Defer PathExpression validation if requested to be defered + $this->_deferredPathExpressions[] = array( + 'expression' => $pathExpr, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $this->_lexer->token, + ); + + return $pathExpr; + } + + /** + * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression + * + * @return \Doctrine\ORM\Query\AST\PathExpression + */ + public function AssociationPathExpression() + { + return $this->PathExpression( + AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION | + AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION + ); + } + + /** + * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression + * + * @return \Doctrine\ORM\Query\AST\PathExpression + */ + public function SingleValuedPathExpression() + { + return $this->PathExpression( + AST\PathExpression::TYPE_STATE_FIELD | + AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION + ); + } + + /** + * StateFieldPathExpression ::= IdentificationVariable "." StateField + * + * @return \Doctrine\ORM\Query\AST\PathExpression + */ + public function StateFieldPathExpression() + { + return $this->PathExpression(AST\PathExpression::TYPE_STATE_FIELD); + } + + /** + * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField + * + * @return \Doctrine\ORM\Query\AST\PathExpression + */ + public function SingleValuedAssociationPathExpression() + { + return $this->PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION); + } + + /** + * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField + * + * @return \Doctrine\ORM\Query\AST\PathExpression + */ + public function CollectionValuedPathExpression() + { + return $this->PathExpression(AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION); + } + + /** + * SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression} + * + * @return \Doctrine\ORM\Query\AST\SelectClause + */ + public function SelectClause() + { + $isDistinct = false; + $this->match(Lexer::T_SELECT); + + // Check for DISTINCT + if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { + $this->match(Lexer::T_DISTINCT); + + $isDistinct = true; + } + + // Process SelectExpressions (1..N) + $selectExpressions = array(); + $selectExpressions[] = $this->SelectExpression(); + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + + $selectExpressions[] = $this->SelectExpression(); + } + + return new AST\SelectClause($selectExpressions, $isDistinct); + } + + /** + * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression + * + * @return \Doctrine\ORM\Query\AST\SimpleSelectClause + */ + public function SimpleSelectClause() + { + $isDistinct = false; + $this->match(Lexer::T_SELECT); + + if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { + $this->match(Lexer::T_DISTINCT); + + $isDistinct = true; + } + + return new AST\SimpleSelectClause($this->SimpleSelectExpression(), $isDistinct); + } + + /** + * UpdateClause ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}* + * + * @return \Doctrine\ORM\Query\AST\UpdateClause + */ + public function UpdateClause() + { + $this->match(Lexer::T_UPDATE); + $token = $this->_lexer->lookahead; + $abstractSchemaName = $this->AbstractSchemaName(); + + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + + $aliasIdentificationVariable = $this->AliasIdentificationVariable(); + + $class = $this->_em->getClassMetadata($abstractSchemaName); + + // Building queryComponent + $queryComponent = array( + 'metadata' => $class, + 'parent' => null, + 'relation' => null, + 'map' => null, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $token, + ); + + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; + + $this->match(Lexer::T_SET); + + $updateItems = array(); + $updateItems[] = $this->UpdateItem(); + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + + $updateItems[] = $this->UpdateItem(); + } + + $updateClause = new AST\UpdateClause($abstractSchemaName, $updateItems); + $updateClause->aliasIdentificationVariable = $aliasIdentificationVariable; + + return $updateClause; + } + + /** + * DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariable + * + * @return \Doctrine\ORM\Query\AST\DeleteClause + */ + public function DeleteClause() + { + $this->match(Lexer::T_DELETE); + + if ($this->_lexer->isNextToken(Lexer::T_FROM)) { + $this->match(Lexer::T_FROM); + } + + $token = $this->_lexer->lookahead; + $deleteClause = new AST\DeleteClause($this->AbstractSchemaName()); + + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + + $aliasIdentificationVariable = $this->AliasIdentificationVariable(); + + $deleteClause->aliasIdentificationVariable = $aliasIdentificationVariable; + $class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName); + + // Building queryComponent + $queryComponent = array( + 'metadata' => $class, + 'parent' => null, + 'relation' => null, + 'map' => null, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $token, + ); + + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; + + return $deleteClause; + } + + /** + * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}* + * + * @return \Doctrine\ORM\Query\AST\FromClause + */ + public function FromClause() + { + $this->match(Lexer::T_FROM); + + $identificationVariableDeclarations = array(); + $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration(); + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + + $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration(); + } + + return new AST\FromClause($identificationVariableDeclarations); + } + + /** + * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}* + * + * @return \Doctrine\ORM\Query\AST\SubselectFromClause + */ + public function SubselectFromClause() + { + $this->match(Lexer::T_FROM); + + $identificationVariables = array(); + $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration(); + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + + $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration(); + } + + return new AST\SubselectFromClause($identificationVariables); + } + + /** + * WhereClause ::= "WHERE" ConditionalExpression + * + * @return \Doctrine\ORM\Query\AST\WhereClause + */ + public function WhereClause() + { + $this->match(Lexer::T_WHERE); + + return new AST\WhereClause($this->ConditionalExpression()); + } + + /** + * HavingClause ::= "HAVING" ConditionalExpression + * + * @return \Doctrine\ORM\Query\AST\HavingClause + */ + public function HavingClause() + { + $this->match(Lexer::T_HAVING); + + return new AST\HavingClause($this->ConditionalExpression()); + } + + /** + * GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}* + * + * @return \Doctrine\ORM\Query\AST\GroupByClause + */ + public function GroupByClause() + { + $this->match(Lexer::T_GROUP); + $this->match(Lexer::T_BY); + + $groupByItems = array($this->GroupByItem()); + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + + $groupByItems[] = $this->GroupByItem(); + } + + return new AST\GroupByClause($groupByItems); + } + + /** + * OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}* + * + * @return \Doctrine\ORM\Query\AST\OrderByClause + */ + public function OrderByClause() + { + $this->match(Lexer::T_ORDER); + $this->match(Lexer::T_BY); + + $orderByItems = array(); + $orderByItems[] = $this->OrderByItem(); + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + + $orderByItems[] = $this->OrderByItem(); + } + + return new AST\OrderByClause($orderByItems); + } + + /** + * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] + * + * @return \Doctrine\ORM\Query\AST\Subselect + */ + public function Subselect() + { + // Increase query nesting level + $this->_nestingLevel++; + + $subselect = new AST\Subselect($this->SimpleSelectClause(), $this->SubselectFromClause()); + + $subselect->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; + $subselect->groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null; + $subselect->havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null; + $subselect->orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null; + + // Decrease query nesting level + $this->_nestingLevel--; + + return $subselect; + } + + /** + * UpdateItem ::= SingleValuedPathExpression "=" NewValue + * + * @return \Doctrine\ORM\Query\AST\UpdateItem + */ + public function UpdateItem() + { + $pathExpr = $this->SingleValuedPathExpression(); + + $this->match(Lexer::T_EQUALS); + + $updateItem = new AST\UpdateItem($pathExpr, $this->NewValue()); + + return $updateItem; + } + + /** + * GroupByItem ::= IdentificationVariable | ResultVariable | SingleValuedPathExpression + * + * @return string | \Doctrine\ORM\Query\AST\PathExpression + */ + public function GroupByItem() + { + // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression + $glimpse = $this->_lexer->glimpse(); + + if ($glimpse['type'] === Lexer::T_DOT) { + return $this->SingleValuedPathExpression(); + } + + // Still need to decide between IdentificationVariable or ResultVariable + $lookaheadValue = $this->_lexer->lookahead['value']; + + if ( ! isset($this->_queryComponents[$lookaheadValue])) { + $this->semanticalError('Cannot group by undefined identification or result variable.'); + } + + return (isset($this->_queryComponents[$lookaheadValue]['metadata'])) + ? $this->IdentificationVariable() + : $this->ResultVariable(); + } + + /** + * OrderByItem ::= ( + * SimpleArithmeticExpression | SingleValuedPathExpression | + * ScalarExpression | ResultVariable + * ) ["ASC" | "DESC"] + * + * @return \Doctrine\ORM\Query\AST\OrderByItem + */ + public function OrderByItem() + { + + $this->_lexer->peek(); // lookahead => '.' + $this->_lexer->peek(); // lookahead => token after '.' + $peek = $this->_lexer->peek(); // lookahead => token after the token after the '.' + $this->_lexer->resetPeek(); + $glimpse = $this->_lexer->glimpse(); + + switch (true) { + + case ($this->_isMathOperator($peek)): + $expr = $this->SimpleArithmeticExpression(); + + break; + case ($glimpse['type'] === Lexer::T_DOT): + $expr = $this->SingleValuedPathExpression(); + + break; + case ($this->_lexer->peek() && $this->_isMathOperator($this->_peekBeyondClosingParenthesis())): + $expr = $this->ScalarExpression(); + + break; + default: + $expr = $this->ResultVariable(); + + break; + } + + $type = 'ASC'; + $item = new AST\OrderByItem($expr); + + switch (true) { + case ($this->_lexer->isNextToken(Lexer::T_DESC)): + $this->match(Lexer::T_DESC); + $type = 'DESC'; + break; + + case ($this->_lexer->isNextToken(Lexer::T_ASC)): + $this->match(Lexer::T_ASC); + break; + + default: + // Do nothing + } + + $item->type = $type; + + return $item; + } + + /** + * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary | + * EnumPrimary | SimpleEntityExpression | "NULL" + * + * NOTE: Since it is not possible to correctly recognize individual types, here is the full + * grammar that needs to be supported: + * + * NewValue ::= SimpleArithmeticExpression | "NULL" + * + * SimpleArithmeticExpression covers all *Primary grammar rules and also SimpleEntityExpression + */ + public function NewValue() + { + if ($this->_lexer->isNextToken(Lexer::T_NULL)) { + $this->match(Lexer::T_NULL); + + return null; + } + + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + $this->match(Lexer::T_INPUT_PARAMETER); + + return new AST\InputParameter($this->_lexer->token['value']); + } + + return $this->SimpleArithmeticExpression(); + } + + /** + * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {Join}* + * + * @return \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration + */ + public function IdentificationVariableDeclaration() + { + $rangeVariableDeclaration = $this->RangeVariableDeclaration(); + $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null; + $joins = array(); + + while ( + $this->_lexer->isNextToken(Lexer::T_LEFT) || + $this->_lexer->isNextToken(Lexer::T_INNER) || + $this->_lexer->isNextToken(Lexer::T_JOIN) + ) { + $joins[] = $this->Join(); + } + + return new AST\IdentificationVariableDeclaration( + $rangeVariableDeclaration, $indexBy, $joins + ); + } + + /** + * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable) + * + * @return \Doctrine\ORM\Query\AST\SubselectIdentificationVariableDeclaration | + * \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration + */ + public function SubselectIdentificationVariableDeclaration() + { + $this->_lexer->glimpse(); + + /* NOT YET IMPLEMENTED! + + if ($glimpse['type'] == Lexer::T_DOT) { + $subselectIdVarDecl = new AST\SubselectIdentificationVariableDeclaration(); + $subselectIdVarDecl->associationPathExpression = $this->AssociationPathExpression(); + $this->match(Lexer::T_AS); + $subselectIdVarDecl->aliasIdentificationVariable = $this->AliasIdentificationVariable(); + + return $subselectIdVarDecl; + } + */ + + return $this->IdentificationVariableDeclaration(); + } + + /** + * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" + * (JoinAssociationDeclaration | RangeVariableDeclaration) + * ["WITH" ConditionalExpression] + * + * @return \Doctrine\ORM\Query\AST\Join + */ + public function Join() + { + // Check Join type + $joinType = AST\Join::JOIN_TYPE_INNER; + + switch (true) { + case ($this->_lexer->isNextToken(Lexer::T_LEFT)): + $this->match(Lexer::T_LEFT); + + $joinType = AST\Join::JOIN_TYPE_LEFT; + + // Possible LEFT OUTER join + if ($this->_lexer->isNextToken(Lexer::T_OUTER)) { + $this->match(Lexer::T_OUTER); + + $joinType = AST\Join::JOIN_TYPE_LEFTOUTER; + } + break; + + case ($this->_lexer->isNextToken(Lexer::T_INNER)): + $this->match(Lexer::T_INNER); + break; + + default: + // Do nothing + } + + $this->match(Lexer::T_JOIN); + + $next = $this->_lexer->glimpse(); + $joinDeclaration = ($next['type'] === Lexer::T_DOT) + ? $this->JoinAssociationDeclaration() + : $this->RangeVariableDeclaration(); + + // Create AST node + $join = new AST\Join($joinType, $joinDeclaration); + + // Check for ad-hoc Join conditions + if ($this->_lexer->isNextToken(Lexer::T_WITH) || $joinDeclaration instanceof AST\RangeVariableDeclaration) { + $this->match(Lexer::T_WITH); + + $join->conditionalExpression = $this->ConditionalExpression(); + } + + return $join; + } + + /** + * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable + * + * @return \Doctrine\ORM\Query\AST\RangeVariableDeclaration + */ + public function RangeVariableDeclaration() + { + $abstractSchemaName = $this->AbstractSchemaName(); + + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + + $token = $this->_lexer->lookahead; + $aliasIdentificationVariable = $this->AliasIdentificationVariable(); + $classMetadata = $this->_em->getClassMetadata($abstractSchemaName); + + // Building queryComponent + $queryComponent = array( + 'metadata' => $classMetadata, + 'parent' => null, + 'relation' => null, + 'map' => null, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $token + ); + + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; + + return new AST\RangeVariableDeclaration($abstractSchemaName, $aliasIdentificationVariable); + } + + /** + * JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy] + * + * @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression + */ + public function JoinAssociationDeclaration() + { + $joinAssociationPathExpression = $this->JoinAssociationPathExpression(); + + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + + $aliasIdentificationVariable = $this->AliasIdentificationVariable(); + $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null; + + $identificationVariable = $joinAssociationPathExpression->identificationVariable; + $field = $joinAssociationPathExpression->associationField; + + $class = $this->_queryComponents[$identificationVariable]['metadata']; + $targetClass = $this->_em->getClassMetadata($class->associationMappings[$field]['targetEntity']); + + // Building queryComponent + $joinQueryComponent = array( + 'metadata' => $targetClass, + 'parent' => $joinAssociationPathExpression->identificationVariable, + 'relation' => $class->getAssociationMapping($field), + 'map' => null, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $this->_lexer->lookahead + ); + + $this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent; + + return new AST\JoinAssociationDeclaration($joinAssociationPathExpression, $aliasIdentificationVariable, $indexBy); + } + + /** + * PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet + * PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}" + * + * @return array + */ + public function PartialObjectExpression() + { + $this->match(Lexer::T_PARTIAL); + + $partialFieldSet = array(); + + $identificationVariable = $this->IdentificationVariable(); + + $this->match(Lexer::T_DOT); + $this->match(Lexer::T_OPEN_CURLY_BRACE); + $this->match(Lexer::T_IDENTIFIER); + + $partialFieldSet[] = $this->_lexer->token['value']; + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + $this->match(Lexer::T_IDENTIFIER); + + $partialFieldSet[] = $this->_lexer->token['value']; + } + + $this->match(Lexer::T_CLOSE_CURLY_BRACE); + + $partialObjectExpression = new AST\PartialObjectExpression($identificationVariable, $partialFieldSet); + + // Defer PartialObjectExpression validation + $this->_deferredPartialObjectExpressions[] = array( + 'expression' => $partialObjectExpression, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $this->_lexer->token, + ); + + return $partialObjectExpression; + } + + /** + * IndexBy ::= "INDEX" "BY" StateFieldPathExpression + * + * @return \Doctrine\ORM\Query\AST\IndexBy + */ + public function IndexBy() + { + $this->match(Lexer::T_INDEX); + $this->match(Lexer::T_BY); + $pathExpr = $this->StateFieldPathExpression(); + + // Add the INDEX BY info to the query component + $this->_queryComponents[$pathExpr->identificationVariable]['map'] = $pathExpr->field; + + return new AST\IndexBy($pathExpr); + } + + /** + * ScalarExpression ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary | + * StateFieldPathExpression | BooleanPrimary | CaseExpression | + * InstanceOfExpression + * + * @return mixed One of the possible expressions or subexpressions. + */ + public function ScalarExpression() + { + $lookahead = $this->_lexer->lookahead['type']; + + switch ($lookahead) { + case Lexer::T_IDENTIFIER: + $this->_lexer->peek(); // lookahead => '.' + $this->_lexer->peek(); // lookahead => token after '.' + $peek = $this->_lexer->peek(); // lookahead => token after the token after the '.' + $this->_lexer->resetPeek(); + + if ($this->_isMathOperator($peek)) { + return $this->SimpleArithmeticExpression(); + } + + return $this->StateFieldPathExpression(); + + case Lexer::T_INTEGER: + case Lexer::T_FLOAT: + return $this->SimpleArithmeticExpression(); + + case Lexer::T_STRING: + return $this->StringPrimary(); + + case Lexer::T_TRUE: + case Lexer::T_FALSE: + $this->match($lookahead); + + return new AST\Literal(AST\Literal::BOOLEAN, $this->_lexer->token['value']); + + case Lexer::T_INPUT_PARAMETER: + return $this->InputParameter(); + + case Lexer::T_CASE: + case Lexer::T_COALESCE: + case Lexer::T_NULLIF: + // Since NULLIF and COALESCE can be identified as a function, + // we need to check if before check for FunctionDeclaration + return $this->CaseExpression(); + + default: + if ( ! ($this->_isFunction() || $this->_isAggregateFunction($lookahead))) { + $this->syntaxError(); + } + + // We may be in an ArithmeticExpression (find the matching ")" and inspect for Math operator) + $this->_lexer->peek(); // "(" + $peek = $this->_peekBeyondClosingParenthesis(); + + if ($this->_isMathOperator($peek)) { + return $this->SimpleArithmeticExpression(); + } + + if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { + return $this->AggregateExpression(); + } + + return $this->FunctionDeclaration(); + } + } + + /** + * CaseExpression ::= GeneralCaseExpression | SimpleCaseExpression | CoalesceExpression | NullifExpression + * GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END" + * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression + * SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END" + * CaseOperand ::= StateFieldPathExpression | TypeDiscriminator + * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression + * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")" + * NullifExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")" + * + * @return mixed One of the possible expressions or subexpressions. + */ + public function CaseExpression() + { + $lookahead = $this->_lexer->lookahead['type']; + + switch ($lookahead) { + case Lexer::T_NULLIF: + return $this->NullIfExpression(); + + case Lexer::T_COALESCE: + return $this->CoalesceExpression(); + + case Lexer::T_CASE: + $this->_lexer->resetPeek(); + $peek = $this->_lexer->peek(); + + if ($peek['type'] === Lexer::T_WHEN) { + return $this->GeneralCaseExpression(); + } + + return $this->SimpleCaseExpression(); + + default: + // Do nothing + break; + } + + $this->syntaxError(); + } + + /** + * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")" + * + * @return \Doctrine\ORM\Query\AST\CoalesceExpression + */ + public function CoalesceExpression() + { + $this->match(Lexer::T_COALESCE); + $this->match(Lexer::T_OPEN_PARENTHESIS); + + // Process ScalarExpressions (1..N) + $scalarExpressions = array(); + $scalarExpressions[] = $this->ScalarExpression(); + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + + $scalarExpressions[] = $this->ScalarExpression(); + } + + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return new AST\CoalesceExpression($scalarExpressions); + } + + /** + * NullIfExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")" + * + * @return \Doctrine\ORM\Query\AST\NullIfExpression + */ + public function NullIfExpression() + { + $this->match(Lexer::T_NULLIF); + $this->match(Lexer::T_OPEN_PARENTHESIS); + + $firstExpression = $this->ScalarExpression(); + $this->match(Lexer::T_COMMA); + $secondExpression = $this->ScalarExpression(); + + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return new AST\NullIfExpression($firstExpression, $secondExpression); + } + + /** + * GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END" + * + * @return \Doctrine\ORM\Query\AST\GeneralExpression + */ + public function GeneralCaseExpression() + { + $this->match(Lexer::T_CASE); + + // Process WhenClause (1..N) + $whenClauses = array(); + + do { + $whenClauses[] = $this->WhenClause(); + } while ($this->_lexer->isNextToken(Lexer::T_WHEN)); + + $this->match(Lexer::T_ELSE); + $scalarExpression = $this->ScalarExpression(); + $this->match(Lexer::T_END); + + return new AST\GeneralCaseExpression($whenClauses, $scalarExpression); + } + + /** + * SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END" + * CaseOperand ::= StateFieldPathExpression | TypeDiscriminator + */ + public function SimpleCaseExpression() + { + $this->match(Lexer::T_CASE); + $caseOperand = $this->StateFieldPathExpression(); + + // Process SimpleWhenClause (1..N) + $simpleWhenClauses = array(); + + do { + $simpleWhenClauses[] = $this->SimpleWhenClause(); + } while ($this->_lexer->isNextToken(Lexer::T_WHEN)); + + $this->match(Lexer::T_ELSE); + $scalarExpression = $this->ScalarExpression(); + $this->match(Lexer::T_END); + + return new AST\SimpleCaseExpression($caseOperand, $simpleWhenClauses, $scalarExpression); + } + + /** + * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression + * + * @return \Doctrine\ORM\Query\AST\WhenExpression + */ + public function WhenClause() + { + $this->match(Lexer::T_WHEN); + $conditionalExpression = $this->ConditionalExpression(); + $this->match(Lexer::T_THEN); + + return new AST\WhenClause($conditionalExpression, $this->ScalarExpression()); + } + + /** + * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression + * + * @return \Doctrine\ORM\Query\AST\SimpleWhenExpression + */ + public function SimpleWhenClause() + { + $this->match(Lexer::T_WHEN); + $conditionalExpression = $this->ScalarExpression(); + $this->match(Lexer::T_THEN); + + return new AST\SimpleWhenClause($conditionalExpression, $this->ScalarExpression()); + } + + /** + * SelectExpression ::= ( + * IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | + * PartialObjectExpression | "(" Subselect ")" | CaseExpression + * ) [["AS"] ["HIDDEN"] AliasResultVariable] + * + * @return \Doctrine\ORM\Query\AST\SelectExpression + */ + public function SelectExpression() + { + $expression = null; + $identVariable = null; + $peek = $this->_lexer->glimpse(); + $lookaheadType = $this->_lexer->lookahead['type']; + + switch (true) { + // ScalarExpression (u.name) + case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT): + $expression = $this->ScalarExpression(); + break; + + // IdentificationVariable (u) + case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS): + $expression = $identVariable = $this->IdentificationVariable(); + break; + + // CaseExpression (CASE ... or NULLIF(...) or COALESCE(...)) + case ($lookaheadType === Lexer::T_CASE): + case ($lookaheadType === Lexer::T_COALESCE): + case ($lookaheadType === Lexer::T_NULLIF): + $expression = $this->CaseExpression(); + break; + + // DQL Function (SUM(u.value) or SUM(u.value) + 1) + case ($this->_isFunction()): + $this->_lexer->peek(); // "(" + + switch (true) { + case ($this->_isMathOperator($this->_peekBeyondClosingParenthesis())): + // SUM(u.id) + COUNT(u.id) + $expression = $this->ScalarExpression(); + break; + + case ($this->_isAggregateFunction($lookaheadType)): + // COUNT(u.id) + $expression = $this->AggregateExpression(); + break; + + default: + // IDENTITY(u) + $expression = $this->FunctionDeclaration(); + break; + } + + break; + + // PartialObjectExpression (PARTIAL u.{id, name}) + case ($lookaheadType === Lexer::T_PARTIAL): + $expression = $this->PartialObjectExpression(); + $identVariable = $expression->identificationVariable; + break; + + // Subselect + case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT): + $this->match(Lexer::T_OPEN_PARENTHESIS); + $expression = $this->Subselect(); + $this->match(Lexer::T_CLOSE_PARENTHESIS); + break; + + // Shortcut: ScalarExpression => SimpleArithmeticExpression + case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS): + case ($lookaheadType === Lexer::T_INTEGER): + case ($lookaheadType === Lexer::T_STRING): + case ($lookaheadType === Lexer::T_FLOAT): + // SimpleArithmeticExpression : (- u.value ) or ( + u.value ) + case ($lookaheadType === Lexer::T_MINUS): + case ($lookaheadType === Lexer::T_PLUS): + $expression = $this->SimpleArithmeticExpression(); + break; + + default: + $this->syntaxError( + 'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression', + $this->_lexer->lookahead + ); + } + + // [["AS"] ["HIDDEN"] AliasResultVariable] + + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + + $hiddenAliasResultVariable = false; + + if ($this->_lexer->isNextToken(Lexer::T_HIDDEN)) { + $this->match(Lexer::T_HIDDEN); + + $hiddenAliasResultVariable = true; + } + + $aliasResultVariable = null; + + if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { + $token = $this->_lexer->lookahead; + $aliasResultVariable = $this->AliasResultVariable(); + + // Include AliasResultVariable in query components. + $this->_queryComponents[$aliasResultVariable] = array( + 'resultVariable' => $expression, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $token, + ); + } + + // AST + + $expr = new AST\SelectExpression($expression, $aliasResultVariable, $hiddenAliasResultVariable); + + if ($identVariable) { + $this->_identVariableExpressions[$identVariable] = $expr; + } + + return $expr; + } + + /** + * SimpleSelectExpression ::= ( + * StateFieldPathExpression | IdentificationVariable | FunctionDeclaration | + * AggregateExpression | "(" Subselect ")" | ScalarExpression + * ) [["AS"] AliasResultVariable] + * + * @return \Doctrine\ORM\Query\AST\SimpleSelectExpression + */ + public function SimpleSelectExpression() + { + $peek = $this->_lexer->glimpse(); + + switch ($this->_lexer->lookahead['type']) { + case Lexer::T_IDENTIFIER: + switch (true) { + case ($peek['type'] === Lexer::T_DOT): + $expression = $this->StateFieldPathExpression(); + + return new AST\SimpleSelectExpression($expression); + + case ($peek['type'] !== Lexer::T_OPEN_PARENTHESIS): + $expression = $this->IdentificationVariable(); + + return new AST\SimpleSelectExpression($expression); + + case ($this->_isFunction()): + // SUM(u.id) + COUNT(u.id) + if ($this->_isMathOperator($this->_peekBeyondClosingParenthesis())) { + return new AST\SimpleSelectExpression($this->ScalarExpression()); + } + // COUNT(u.id) + if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { + return new AST\SimpleSelectExpression($this->AggregateExpression()); + } + // IDENTITY(u) + return new AST\SimpleSelectExpression($this->FunctionDeclaration()); + + default: + // Do nothing + } + break; + + case Lexer::T_OPEN_PARENTHESIS: + if ($peek['type'] !== Lexer::T_SELECT) { + // Shortcut: ScalarExpression => SimpleArithmeticExpression + $expression = $this->SimpleArithmeticExpression(); + + return new AST\SimpleSelectExpression($expression); + } + + // Subselect + $this->match(Lexer::T_OPEN_PARENTHESIS); + $expression = $this->Subselect(); + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return new AST\SimpleSelectExpression($expression); + + default: + // Do nothing + } + + $this->_lexer->peek(); + + $expression = $this->ScalarExpression(); + $expr = new AST\SimpleSelectExpression($expression); + + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + + if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { + $token = $this->_lexer->lookahead; + $resultVariable = $this->AliasResultVariable(); + $expr->fieldIdentificationVariable = $resultVariable; + + // Include AliasResultVariable in query components. + $this->_queryComponents[$resultVariable] = array( + 'resultvariable' => $expr, + 'nestingLevel' => $this->_nestingLevel, + 'token' => $token, + ); + } + + return $expr; + } + + /** + * ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}* + * + * @return \Doctrine\ORM\Query\AST\ConditionalExpression + */ + public function ConditionalExpression() + { + $conditionalTerms = array(); + $conditionalTerms[] = $this->ConditionalTerm(); + + while ($this->_lexer->isNextToken(Lexer::T_OR)) { + $this->match(Lexer::T_OR); + + $conditionalTerms[] = $this->ConditionalTerm(); + } + + // Phase 1 AST optimization: Prevent AST\ConditionalExpression + // if only one AST\ConditionalTerm is defined + if (count($conditionalTerms) == 1) { + return $conditionalTerms[0]; + } + + return new AST\ConditionalExpression($conditionalTerms); + } + + /** + * ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}* + * + * @return \Doctrine\ORM\Query\AST\ConditionalTerm + */ + public function ConditionalTerm() + { + $conditionalFactors = array(); + $conditionalFactors[] = $this->ConditionalFactor(); + + while ($this->_lexer->isNextToken(Lexer::T_AND)) { + $this->match(Lexer::T_AND); + + $conditionalFactors[] = $this->ConditionalFactor(); + } + + // Phase 1 AST optimization: Prevent AST\ConditionalTerm + // if only one AST\ConditionalFactor is defined + if (count($conditionalFactors) == 1) { + return $conditionalFactors[0]; + } + + return new AST\ConditionalTerm($conditionalFactors); + } + + /** + * ConditionalFactor ::= ["NOT"] ConditionalPrimary + * + * @return \Doctrine\ORM\Query\AST\ConditionalFactor + */ + public function ConditionalFactor() + { + $not = false; + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + + $not = true; + } + + $conditionalPrimary = $this->ConditionalPrimary(); + + // Phase 1 AST optimization: Prevent AST\ConditionalFactor + // if only one AST\ConditionalPrimary is defined + if ( ! $not) { + return $conditionalPrimary; + } + + $conditionalFactor = new AST\ConditionalFactor($conditionalPrimary); + $conditionalFactor->not = $not; + + return $conditionalFactor; + } + + /** + * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")" + * + * @return \Doctrine\ORM\Query\AST\ConditionalPrimary + */ + public function ConditionalPrimary() + { + $condPrimary = new AST\ConditionalPrimary; + + if ( ! $this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { + $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression(); + + return $condPrimary; + } + + // Peek beyond the matching closing paranthesis ')' + $peek = $this->_peekBeyondClosingParenthesis(); + + if (in_array($peek['value'], array("=", "<", "<=", "<>", ">", ">=", "!=")) || + in_array($peek['type'], array(Lexer::T_NOT, Lexer::T_BETWEEN, Lexer::T_LIKE, Lexer::T_IN, Lexer::T_IS, Lexer::T_EXISTS)) || + $this->_isMathOperator($peek)) { + $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression(); + + return $condPrimary; + } + + $this->match(Lexer::T_OPEN_PARENTHESIS); + $condPrimary->conditionalExpression = $this->ConditionalExpression(); + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return $condPrimary; + } + + /** + * SimpleConditionalExpression ::= + * ComparisonExpression | BetweenExpression | LikeExpression | + * InExpression | NullComparisonExpression | ExistsExpression | + * EmptyCollectionComparisonExpression | CollectionMemberExpression | + * InstanceOfExpression + */ + public function SimpleConditionalExpression() + { + $token = $this->_lexer->lookahead; + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $token = $this->_lexer->glimpse(); + } + + if ($token['type'] === Lexer::T_EXISTS) { + return $this->ExistsExpression(); + } + + $peek = $this->_lexer->glimpse(); + + if ($token['type'] === Lexer::T_IDENTIFIER || $token['type'] === Lexer::T_INPUT_PARAMETER) { + if ($peek['value'] == '(') { + // Peek beyond the matching closing paranthesis ')' + $this->_lexer->peek(); + $token = $this->_peekBeyondClosingParenthesis(false); + + if ($token['type'] === Lexer::T_NOT) { + $token = $this->_lexer->peek(); + } + + $this->_lexer->resetPeek(); + } else { + // Peek beyond the PathExpression (or InputParameter) + $peek = $this->_lexer->peek(); + + while ($peek['value'] === '.') { + $this->_lexer->peek(); + $peek = $this->_lexer->peek(); + } + + // Also peek beyond a NOT if there is one + if ($peek['type'] === Lexer::T_NOT) { + $peek = $this->_lexer->peek(); + } + + $token = $peek; + + // We need to go even further in case of IS (differenciate between NULL and EMPTY) + $lookahead = $this->_lexer->peek(); + + // Also peek beyond a NOT if there is one + if ($lookahead['type'] === Lexer::T_NOT) { + $lookahead = $this->_lexer->peek(); + } + + $this->_lexer->resetPeek(); + } + } + + switch ($token['type']) { + case Lexer::T_BETWEEN: + return $this->BetweenExpression(); + case Lexer::T_LIKE: + return $this->LikeExpression(); + case Lexer::T_IN: + return $this->InExpression(); + case Lexer::T_INSTANCE: + return $this->InstanceOfExpression(); + case Lexer::T_IS: + if ($lookahead['type'] == Lexer::T_NULL) { + return $this->NullComparisonExpression(); + } + return $this->EmptyCollectionComparisonExpression(); + case Lexer::T_MEMBER: + return $this->CollectionMemberExpression(); + default: + return $this->ComparisonExpression(); + } + } + + /** + * EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY" + * + * @return \Doctrine\ORM\Query\AST\EmptyCollectionComparisonExpression + */ + public function EmptyCollectionComparisonExpression() + { + $emptyColletionCompExpr = new AST\EmptyCollectionComparisonExpression( + $this->CollectionValuedPathExpression() + ); + $this->match(Lexer::T_IS); + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $emptyColletionCompExpr->not = true; + } + + $this->match(Lexer::T_EMPTY); + + return $emptyColletionCompExpr; + } + + /** + * CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression + * + * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression + * SimpleEntityExpression ::= IdentificationVariable | InputParameter + * + * @return \Doctrine\ORM\Query\AST\CollectionMemberExpression + */ + public function CollectionMemberExpression() + { + $not = false; + $entityExpr = $this->EntityExpression(); + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + + $not = true; + } + + $this->match(Lexer::T_MEMBER); + + if ($this->_lexer->isNextToken(Lexer::T_OF)) { + $this->match(Lexer::T_OF); + } + + $collMemberExpr = new AST\CollectionMemberExpression( + $entityExpr, $this->CollectionValuedPathExpression() + ); + $collMemberExpr->not = $not; + + return $collMemberExpr; + } + + /** + * Literal ::= string | char | integer | float | boolean + * + * @return string + */ + public function Literal() + { + switch ($this->_lexer->lookahead['type']) { + case Lexer::T_STRING: + $this->match(Lexer::T_STRING); + return new AST\Literal(AST\Literal::STRING, $this->_lexer->token['value']); + + case Lexer::T_INTEGER: + case Lexer::T_FLOAT: + $this->match( + $this->_lexer->isNextToken(Lexer::T_INTEGER) ? Lexer::T_INTEGER : Lexer::T_FLOAT + ); + return new AST\Literal(AST\Literal::NUMERIC, $this->_lexer->token['value']); + + case Lexer::T_TRUE: + case Lexer::T_FALSE: + $this->match( + $this->_lexer->isNextToken(Lexer::T_TRUE) ? Lexer::T_TRUE : Lexer::T_FALSE + ); + return new AST\Literal(AST\Literal::BOOLEAN, $this->_lexer->token['value']); + + default: + $this->syntaxError('Literal'); + } + } + + /** + * InParameter ::= Literal | InputParameter + * + * @return string | \Doctrine\ORM\Query\AST\InputParameter + */ + public function InParameter() + { + if ($this->_lexer->lookahead['type'] == Lexer::T_INPUT_PARAMETER) { + return $this->InputParameter(); + } + + return $this->Literal(); + } + + /** + * InputParameter ::= PositionalParameter | NamedParameter + * + * @return \Doctrine\ORM\Query\AST\InputParameter + */ + public function InputParameter() + { + $this->match(Lexer::T_INPUT_PARAMETER); + + return new AST\InputParameter($this->_lexer->token['value']); + } + + /** + * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")" + * + * @return \Doctrine\ORM\Query\AST\ArithmeticExpression + */ + public function ArithmeticExpression() + { + $expr = new AST\ArithmeticExpression; + + if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { + $peek = $this->_lexer->glimpse(); + + if ($peek['type'] === Lexer::T_SELECT) { + $this->match(Lexer::T_OPEN_PARENTHESIS); + $expr->subselect = $this->Subselect(); + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return $expr; + } + } + + $expr->simpleArithmeticExpression = $this->SimpleArithmeticExpression(); + + return $expr; + } + + /** + * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}* + * + * @return \Doctrine\ORM\Query\AST\SimpleArithmeticExpression + */ + public function SimpleArithmeticExpression() + { + $terms = array(); + $terms[] = $this->ArithmeticTerm(); + + while (($isPlus = $this->_lexer->isNextToken(Lexer::T_PLUS)) || $this->_lexer->isNextToken(Lexer::T_MINUS)) { + $this->match(($isPlus) ? Lexer::T_PLUS : Lexer::T_MINUS); + + $terms[] = $this->_lexer->token['value']; + $terms[] = $this->ArithmeticTerm(); + } + + // Phase 1 AST optimization: Prevent AST\SimpleArithmeticExpression + // if only one AST\ArithmeticTerm is defined + if (count($terms) == 1) { + return $terms[0]; + } + + return new AST\SimpleArithmeticExpression($terms); + } + + /** + * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}* + * + * @return \Doctrine\ORM\Query\AST\ArithmeticTerm + */ + public function ArithmeticTerm() + { + $factors = array(); + $factors[] = $this->ArithmeticFactor(); + + while (($isMult = $this->_lexer->isNextToken(Lexer::T_MULTIPLY)) || $this->_lexer->isNextToken(Lexer::T_DIVIDE)) { + $this->match(($isMult) ? Lexer::T_MULTIPLY : Lexer::T_DIVIDE); + + $factors[] = $this->_lexer->token['value']; + $factors[] = $this->ArithmeticFactor(); + } + + // Phase 1 AST optimization: Prevent AST\ArithmeticTerm + // if only one AST\ArithmeticFactor is defined + if (count($factors) == 1) { + return $factors[0]; + } + + return new AST\ArithmeticTerm($factors); + } + + /** + * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary + * + * @return \Doctrine\ORM\Query\AST\ArithmeticFactor + */ + public function ArithmeticFactor() + { + $sign = null; + + if (($isPlus = $this->_lexer->isNextToken(Lexer::T_PLUS)) || $this->_lexer->isNextToken(Lexer::T_MINUS)) { + $this->match(($isPlus) ? Lexer::T_PLUS : Lexer::T_MINUS); + $sign = $isPlus; + } + + $primary = $this->ArithmeticPrimary(); + + // Phase 1 AST optimization: Prevent AST\ArithmeticFactor + // if only one AST\ArithmeticPrimary is defined + if ($sign === null) { + return $primary; + } + + return new AST\ArithmeticFactor($primary, $sign); + } + + /** + * ArithmeticPrimary ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")" + * | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings + * | FunctionsReturningDatetime | IdentificationVariable | ResultVariable + * | InputParameter | CaseExpression + */ + public function ArithmeticPrimary() + { + if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { + $this->match(Lexer::T_OPEN_PARENTHESIS); + $expr = $this->SimpleArithmeticExpression(); + + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return $expr; + } + + switch ($this->_lexer->lookahead['type']) { + case Lexer::T_COALESCE: + case Lexer::T_NULLIF: + case Lexer::T_CASE: + return $this->CaseExpression(); + + case Lexer::T_IDENTIFIER: + $peek = $this->_lexer->glimpse(); + + if ($peek['value'] == '(') { + return $this->FunctionDeclaration(); + } + + if ($peek['value'] == '.') { + return $this->SingleValuedPathExpression(); + } + + if (isset($this->_queryComponents[$this->_lexer->lookahead['value']]['resultVariable'])) { + return $this->ResultVariable(); + } + + return $this->StateFieldPathExpression(); + + case Lexer::T_INPUT_PARAMETER: + return $this->InputParameter(); + + default: + $peek = $this->_lexer->glimpse(); + + if ($peek['value'] == '(') { + if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { + return $this->AggregateExpression(); + } + + return $this->FunctionDeclaration(); + } + + return $this->Literal(); + } + } + + /** + * StringExpression ::= StringPrimary | "(" Subselect ")" + * + * @return \Doctrine\ORM\Query\AST\StringPrimary | + * \Doctrine]ORM\Query\AST\Subselect + */ + public function StringExpression() + { + if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { + $peek = $this->_lexer->glimpse(); + + if ($peek['type'] === Lexer::T_SELECT) { + $this->match(Lexer::T_OPEN_PARENTHESIS); + $expr = $this->Subselect(); + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return $expr; + } + } + + return $this->StringPrimary(); + } + + /** + * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression | CaseExpression + */ + public function StringPrimary() + { + $lookaheadType = $this->_lexer->lookahead['type']; + + switch ($lookaheadType) { + case Lexer::T_IDENTIFIER: + $peek = $this->_lexer->glimpse(); + + if ($peek['value'] == '.') { + return $this->StateFieldPathExpression(); + } + + if ($peek['value'] == '(') { + // do NOT directly go to FunctionsReturningString() because it doesnt check for custom functions. + return $this->FunctionDeclaration(); + } + + $this->syntaxError("'.' or '('"); + break; + + case Lexer::T_STRING: + $this->match(Lexer::T_STRING); + + return new AST\Literal(AST\Literal::STRING, $this->_lexer->token['value']); + + case Lexer::T_INPUT_PARAMETER: + return $this->InputParameter(); + + case Lexer::T_CASE: + case Lexer::T_COALESCE: + case Lexer::T_NULLIF: + return $this->CaseExpression(); + + default: + if ($this->_isAggregateFunction($lookaheadType)) { + return $this->AggregateExpression(); + } + } + + $this->syntaxError( + 'StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression' + ); + } + + /** + * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression + * + * @return \Doctrine\ORM\Query\AST\SingleValuedAssociationPathExpression | + * \Doctrine\ORM\Query\AST\SimpleEntityExpression + */ + public function EntityExpression() + { + $glimpse = $this->_lexer->glimpse(); + + if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER) && $glimpse['value'] === '.') { + return $this->SingleValuedAssociationPathExpression(); + } + + return $this->SimpleEntityExpression(); + } + + /** + * SimpleEntityExpression ::= IdentificationVariable | InputParameter + * + * @return string | \Doctrine\ORM\Query\AST\InputParameter + */ + public function SimpleEntityExpression() + { + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + return $this->InputParameter(); + } + + return $this->StateFieldPathExpression(); + } + + /** + * AggregateExpression ::= + * ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | + * "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedPathExpression) ")" + * + * @return \Doctrine\ORM\Query\AST\AggregateExpression + */ + public function AggregateExpression() + { + $lookaheadType = $this->_lexer->lookahead['type']; + $isDistinct = false; + + if ( ! in_array($lookaheadType, array(Lexer::T_COUNT, Lexer::T_AVG, Lexer::T_MAX, Lexer::T_MIN, Lexer::T_SUM))) { + $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT'); + } + + $this->match($lookaheadType); + $functionName = $this->_lexer->token['value']; + $this->match(Lexer::T_OPEN_PARENTHESIS); + + if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { + $this->match(Lexer::T_DISTINCT); + $isDistinct = true; + } + + $pathExp = ($lookaheadType === Lexer::T_COUNT) + ? $this->SingleValuedPathExpression() + : $this->SimpleArithmeticExpression(); + + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return new AST\AggregateExpression($functionName, $pathExp, $isDistinct); + } + + /** + * QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")" + * + * @return \Doctrine\ORM\Query\AST\QuantifiedExpression + */ + public function QuantifiedExpression() + { + $lookaheadType = $this->_lexer->lookahead['type']; + $value = $this->_lexer->lookahead['value']; + + if ( ! in_array($lookaheadType, array(Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME))) { + $this->syntaxError('ALL, ANY or SOME'); + } + + $this->match($lookaheadType); + $this->match(Lexer::T_OPEN_PARENTHESIS); + + $qExpr = new AST\QuantifiedExpression($this->Subselect()); + $qExpr->type = $value; + + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return $qExpr; + } + + /** + * BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression + * + * @return \Doctrine\ORM\Query\AST\BetweenExpression + */ + public function BetweenExpression() + { + $not = false; + $arithExpr1 = $this->ArithmeticExpression(); + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $not = true; + } + + $this->match(Lexer::T_BETWEEN); + $arithExpr2 = $this->ArithmeticExpression(); + $this->match(Lexer::T_AND); + $arithExpr3 = $this->ArithmeticExpression(); + + $betweenExpr = new AST\BetweenExpression($arithExpr1, $arithExpr2, $arithExpr3); + $betweenExpr->not = $not; + + return $betweenExpr; + } + + /** + * ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) + * + * @return \Doctrine\ORM\Query\AST\ComparisonExpression + */ + public function ComparisonExpression() + { + $this->_lexer->glimpse(); + + $leftExpr = $this->ArithmeticExpression(); + $operator = $this->ComparisonOperator(); + $rightExpr = ($this->_isNextAllAnySome()) + ? $this->QuantifiedExpression() + : $this->ArithmeticExpression(); + + return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr); + } + + /** + * InExpression ::= SingleValuedPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")" + * + * @return \Doctrine\ORM\Query\AST\InExpression + */ + public function InExpression() + { + $inExpression = new AST\InExpression($this->ArithmeticExpression()); + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $inExpression->not = true; + } + + $this->match(Lexer::T_IN); + $this->match(Lexer::T_OPEN_PARENTHESIS); + + if ($this->_lexer->isNextToken(Lexer::T_SELECT)) { + $inExpression->subselect = $this->Subselect(); + } else { + $literals = array(); + $literals[] = $this->InParameter(); + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + $literals[] = $this->InParameter(); + } + + $inExpression->literals = $literals; + } + + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return $inExpression; + } + + /** + * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")") + * + * @return \Doctrine\ORM\Query\AST\InstanceOfExpression + */ + public function InstanceOfExpression() + { + $instanceOfExpression = new AST\InstanceOfExpression($this->IdentificationVariable()); + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $instanceOfExpression->not = true; + } + + $this->match(Lexer::T_INSTANCE); + $this->match(Lexer::T_OF); + + $exprValues = array(); + + if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { + $this->match(Lexer::T_OPEN_PARENTHESIS); + + $exprValues[] = $this->InstanceOfParameter(); + + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + + $exprValues[] = $this->InstanceOfParameter(); + } + + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + $instanceOfExpression->value = $exprValues; + + return $instanceOfExpression; + } + + $exprValues[] = $this->InstanceOfParameter(); + + $instanceOfExpression->value = $exprValues; + + return $instanceOfExpression; + } + + /** + * InstanceOfParameter ::= AbstractSchemaName | InputParameter + * + * @return mixed + */ + public function InstanceOfParameter() + { + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + $this->match(Lexer::T_INPUT_PARAMETER); + + return new AST\InputParameter($this->_lexer->token['value']); + } + + return $this->AliasIdentificationVariable(); + } + + /** + * LikeExpression ::= StringExpression ["NOT"] "LIKE" StringPrimary ["ESCAPE" char] + * + * @return \Doctrine\ORM\Query\AST\LikeExpression + */ + public function LikeExpression() + { + $stringExpr = $this->StringExpression(); + $not = false; + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $not = true; + } + + $this->match(Lexer::T_LIKE); + + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + $this->match(Lexer::T_INPUT_PARAMETER); + $stringPattern = new AST\InputParameter($this->_lexer->token['value']); + } else { + $stringPattern = $this->StringPrimary(); + } + + $escapeChar = null; + + if ($this->_lexer->lookahead['type'] === Lexer::T_ESCAPE) { + $this->match(Lexer::T_ESCAPE); + $this->match(Lexer::T_STRING); + + $escapeChar = new AST\Literal(AST\Literal::STRING, $this->_lexer->token['value']); + } + + $likeExpr = new AST\LikeExpression($stringExpr, $stringPattern, $escapeChar); + $likeExpr->not = $not; + + return $likeExpr; + } + + /** + * NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL" + * + * @return \Doctrine\ORM\Query\AST\NullComparisonExpression + */ + public function NullComparisonExpression() + { + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + $this->match(Lexer::T_INPUT_PARAMETER); + $expr = new AST\InputParameter($this->_lexer->token['value']); + } else { + $expr = $this->SingleValuedPathExpression(); + } + + $nullCompExpr = new AST\NullComparisonExpression($expr); + $this->match(Lexer::T_IS); + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $nullCompExpr->not = true; + } + + $this->match(Lexer::T_NULL); + + return $nullCompExpr; + } + + /** + * ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")" + * + * @return \Doctrine\ORM\Query\AST\ExistsExpression + */ + public function ExistsExpression() + { + $not = false; + + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $not = true; + } + + $this->match(Lexer::T_EXISTS); + $this->match(Lexer::T_OPEN_PARENTHESIS); + + $existsExpression = new AST\ExistsExpression($this->Subselect()); + $existsExpression->not = $not; + + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + return $existsExpression; + } + + /** + * ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!=" + * + * @return string + */ + public function ComparisonOperator() + { + switch ($this->_lexer->lookahead['value']) { + case '=': + $this->match(Lexer::T_EQUALS); + + return '='; + + case '<': + $this->match(Lexer::T_LOWER_THAN); + $operator = '<'; + + if ($this->_lexer->isNextToken(Lexer::T_EQUALS)) { + $this->match(Lexer::T_EQUALS); + $operator .= '='; + } else if ($this->_lexer->isNextToken(Lexer::T_GREATER_THAN)) { + $this->match(Lexer::T_GREATER_THAN); + $operator .= '>'; + } + + return $operator; + + case '>': + $this->match(Lexer::T_GREATER_THAN); + $operator = '>'; + + if ($this->_lexer->isNextToken(Lexer::T_EQUALS)) { + $this->match(Lexer::T_EQUALS); + $operator .= '='; + } + + return $operator; + + case '!': + $this->match(Lexer::T_NEGATE); + $this->match(Lexer::T_EQUALS); + + return '<>'; + + default: + $this->syntaxError('=, <, <=, <>, >, >=, !='); + } + } + + /** + * FunctionDeclaration ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime + */ + public function FunctionDeclaration() + { + $token = $this->_lexer->lookahead; + $funcName = strtolower($token['value']); + + // Check for built-in functions first! + switch (true) { + case (isset(self::$_STRING_FUNCTIONS[$funcName])): + return $this->FunctionsReturningStrings(); + + case (isset(self::$_NUMERIC_FUNCTIONS[$funcName])): + return $this->FunctionsReturningNumerics(); + + case (isset(self::$_DATETIME_FUNCTIONS[$funcName])): + return $this->FunctionsReturningDatetime(); + + default: + return $this->CustomFunctionDeclaration(); + } + } + + /** + * Helper function for FunctionDeclaration grammar rule + */ + private function CustomFunctionDeclaration() + { + $token = $this->_lexer->lookahead; + $funcName = strtolower($token['value']); + + // Check for custom functions afterwards + $config = $this->_em->getConfiguration(); + + switch (true) { + case ($config->getCustomStringFunction($funcName) !== null): + return $this->CustomFunctionsReturningStrings(); + + case ($config->getCustomNumericFunction($funcName) !== null): + return $this->CustomFunctionsReturningNumerics(); + + case ($config->getCustomDatetimeFunction($funcName) !== null): + return $this->CustomFunctionsReturningDatetime(); + + default: + $this->syntaxError('known function', $token); + } + } + + /** + * FunctionsReturningNumerics ::= + * "LENGTH" "(" StringPrimary ")" | + * "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" | + * "ABS" "(" SimpleArithmeticExpression ")" | + * "SQRT" "(" SimpleArithmeticExpression ")" | + * "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | + * "SIZE" "(" CollectionValuedPathExpression ")" + */ + public function FunctionsReturningNumerics() + { + $funcNameLower = strtolower($this->_lexer->lookahead['value']); + $funcClass = self::$_NUMERIC_FUNCTIONS[$funcNameLower]; + + $function = new $funcClass($funcNameLower); + $function->parse($this); + + return $function; + } + + public function CustomFunctionsReturningNumerics() + { + // getCustomNumericFunction is case-insensitive + $funcName = strtolower($this->_lexer->lookahead['value']); + $funcClass = $this->_em->getConfiguration()->getCustomNumericFunction($funcName); + + $function = new $funcClass($funcName); + $function->parse($this); + + return $function; + } + + /** + * FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP" + */ + public function FunctionsReturningDatetime() + { + $funcNameLower = strtolower($this->_lexer->lookahead['value']); + $funcClass = self::$_DATETIME_FUNCTIONS[$funcNameLower]; + + $function = new $funcClass($funcNameLower); + $function->parse($this); + + return $function; + } + + public function CustomFunctionsReturningDatetime() + { + // getCustomDatetimeFunction is case-insensitive + $funcName = $this->_lexer->lookahead['value']; + $funcClass = $this->_em->getConfiguration()->getCustomDatetimeFunction($funcName); + + $function = new $funcClass($funcName); + $function->parse($this); + + return $function; + } + + /** + * FunctionsReturningStrings ::= + * "CONCAT" "(" StringPrimary "," StringPrimary ")" | + * "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | + * "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" | + * "LOWER" "(" StringPrimary ")" | + * "UPPER" "(" StringPrimary ")" + */ + public function FunctionsReturningStrings() + { + $funcNameLower = strtolower($this->_lexer->lookahead['value']); + $funcClass = self::$_STRING_FUNCTIONS[$funcNameLower]; + + $function = new $funcClass($funcNameLower); + $function->parse($this); + + return $function; + } + + public function CustomFunctionsReturningStrings() + { + // getCustomStringFunction is case-insensitive + $funcName = $this->_lexer->lookahead['value']; + $funcClass = $this->_em->getConfiguration()->getCustomStringFunction($funcName); + + $function = new $funcClass($funcName); + $function->parse($this); + + return $function; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ParserResult.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ParserResult.php new file mode 100644 index 0000000..e068622 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ParserResult.php @@ -0,0 +1,138 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * Encapsulates the resulting components from a DQL query parsing process that + * can be serialized. + * + * @author Guilherme Blanco + * @author Janne Vanhala + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + */ +class ParserResult +{ + /** + * The SQL executor used for executing the SQL. + * + * @var \Doctrine\ORM\Query\Exec\AbstractSqlExecutor + */ + private $_sqlExecutor; + + /** + * The ResultSetMapping that describes how to map the SQL result set. + * + * @var \Doctrine\ORM\Query\ResultSetMapping + */ + private $_resultSetMapping; + + /** + * The mappings of DQL parameter names/positions to SQL parameter positions. + * + * @var array + */ + private $_parameterMappings = array(); + + /** + * Initializes a new instance of the ParserResult class. + * The new instance is initialized with an empty ResultSetMapping. + */ + public function __construct() + { + $this->_resultSetMapping = new ResultSetMapping; + } + + /** + * Gets the ResultSetMapping for the parsed query. + * + * @return ResultSetMapping The result set mapping of the parsed query or NULL + * if the query is not a SELECT query. + */ + public function getResultSetMapping() + { + return $this->_resultSetMapping; + } + + /** + * Sets the ResultSetMapping of the parsed query. + * + * @param ResultSetMapping $rsm + */ + public function setResultSetMapping(ResultSetMapping $rsm) + { + $this->_resultSetMapping = $rsm; + } + + /** + * Sets the SQL executor that should be used for this ParserResult. + * + * @param \Doctrine\ORM\Query\Exec\AbstractSqlExecutor $executor + */ + public function setSqlExecutor($executor) + { + $this->_sqlExecutor = $executor; + } + + /** + * Gets the SQL executor used by this ParserResult. + * + * @return \Doctrine\ORM\Query\Exec\AbstractSqlExecutor + */ + public function getSqlExecutor() + { + return $this->_sqlExecutor; + } + + /** + * Adds a DQL to SQL parameter mapping. One DQL parameter name/position can map to + * several SQL parameter positions. + * + * @param string|integer $dqlPosition + * @param integer $sqlPosition + */ + public function addParameterMapping($dqlPosition, $sqlPosition) + { + $this->_parameterMappings[$dqlPosition][] = $sqlPosition; + } + + /** + * Gets all DQL to SQL parameter mappings. + * + * @return array The parameter mappings. + */ + public function getParameterMappings() + { + return $this->_parameterMappings; + } + + /** + * Gets the SQL parameter positions for a DQL parameter name/position. + * + * @param string|integer $dqlPosition The name or position of the DQL parameter. + * @return array The positions of the corresponding SQL parameters. + */ + public function getSqlParameterPositions($dqlPosition) + { + return $this->_parameterMappings[$dqlPosition]; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Printer.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Printer.php new file mode 100644 index 0000000..83640c5 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/Printer.php @@ -0,0 +1,92 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * A parse tree printer for Doctrine Query Language parser. + * + * @author Janne Vanhala + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + */ +class Printer +{ + /** + * Current indentation level + * + * @var int + */ + protected $_indent = 0; + + /** + * Defines whether parse tree is printed (default, false) or not (true). + * + * @var bool + */ + protected $_silent; + + /** + * Constructs a new parse tree printer. + * + * @param bool $silent Parse tree will not be printed if true. + */ + public function __construct($silent = false) + { + $this->_silent = $silent; + } + + /** + * Prints an opening parenthesis followed by production name and increases + * indentation level by one. + * + * This method is called before executing a production. + * + * @param string $name production name + */ + public function startProduction($name) + { + $this->println('(' . $name); + $this->_indent++; + } + + /** + * Decreases indentation level by one and prints a closing parenthesis. + * + * This method is called after executing a production. + */ + public function endProduction() + { + $this->_indent--; + $this->println(')'); + } + + /** + * Prints text indented with spaces depending on current indentation level. + * + * @param string $str text + */ + public function println($str) + { + if ( ! $this->_silent) { + echo str_repeat(' ', $this->_indent), $str, "\n"; + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php new file mode 100644 index 0000000..6a03c8c --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php @@ -0,0 +1,156 @@ +. + */ + +namespace Doctrine\ORM\Query; + +use Doctrine\ORM\Query\AST\PathExpression; + +/** + * Description of QueryException + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class QueryException extends \Doctrine\ORM\ORMException +{ + public static function dqlError($dql) + { + return new self($dql); + } + + public static function syntaxError($message, $previous = null) + { + return new self('[Syntax Error] ' . $message, 0, $previous); + } + + public static function semanticalError($message, $previous = null) + { + return new self('[Semantical Error] ' . $message, 0, $previous); + } + + public static function invalidLockMode() + { + return new self('Invalid lock mode hint provided.'); + } + + public static function invalidParameterType($expected, $received) + { + return new self('Invalid parameter type, ' . $received . ' given, but ' . $expected . ' expected.'); + } + + public static function invalidParameterPosition($pos) + { + return new self('Invalid parameter position: ' . $pos); + } + + public static function invalidParameterNumber() + { + return new self("Invalid parameter number: number of bound variables does not match number of tokens"); + } + + public static function invalidParameterFormat($value) + { + return new self('Invalid parameter format, '.$value.' given, but : or ? expected.'); + } + + public static function unknownParameter($key) + { + return new self("Invalid parameter: token ".$key." is not defined in the query."); + } + + public static function parameterTypeMissmatch() + { + return new self("DQL Query parameter and type numbers missmatch, but have to be exactly equal."); + } + + public static function invalidPathExpression($pathExpr) + { + return new self( + "Invalid PathExpression '" . $pathExpr->identificationVariable . "." . $pathExpr->field . "'." + ); + } + + public static function invalidLiteral($literal) { + return new self("Invalid literal '$literal'"); + } + + /** + * @param array $assoc + */ + public static function iterateWithFetchJoinCollectionNotAllowed($assoc) + { + return new self( + "Invalid query operation: Not allowed to iterate over fetch join collections ". + "in class ".$assoc['sourceEntity']." assocation ".$assoc['fieldName'] + ); + } + + public static function partialObjectsAreDangerous() + { + return new self( + "Loading partial objects is dangerous. Fetch full objects or consider " . + "using a different fetch mode. If you really want partial objects, " . + "set the doctrine.forcePartialLoad query hint to TRUE." + ); + } + + public static function overwritingJoinConditionsNotYetSupported($assoc) + { + return new self( + "Unsupported query operation: It is not yet possible to overwrite the join ". + "conditions in class ".$assoc['sourceEntityName']." assocation ".$assoc['fieldName'].". ". + "Use WITH to append additional join conditions to the association." + ); + } + + public static function associationPathInverseSideNotSupported() + { + return new self( + "A single-valued association path expression to an inverse side is not supported". + " in DQL queries. Use an explicit join instead." + ); + } + + public static function iterateWithFetchJoinNotAllowed($assoc) { + return new self( + "Iterate with fetch join in class " . $assoc['sourceEntity'] . + " using association " . $assoc['fieldName'] . " not allowed." + ); + } + + public static function associationPathCompositeKeyNotSupported() + { + return new self( + "A single-valued association path expression to an entity with a composite primary ". + "key is not supported. Explicitly name the components of the composite primary key ". + "in the query." + ); + } + + public static function instanceOfUnrelatedClass($className, $rootClass) + { + return new self("Cannot check if a child of '" . $rootClass . "' is instanceof '" . $className . "', " . + "inheritance hierachy exists between these two classes."); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ResultSetMapping.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ResultSetMapping.php new file mode 100644 index 0000000..b8cbd32 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ResultSetMapping.php @@ -0,0 +1,485 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * A ResultSetMapping describes how a result set of an SQL query maps to a Doctrine result. + * + * IMPORTANT NOTE: + * The properties of this class are only public for fast internal READ access and to (drastically) + * reduce the size of serialized instances for more effective caching due to better (un-)serialization + * performance. + * + * Users should use the public methods. + * + * @author Roman Borschel + * @since 2.0 + * @todo Think about whether the number of lookup maps can be reduced. + */ +class ResultSetMapping +{ + /** + * @ignore + * @var boolean Whether the result is mixed (contains scalar values together with field values). + */ + public $isMixed = false; + + /** + * @ignore + * @var array Maps alias names to class names. + */ + public $aliasMap = array(); + + /** + * @ignore + * @var array Maps alias names to related association field names. + */ + public $relationMap = array(); + + /** + * @ignore + * @var array Maps alias names to parent alias names. + */ + public $parentAliasMap = array(); + + /** + * @ignore + * @var array Maps column names in the result set to field names for each class. + */ + public $fieldMappings = array(); + + /** + * @ignore + * @var array Maps column names in the result set to the alias/field name to use in the mapped result. + */ + public $scalarMappings = array(); + + /** + * @ignore + * @var array Maps column names in the result set to the alias/field type to use in the mapped result. + */ + public $typeMappings = array(); + + /** + * @ignore + * @var array Maps entities in the result set to the alias name to use in the mapped result. + */ + public $entityMappings = array(); + + /** + * @ignore + * @var array Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names. + */ + public $metaMappings = array(); + + /** + * @ignore + * @var array Maps column names in the result set to the alias they belong to. + */ + public $columnOwnerMap = array(); + + /** + * @ignore + * @var array List of columns in the result set that are used as discriminator columns. + */ + public $discriminatorColumns = array(); + + /** + * @ignore + * @var array Maps alias names to field names that should be used for indexing. + */ + public $indexByMap = array(); + + /** + * @ignore + * @var array Map from column names to class names that declare the field the column is mapped to. + */ + public $declaringClasses = array(); + + /** + * @var array This is necessary to hydrate derivate foreign keys correctly. + */ + public $isIdentifierColumn = array(); + + /** + * Adds an entity result to this ResultSetMapping. + * + * @param string $class The class name of the entity. + * @param string $alias The alias for the class. The alias must be unique among all entity + * results or joined entity results within this ResultSetMapping. + * @param string $resultAlias The result alias with which the entity result should be + * placed in the result structure. + * @return ResultSetMapping This ResultSetMapping instance. + * @todo Rename: addRootEntity + */ + public function addEntityResult($class, $alias, $resultAlias = null) + { + $this->aliasMap[$alias] = $class; + $this->entityMappings[$alias] = $resultAlias; + + if ($resultAlias !== null) { + $this->isMixed = true; + } + + return $this; + } + + /** + * Sets a discriminator column for an entity result or joined entity result. + * The discriminator column will be used to determine the concrete class name to + * instantiate. + * + * @param string $alias The alias of the entity result or joined entity result the discriminator + * column should be used for. + * @param string $discrColumn The name of the discriminator column in the SQL result set. + * @return ResultSetMapping This ResultSetMapping instance. + * @todo Rename: addDiscriminatorColumn + */ + public function setDiscriminatorColumn($alias, $discrColumn) + { + $this->discriminatorColumns[$alias] = $discrColumn; + $this->columnOwnerMap[$discrColumn] = $alias; + + return $this; + } + + /** + * Sets a field to use for indexing an entity result or joined entity result. + * + * @param string $alias The alias of an entity result or joined entity result. + * @param string $fieldName The name of the field to use for indexing. + * @return ResultSetMapping This ResultSetMapping instance. + */ + public function addIndexBy($alias, $fieldName) + { + $found = false; + + foreach ($this->fieldMappings as $columnName => $columnFieldName) { + if ( ! ($columnFieldName === $fieldName && $this->columnOwnerMap[$columnName] === $alias)) continue; + + $this->addIndexByColumn($alias, $columnName); + $found = true; + + break; + } + + /* TODO: check if this exception can be put back, for now it's gone because of assumptions made by some ORM internals + if ( ! $found) { + $message = sprintf( + 'Cannot add index by for DQL alias %s and field %s without calling addFieldResult() for them before.', + $alias, + $fieldName + ); + + throw new \LogicException($message); + } + */ + + return $this; + } + + /** + * Set to index by a scalar result column name + * + * @param $resultColumnName + * @return ResultSetMapping This ResultSetMapping instance. + */ + public function addIndexByScalar($resultColumnName) + { + $this->indexByMap['scalars'] = $resultColumnName; + + return $this; + } + + /** + * Sets a column to use for indexing an entity or joined entity result by the given alias name. + * + * @param $alias + * @param $resultColumnName + * @return ResultSetMapping This ResultSetMapping instance. + */ + public function addIndexByColumn($alias, $resultColumnName) + { + $this->indexByMap[$alias] = $resultColumnName; + + return $this; + } + + /** + * Checks whether an entity result or joined entity result with a given alias has + * a field set for indexing. + * + * @param string $alias + * @return boolean + * @todo Rename: isIndexed($alias) + */ + public function hasIndexBy($alias) + { + return isset($this->indexByMap[$alias]); + } + + /** + * Checks whether the column with the given name is mapped as a field result + * as part of an entity result or joined entity result. + * + * @param string $columnName The name of the column in the SQL result set. + * @return boolean + * @todo Rename: isField + */ + public function isFieldResult($columnName) + { + return isset($this->fieldMappings[$columnName]); + } + + /** + * Adds a field to the result that belongs to an entity or joined entity. + * + * @param string $alias The alias of the root entity or joined entity to which the field belongs. + * @param string $columnName The name of the column in the SQL result set. + * @param string $fieldName The name of the field on the declaring class. + * @param string $declaringClass The name of the class that declares/owns the specified field. + * When $alias refers to a superclass in a mapped hierarchy but + * the field $fieldName is defined on a subclass, specify that here. + * If not specified, the field is assumed to belong to the class + * designated by $alias. + * @return ResultSetMapping This ResultSetMapping instance. + * @todo Rename: addField + */ + public function addFieldResult($alias, $columnName, $fieldName, $declaringClass = null) + { + // column name (in result set) => field name + $this->fieldMappings[$columnName] = $fieldName; + // column name => alias of owner + $this->columnOwnerMap[$columnName] = $alias; + // field name => class name of declaring class + $this->declaringClasses[$columnName] = $declaringClass ?: $this->aliasMap[$alias]; + + if ( ! $this->isMixed && $this->scalarMappings) { + $this->isMixed = true; + } + + return $this; + } + + /** + * Adds a joined entity result. + * + * @param string $class The class name of the joined entity. + * @param string $alias The unique alias to use for the joined entity. + * @param string $parentAlias The alias of the entity result that is the parent of this joined result. + * @param object $relation The association field that connects the parent entity result with the joined entity result. + * @return ResultSetMapping This ResultSetMapping instance. + * @todo Rename: addJoinedEntity + */ + public function addJoinedEntityResult($class, $alias, $parentAlias, $relation) + { + $this->aliasMap[$alias] = $class; + $this->parentAliasMap[$alias] = $parentAlias; + $this->relationMap[$alias] = $relation; + + return $this; + } + + /** + * Adds a scalar result mapping. + * + * @param string $columnName The name of the column in the SQL result set. + * @param string $alias The result alias with which the scalar result should be placed in the result structure. + * @param string $type The column type + * + * @return ResultSetMapping This ResultSetMapping instance. + * + * @todo Rename: addScalar + */ + public function addScalarResult($columnName, $alias, $type = 'string') + { + $this->scalarMappings[$columnName] = $alias; + $this->typeMappings[$columnName] = $type; + + if ( ! $this->isMixed && $this->fieldMappings) { + $this->isMixed = true; + } + + return $this; + } + + /** + * Checks whether a column with a given name is mapped as a scalar result. + * + * @param string $columName The name of the column in the SQL result set. + * @return boolean + * @todo Rename: isScalar + */ + public function isScalarResult($columnName) + { + return isset($this->scalarMappings[$columnName]); + } + + /** + * Gets the name of the class of an entity result or joined entity result, + * identified by the given unique alias. + * + * @param string $alias + * @return string + */ + public function getClassName($alias) + { + return $this->aliasMap[$alias]; + } + + /** + * Gets the field alias for a column that is mapped as a scalar value. + * + * @param string $columnName The name of the column in the SQL result set. + * @return string + */ + public function getScalarAlias($columnName) + { + return $this->scalarMappings[$columnName]; + } + + /** + * Gets the name of the class that owns a field mapping for the specified column. + * + * @param string $columnName + * @return string + */ + public function getDeclaringClass($columnName) + { + return $this->declaringClasses[$columnName]; + } + + /** + * + * @param string $alias + * @return AssociationMapping + */ + public function getRelation($alias) + { + return $this->relationMap[$alias]; + } + + /** + * + * @param string $alias + * @return boolean + */ + public function isRelation($alias) + { + return isset($this->relationMap[$alias]); + } + + /** + * Gets the alias of the class that owns a field mapping for the specified column. + * + * @param string $columnName + * @return string + */ + public function getEntityAlias($columnName) + { + return $this->columnOwnerMap[$columnName]; + } + + /** + * Gets the parent alias of the given alias. + * + * @param string $alias + * @return string + */ + public function getParentAlias($alias) + { + return $this->parentAliasMap[$alias]; + } + + /** + * Checks whether the given alias has a parent alias. + * + * @param string $alias + * @return boolean + */ + public function hasParentAlias($alias) + { + return isset($this->parentAliasMap[$alias]); + } + + /** + * Gets the field name for a column name. + * + * @param string $columnName + * @return string + */ + public function getFieldName($columnName) + { + return $this->fieldMappings[$columnName]; + } + + /** + * + * @return array + */ + public function getAliasMap() + { + return $this->aliasMap; + } + + /** + * Gets the number of different entities that appear in the mapped result. + * + * @return integer + */ + public function getEntityResultCount() + { + return count($this->aliasMap); + } + + /** + * Checks whether this ResultSetMapping defines a mixed result. + * Mixed results can only occur in object and array (graph) hydration. In such a + * case a mixed result means that scalar values are mixed with objects/array in + * the result. + * + * @return boolean + */ + public function isMixedResult() + { + return $this->isMixed; + } + + /** + * Adds a meta column (foreign key or discriminator column) to the result set. + * + * @param string $alias + * @param string $columnName + * @param string $fieldName + * @param bool + * @return ResultSetMapping This ResultSetMapping instance. + */ + public function addMetaResult($alias, $columnName, $fieldName, $isIdentifierColumn = false) + { + $this->metaMappings[$columnName] = $fieldName; + $this->columnOwnerMap[$columnName] = $alias; + + if ($isIdentifierColumn) { + $this->isIdentifierColumn[$alias][$columnName] = true; + } + + return $this; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php new file mode 100644 index 0000000..8e31bcf --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php @@ -0,0 +1,264 @@ +. + */ + +namespace Doctrine\ORM\Query; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Mapping\ClassMetadataInfo; + +/** + * A ResultSetMappingBuilder uses the EntityManager to automatically populate entity fields + * + * @author Michael Ridgway + * @since 2.1 + */ +class ResultSetMappingBuilder extends ResultSetMapping +{ + /** + * @var EntityManager + */ + private $em; + + /** + * @param EntityManager + */ + public function __construct(EntityManager $em) + { + $this->em = $em; + } + + /** + * Adds a root entity and all of its fields to the result set. + * + * @param string $class The class name of the root entity. + * @param string $alias The unique alias to use for the root entity. + * @param array $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName) + */ + public function addRootEntityFromClassMetadata($class, $alias, $renamedColumns = array()) + { + $this->addEntityResult($class, $alias); + $this->addAllClassFields($class, $alias, $renamedColumns); + } + + /** + * Adds a joined entity and all of its fields to the result set. + * + * @param string $class The class name of the joined entity. + * @param string $alias The unique alias to use for the joined entity. + * @param string $parentAlias The alias of the entity result that is the parent of this joined result. + * @param object $relation The association field that connects the parent entity result with the joined entity result. + * @param array $renamedColumns Columns that have been renamed (tableColumnName => queryColumnName) + */ + public function addJoinedEntityFromClassMetadata($class, $alias, $parentAlias, $relation, $renamedColumns = array()) + { + $this->addJoinedEntityResult($class, $alias, $parentAlias, $relation); + $this->addAllClassFields($class, $alias, $renamedColumns); + } + + /** + * Adds all fields of the given class to the result set mapping (columns and meta fields) + */ + protected function addAllClassFields($class, $alias, $renamedColumns = array()) + { + $classMetadata = $this->em->getClassMetadata($class); + if ($classMetadata->isInheritanceTypeSingleTable() || $classMetadata->isInheritanceTypeJoined()) { + throw new \InvalidArgumentException('ResultSetMapping builder does not currently support inheritance.'); + } + $platform = $this->em->getConnection()->getDatabasePlatform(); + foreach ($classMetadata->getColumnNames() as $columnName) { + $propertyName = $classMetadata->getFieldName($columnName); + if (isset($renamedColumns[$columnName])) { + $columnName = $renamedColumns[$columnName]; + } + $columnName = $platform->getSQLResultCasing($columnName); + if (isset($this->fieldMappings[$columnName])) { + throw new \InvalidArgumentException("The column '$columnName' conflicts with another column in the mapper."); + } + $this->addFieldResult($alias, $columnName, $propertyName); + } + foreach ($classMetadata->associationMappings as $associationMapping) { + if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) { + foreach ($associationMapping['joinColumns'] as $joinColumn) { + $columnName = $joinColumn['name']; + $renamedColumnName = isset($renamedColumns[$columnName]) ? $renamedColumns[$columnName] : $columnName; + $renamedColumnName = $platform->getSQLResultCasing($renamedColumnName); + if (isset($this->metaMappings[$renamedColumnName])) { + throw new \InvalidArgumentException("The column '$renamedColumnName' conflicts with another column in the mapper."); + } + $this->addMetaResult($alias, $renamedColumnName, $columnName); + } + } + } + } + + + /** + * Adds the mappings of the results of native SQL queries to the result set. + * + * @param ClassMetadataInfo $class + * @param array $queryMapping + * @return ResultSetMappingBuilder + */ + public function addNamedNativeQueryMapping(ClassMetadataInfo $class, array $queryMapping) + { + if (isset($queryMapping['resultClass'])) { + return $this->addNamedNativeQueryResultClassMapping($class, $queryMapping['resultClass']); + } + + return $this->addNamedNativeQueryResultSetMapping($class, $queryMapping['resultSetMapping']); + } + + /** + * Adds the class mapping of the results of native SQL queries to the result set. + * + * @param ClassMetadataInfo $class + * @param string $resultClassName + * @return ResultSetMappingBuilder + */ + public function addNamedNativeQueryResultClassMapping(ClassMetadataInfo $class, $resultClassName) + { + + $classMetadata = $this->em->getClassMetadata($resultClassName); + $shortName = $classMetadata->reflClass->getShortName(); + $alias = strtolower($shortName[0]).'0'; + + $this->addEntityResult($class->name, $alias); + + if ($classMetadata->discriminatorColumn) { + $discriminatorColumn = $classMetadata->discriminatorColumn; + $this->setDiscriminatorColumn($alias, $discriminatorColumn['name']); + $this->addMetaResult($alias, $discriminatorColumn['name'], $discriminatorColumn['fieldName']); + } + + foreach ($classMetadata->getColumnNames() as $key => $columnName) { + $propertyName = $classMetadata->getFieldName($columnName); + $this->addFieldResult($alias, $columnName, $propertyName); + } + + foreach ($classMetadata->associationMappings as $associationMapping) { + if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) { + foreach ($associationMapping['joinColumns'] as $joinColumn) { + $columnName = $joinColumn['name']; + $this->addMetaResult($alias, $columnName, $columnName, $classMetadata->isIdentifier($columnName)); + } + } + } + + return $this; + } + + /** + * Adds the result set mapping of the results of native SQL queries to the result set. + * + * @param ClassMetadataInfo $class + * @param string $resultSetMappingName + * @return ResultSetMappingBuilder + */ + public function addNamedNativeQueryResultSetMapping(ClassMetadataInfo $class, $resultSetMappingName) + { + $counter = 0; + $resultMapping = $class->getSqlResultSetMapping($resultSetMappingName); + $rooShortName = $class->reflClass->getShortName(); + $rootAlias = strtolower($rooShortName[0]) . $counter; + + + if (isset($resultMapping['entities'])) { + foreach ($resultMapping['entities'] as $key => $entityMapping) { + $classMetadata = $this->em->getClassMetadata($entityMapping['entityClass']); + + if ($class->reflClass->name == $classMetadata->reflClass->name) { + $this->addEntityResult($classMetadata->name, $rootAlias); + $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $rootAlias); + } else { + $shortName = $classMetadata->reflClass->getShortName(); + $joinAlias = strtolower($shortName[0]) . ++ $counter; + $associations = $class->getAssociationsByTargetClass($classMetadata->name); + + foreach ($associations as $relation => $mapping) { + $this->addJoinedEntityResult($mapping['targetEntity'], $joinAlias, $rootAlias, $relation); + $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $joinAlias); + } + } + + } + } + + if (isset($resultMapping['columns'])) { + foreach ($resultMapping['columns'] as $entityMapping) { + $this->addScalarResult($entityMapping['name'], $entityMapping['name']); + } + } + + return $this; + } + + /** + * Adds the entity result mapping of the results of native SQL queries to the result set. + * + * @param ClassMetadataInfo $classMetadata + * @param array $entityMapping + * @param string $alias + * @return ResultSetMappingBuilder + */ + public function addNamedNativeQueryEntityResultMapping(ClassMetadataInfo $classMetadata, array $entityMapping, $alias) + { + if (isset($entityMapping['discriminatorColumn']) && $entityMapping['discriminatorColumn']) { + $discriminatorColumn = $entityMapping['discriminatorColumn']; + $this->setDiscriminatorColumn($alias, $discriminatorColumn); + $this->addMetaResult($alias, $discriminatorColumn, $discriminatorColumn); + } + + if (isset($entityMapping['fields']) && !empty($entityMapping['fields'])) { + foreach ($entityMapping['fields'] as $field) { + $fieldName = $field['name']; + $relation = null; + + if(strpos($fieldName, '.')){ + list($relation, $fieldName) = explode('.', $fieldName); + } + + if (isset($classMetadata->associationMappings[$relation])) { + if($relation) { + $associationMapping = $classMetadata->associationMappings[$relation]; + $joinAlias = $alias.$relation; + $parentAlias = $alias; + + $this->addJoinedEntityResult($associationMapping['targetEntity'], $joinAlias, $parentAlias, $relation); + $this->addFieldResult($joinAlias, $field['column'], $fieldName); + }else { + $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name); + } + } else { + if(!isset($classMetadata->fieldMappings[$fieldName])) { + throw new \InvalidArgumentException("Entity '".$classMetadata->name."' has no field '".$fieldName."'. "); + } + $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name); + } + } + + } else { + foreach ($classMetadata->getColumnNames() as $columnName) { + $propertyName = $classMetadata->getFieldName($columnName); + $this->addFieldResult($alias, $columnName, $propertyName); + } + } + + return $this; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php new file mode 100644 index 0000000..13c2b5d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php @@ -0,0 +1,2202 @@ +. + */ + +namespace Doctrine\ORM\Query; + +use Doctrine\DBAL\LockMode, + Doctrine\DBAL\Types\Type, + Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\Query, + Doctrine\ORM\Query\QueryException, + Doctrine\ORM\Mapping\ClassMetadataInfo; + +/** + * The SqlWalker is a TreeWalker that walks over a DQL AST and constructs + * the corresponding SQL. + * + * @author Guilherme Blanco + * @author Roman Borschel + * @author Benjamin Eberlei + * @author Alexander + * @since 2.0 + * @todo Rename: SQLWalker + */ +class SqlWalker implements TreeWalker +{ + /** + * @var string + */ + const HINT_DISTINCT = 'doctrine.distinct'; + + /** + * @var ResultSetMapping + */ + private $rsm; + + /** + * Counters for generating unique column aliases. + * + * @var integer + */ + private $aliasCounter = 0; + + /** + * Counters for generating unique table aliases. + * + * @var integer + */ + private $tableAliasCounter = 0; + + /** + * Counters for generating unique scalar result. + * + * @var integer + */ + private $scalarResultCounter = 1; + + /** + * Counters for generating unique parameter indexes. + * + * @var integer + */ + private $sqlParamIndex = 0; + + /** + * @var ParserResult + */ + private $parserResult; + + /** + * @var EntityManager + */ + private $em; + + /** + * @var \Doctrine\DBAL\Connection + */ + private $conn; + + /** + * @var AbstractQuery + */ + private $query; + + /** + * @var array + */ + private $tableAliasMap = array(); + + /** + * Map from result variable names to their SQL column alias names. + * + * @var array + */ + private $scalarResultAliasMap = array(); + + /** + * Map from DQL-Alias + Field-Name to SQL Column Alias + * + * @var array + */ + private $scalarFields = array(); + + /** + * Map of all components/classes that appear in the DQL query. + * + * @var array + */ + private $queryComponents; + + /** + * A list of classes that appear in non-scalar SelectExpressions. + * + * @var array + */ + private $selectedClasses = array(); + + /** + * The DQL alias of the root class of the currently traversed query. + * + * @var array + */ + private $rootAliases = array(); + + /** + * Flag that indicates whether to generate SQL table aliases in the SQL. + * These should only be generated for SELECT queries, not for UPDATE/DELETE. + * + * @var boolean + */ + private $useSqlTableAliases = true; + + /** + * The database platform abstraction. + * + * @var AbstractPlatform + */ + private $platform; + + /** + * The quote strategy. + * + * @var \Doctrine\ORM\Mapping\QuoteStrategy + */ + private $quoteStrategy; + + /** + * {@inheritDoc} + */ + public function __construct($query, $parserResult, array $queryComponents) + { + $this->query = $query; + $this->parserResult = $parserResult; + $this->queryComponents = $queryComponents; + $this->rsm = $parserResult->getResultSetMapping(); + $this->em = $query->getEntityManager(); + $this->conn = $this->em->getConnection(); + $this->platform = $this->conn->getDatabasePlatform(); + $this->quoteStrategy = $this->em->getConfiguration()->getQuoteStrategy(); + } + + /** + * Gets the Query instance used by the walker. + * + * @return Query. + */ + public function getQuery() + { + return $this->query; + } + + /** + * Gets the Connection used by the walker. + * + * @return Connection + */ + public function getConnection() + { + return $this->conn; + } + + /** + * Gets the EntityManager used by the walker. + * + * @return EntityManager + */ + public function getEntityManager() + { + return $this->em; + } + + /** + * Gets the information about a single query component. + * + * @param string $dqlAlias The DQL alias. + * @return array + */ + public function getQueryComponent($dqlAlias) + { + return $this->queryComponents[$dqlAlias]; + } + + /** + * Gets an executor that can be used to execute the result of this walker. + * + * @return AbstractExecutor + */ + public function getExecutor($AST) + { + switch (true) { + case ($AST instanceof AST\DeleteStatement): + $primaryClass = $this->em->getClassMetadata($AST->deleteClause->abstractSchemaName); + + return ($primaryClass->isInheritanceTypeJoined()) + ? new Exec\MultiTableDeleteExecutor($AST, $this) + : new Exec\SingleTableDeleteUpdateExecutor($AST, $this); + + case ($AST instanceof AST\UpdateStatement): + $primaryClass = $this->em->getClassMetadata($AST->updateClause->abstractSchemaName); + + return ($primaryClass->isInheritanceTypeJoined()) + ? new Exec\MultiTableUpdateExecutor($AST, $this) + : new Exec\SingleTableDeleteUpdateExecutor($AST, $this); + + default: + return new Exec\SingleSelectExecutor($AST, $this); + } + } + + /** + * Generates a unique, short SQL table alias. + * + * @param string $tableName Table name + * @param string $dqlAlias The DQL alias. + * @return string Generated table alias. + */ + public function getSQLTableAlias($tableName, $dqlAlias = '') + { + $tableName .= ($dqlAlias) ? '@[' . $dqlAlias . ']' : ''; + + if ( ! isset($this->tableAliasMap[$tableName])) { + $this->tableAliasMap[$tableName] = strtolower(substr($tableName, 0, 1)) . $this->tableAliasCounter++ . '_'; + } + + return $this->tableAliasMap[$tableName]; + } + + /** + * Forces the SqlWalker to use a specific alias for a table name, rather than + * generating an alias on its own. + * + * @param string $tableName + * @param string $alias + * @param string $dqlAlias + * @return string + */ + public function setSQLTableAlias($tableName, $alias, $dqlAlias = '') + { + $tableName .= ($dqlAlias) ? '@[' . $dqlAlias . ']' : ''; + + $this->tableAliasMap[$tableName] = $alias; + + return $alias; + } + + /** + * Gets an SQL column alias for a column name. + * + * @param string $columnName + * @return string + */ + public function getSQLColumnAlias($columnName) + { + return $this->quoteStrategy->getColumnAlias($columnName, $this->aliasCounter++, $this->platform); + } + + /** + * Generates the SQL JOINs that are necessary for Class Table Inheritance + * for the given class. + * + * @param ClassMetadata $class The class for which to generate the joins. + * @param string $dqlAlias The DQL alias of the class. + * @return string The SQL. + */ + private function _generateClassTableInheritanceJoins($class, $dqlAlias) + { + $sql = ''; + + $baseTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); + + // INNER JOIN parent class tables + foreach ($class->parentClasses as $parentClassName) { + $parentClass = $this->em->getClassMetadata($parentClassName); + $tableAlias = $this->getSQLTableAlias($parentClass->getTableName(), $dqlAlias); + + // If this is a joined association we must use left joins to preserve the correct result. + $sql .= isset($this->queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER '; + $sql .= 'JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON '; + + $sqlParts = array(); + + foreach ($this->quoteStrategy->getIdentifierColumnNames($class, $this->platform) as $columnName) { + $sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; + } + + // Add filters on the root class + if ($filterSql = $this->generateFilterConditionSQL($parentClass, $tableAlias)) { + $sqlParts[] = $filterSql; + } + + $sql .= implode(' AND ', $sqlParts); + } + + // Ignore subclassing inclusion if partial objects is disallowed + if ($this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) { + return $sql; + } + + // LEFT JOIN child class tables + foreach ($class->subClasses as $subClassName) { + $subClass = $this->em->getClassMetadata($subClassName); + $tableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); + + $sql .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->platform) . ' ' . $tableAlias . ' ON '; + + $sqlParts = array(); + + foreach ($this->quoteStrategy->getIdentifierColumnNames($subClass, $this->platform) as $columnName) { + $sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; + } + + $sql .= implode(' AND ', $sqlParts); + } + + return $sql; + } + + private function _generateOrderedCollectionOrderByItems() + { + $sqlParts = array(); + + foreach ($this->selectedClasses as $selectedClass) { + $dqlAlias = $selectedClass['dqlAlias']; + $qComp = $this->queryComponents[$dqlAlias]; + + if ( ! isset($qComp['relation']['orderBy'])) continue; + + foreach ($qComp['relation']['orderBy'] as $fieldName => $orientation) { + $columnName = $this->quoteStrategy->getColumnName($fieldName, $qComp['metadata'], $this->platform); + $tableName = ($qComp['metadata']->isInheritanceTypeJoined()) + ? $this->em->getUnitOfWork()->getEntityPersister($qComp['metadata']->name)->getOwningTable($fieldName) + : $qComp['metadata']->getTableName(); + + $sqlParts[] = $this->getSQLTableAlias($tableName, $dqlAlias) . '.' . $columnName . ' ' . $orientation; + } + } + + return implode(', ', $sqlParts); + } + + /** + * Generates a discriminator column SQL condition for the class with the given DQL alias. + * + * @param array $dqlAliases List of root DQL aliases to inspect for discriminator restrictions. + * @return string + */ + private function _generateDiscriminatorColumnConditionSQL(array $dqlAliases) + { + $sqlParts = array(); + + foreach ($dqlAliases as $dqlAlias) { + $class = $this->queryComponents[$dqlAlias]['metadata']; + + if ( ! $class->isInheritanceTypeSingleTable()) continue; + + $conn = $this->em->getConnection(); + $values = array(); + + if ($class->discriminatorValue !== null) { // discrimnators can be 0 + $values[] = $conn->quote($class->discriminatorValue); + } + + foreach ($class->subClasses as $subclassName) { + $values[] = $conn->quote($this->em->getClassMetadata($subclassName)->discriminatorValue); + } + + $sqlParts[] = (($this->useSqlTableAliases) ? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.' : '') + . $class->discriminatorColumn['name'] . ' IN (' . implode(', ', $values) . ')'; + } + + $sql = implode(' AND ', $sqlParts); + + return (count($sqlParts) > 1) ? '(' . $sql . ')' : $sql; + } + + /** + * Generates the filter SQL for a given entity and table alias. + * + * @param ClassMetadata $targetEntity Metadata of the target entity. + * @param string $targetTableAlias The table alias of the joined/selected table. + * + * @return string The SQL query part to add to a query. + */ + private function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) + { + if (!$this->em->hasFilters()) { + return ''; + } + + switch($targetEntity->inheritanceType) { + case ClassMetadata::INHERITANCE_TYPE_NONE: + break; + case ClassMetadata::INHERITANCE_TYPE_JOINED: + // The classes in the inheritance will be added to the query one by one, + // but only the root node is getting filtered + if ($targetEntity->name !== $targetEntity->rootEntityName) { + return ''; + } + break; + case ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE: + // With STI the table will only be queried once, make sure that the filters + // are added to the root entity + $targetEntity = $this->em->getClassMetadata($targetEntity->rootEntityName); + break; + default: + //@todo: throw exception? + return ''; + break; + } + + $filterClauses = array(); + foreach ($this->em->getFilters()->getEnabledFilters() as $filter) { + if ('' !== $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) { + $filterClauses[] = '(' . $filterExpr . ')'; + } + } + + return implode(' AND ', $filterClauses); + } + /** + * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkSelectStatement(AST\SelectStatement $AST) + { + $sql = $this->walkSelectClause($AST->selectClause); + $sql .= $this->walkFromClause($AST->fromClause); + $sql .= $this->walkWhereClause($AST->whereClause); + $sql .= $AST->groupByClause ? $this->walkGroupByClause($AST->groupByClause) : ''; + $sql .= $AST->havingClause ? $this->walkHavingClause($AST->havingClause) : ''; + + if (($orderByClause = $AST->orderByClause) !== null) { + $sql .= $AST->orderByClause ? $this->walkOrderByClause($AST->orderByClause) : ''; + } else if (($orderBySql = $this->_generateOrderedCollectionOrderByItems()) !== '') { + $sql .= ' ORDER BY ' . $orderBySql; + } + + $sql = $this->platform->modifyLimitQuery( + $sql, $this->query->getMaxResults(), $this->query->getFirstResult() + ); + + if (($lockMode = $this->query->getHint(Query::HINT_LOCK_MODE)) !== false) { + switch ($lockMode) { + case LockMode::PESSIMISTIC_READ: + $sql .= ' ' . $this->platform->getReadLockSQL(); + break; + + case LockMode::PESSIMISTIC_WRITE: + $sql .= ' ' . $this->platform->getWriteLockSQL(); + break; + + case LockMode::OPTIMISTIC: + foreach ($this->selectedClasses as $selectedClass) { + if ( ! $selectedClass['class']->isVersioned) { + throw \Doctrine\ORM\OptimisticLockException::lockFailed($selectedClass['class']->name); + } + } + break; + case LockMode::NONE: + break; + + default: + throw \Doctrine\ORM\Query\QueryException::invalidLockMode(); + } + } + + return $sql; + } + + /** + * Walks down an UpdateStatement AST node, thereby generating the appropriate SQL. + * + * @param UpdateStatement + * @return string The SQL. + */ + public function walkUpdateStatement(AST\UpdateStatement $AST) + { + $this->useSqlTableAliases = false; + + return $this->walkUpdateClause($AST->updateClause) + . $this->walkWhereClause($AST->whereClause); + } + + /** + * Walks down a DeleteStatement AST node, thereby generating the appropriate SQL. + * + * @param DeleteStatement + * @return string The SQL. + */ + public function walkDeleteStatement(AST\DeleteStatement $AST) + { + $this->useSqlTableAliases = false; + + return $this->walkDeleteClause($AST->deleteClause) + . $this->walkWhereClause($AST->whereClause); + } + + /** + * Walks down an IdentificationVariable AST node, thereby generating the appropriate SQL. + * This one differs of ->walkIdentificationVariable() because it generates the entity identifiers. + * + * @param string $identVariable + * @return string + */ + public function walkEntityIdentificationVariable($identVariable) + { + $class = $this->queryComponents[$identVariable]['metadata']; + $tableAlias = $this->getSQLTableAlias($class->getTableName(), $identVariable); + $sqlParts = array(); + + foreach ($this->quoteStrategy->getIdentifierColumnNames($class, $this->platform) as $columnName) { + $sqlParts[] = $tableAlias . '.' . $columnName; + } + + return implode(', ', $sqlParts); + } + + /** + * Walks down an IdentificationVariable (no AST node associated), thereby generating the SQL. + * + * @param string $identificationVariable + * @param string $fieldName + * @return string The SQL. + */ + public function walkIdentificationVariable($identificationVariable, $fieldName = null) + { + $class = $this->queryComponents[$identificationVariable]['metadata']; + + if ( + $fieldName !== null && $class->isInheritanceTypeJoined() && + isset($class->fieldMappings[$fieldName]['inherited']) + ) { + $class = $this->em->getClassMetadata($class->fieldMappings[$fieldName]['inherited']); + } + + return $this->getSQLTableAlias($class->getTableName(), $identificationVariable); + } + + /** + * Walks down a PathExpression AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkPathExpression($pathExpr) + { + $sql = ''; + + switch ($pathExpr->type) { + case AST\PathExpression::TYPE_STATE_FIELD: + $fieldName = $pathExpr->field; + $dqlAlias = $pathExpr->identificationVariable; + $class = $this->queryComponents[$dqlAlias]['metadata']; + + if ($this->useSqlTableAliases) { + $sql .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.'; + } + + $sql .= $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); + break; + + case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION: + // 1- the owning side: + // Just use the foreign key, i.e. u.group_id + $fieldName = $pathExpr->field; + $dqlAlias = $pathExpr->identificationVariable; + $class = $this->queryComponents[$dqlAlias]['metadata']; + + if (isset($class->associationMappings[$fieldName]['inherited'])) { + $class = $this->em->getClassMetadata($class->associationMappings[$fieldName]['inherited']); + } + + $assoc = $class->associationMappings[$fieldName]; + + if ( ! $assoc['isOwningSide']) { + throw QueryException::associationPathInverseSideNotSupported(); + } + + // COMPOSITE KEYS NOT (YET?) SUPPORTED + if (count($assoc['sourceToTargetKeyColumns']) > 1) { + throw QueryException::associationPathCompositeKeyNotSupported(); + } + + if ($this->useSqlTableAliases) { + $sql .= $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.'; + } + + $sql .= reset($assoc['targetToSourceKeyColumns']); + break; + + default: + throw QueryException::invalidPathExpression($pathExpr); + } + + return $sql; + } + + /** + * Walks down a SelectClause AST node, thereby generating the appropriate SQL. + * + * @param $selectClause + * @return string The SQL. + */ + public function walkSelectClause($selectClause) + { + $sql = 'SELECT ' . (($selectClause->isDistinct) ? 'DISTINCT ' : ''); + $sqlSelectExpressions = array_filter(array_map(array($this, 'walkSelectExpression'), $selectClause->selectExpressions)); + + if ($this->query->getHint(Query::HINT_INTERNAL_ITERATION) == true && $selectClause->isDistinct) { + $this->query->setHint(self::HINT_DISTINCT, true); + } + + $addMetaColumns = ! $this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) && + $this->query->getHydrationMode() == Query::HYDRATE_OBJECT + || + $this->query->getHydrationMode() != Query::HYDRATE_OBJECT && + $this->query->getHint(Query::HINT_INCLUDE_META_COLUMNS); + + foreach ($this->selectedClasses as $selectedClass) { + $class = $selectedClass['class']; + $dqlAlias = $selectedClass['dqlAlias']; + $resultAlias = $selectedClass['resultAlias']; + + // Register as entity or joined entity result + if ($this->queryComponents[$dqlAlias]['relation'] === null) { + $this->rsm->addEntityResult($class->name, $dqlAlias, $resultAlias); + } else { + $this->rsm->addJoinedEntityResult( + $class->name, + $dqlAlias, + $this->queryComponents[$dqlAlias]['parent'], + $this->queryComponents[$dqlAlias]['relation']['fieldName'] + ); + } + + if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) { + // Add discriminator columns to SQL + $rootClass = $this->em->getClassMetadata($class->rootEntityName); + $tblAlias = $this->getSQLTableAlias($rootClass->getTableName(), $dqlAlias); + $discrColumn = $rootClass->discriminatorColumn; + $columnAlias = $this->getSQLColumnAlias($discrColumn['name']); + + $sqlSelectExpressions[] = $tblAlias . '.' . $discrColumn['name'] . ' AS ' . $columnAlias; + + $this->rsm->setDiscriminatorColumn($dqlAlias, $columnAlias); + $this->rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']); + } + + // Add foreign key columns to SQL, if necessary + if ( ! $addMetaColumns && ! $class->containsForeignIdentifier) { + continue; + } + + // Add foreign key columns of class and also parent classes + foreach ($class->associationMappings as $assoc) { + if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) { + continue; + } else if ( !$addMetaColumns && !isset($assoc['id'])) { + continue; + } + + $owningClass = (isset($assoc['inherited'])) ? $this->em->getClassMetadata($assoc['inherited']) : $class; + $sqlTableAlias = $this->getSQLTableAlias($owningClass->getTableName(), $dqlAlias); + + foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { + $columnAlias = $this->getSQLColumnAlias($srcColumn); + + $sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias; + + $this->rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true)); + } + } + + // Add foreign key columns to SQL, if necessary + if ( ! $addMetaColumns) { + continue; + } + + // Add foreign key columns of subclasses + foreach ($class->subClasses as $subClassName) { + $subClass = $this->em->getClassMetadata($subClassName); + $sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); + + foreach ($subClass->associationMappings as $assoc) { + // Skip if association is inherited + if (isset($assoc['inherited'])) continue; + + if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) continue; + + foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { + $columnAlias = $this->getSQLColumnAlias($srcColumn); + + $sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias; + + $this->rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn); + } + } + } + } + + $sql .= implode(', ', $sqlSelectExpressions); + + return $sql; + } + + /** + * Walks down a FromClause AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkFromClause($fromClause) + { + $identificationVarDecls = $fromClause->identificationVariableDeclarations; + $sqlParts = array(); + + foreach ($identificationVarDecls as $identificationVariableDecl) { + $sql = $this->walkRangeVariableDeclaration($identificationVariableDecl->rangeVariableDeclaration); + + foreach ($identificationVariableDecl->joins as $join) { + $sql .= $this->walkJoin($join); + } + + if ($identificationVariableDecl->indexBy) { + $alias = $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->identificationVariable; + $field = $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->field; + + if (isset($this->scalarFields[$alias][$field])) { + $this->rsm->addIndexByScalar($this->scalarFields[$alias][$field]); + } else { + $this->rsm->addIndexBy( + $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->identificationVariable, + $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->field + ); + } + } + + $sqlParts[] = $this->platform->appendLockHint($sql, $this->query->getHint(Query::HINT_LOCK_MODE)); + } + + return ' FROM ' . implode(', ', $sqlParts); + } + + /** + * Walks down a RangeVariableDeclaration AST node, thereby generating the appropriate SQL. + * + * @return string + */ + public function walkRangeVariableDeclaration($rangeVariableDeclaration) + { + $class = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName); + $dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable; + + $this->rootAliases[] = $dqlAlias; + + $sql = $class->getQuotedTableName($this->platform) . ' ' + . $this->getSQLTableAlias($class->getTableName(), $dqlAlias); + + if ($class->isInheritanceTypeJoined()) { + $sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias); + } + + return $sql; + } + + /** + * Walks down a JoinAssociationDeclaration AST node, thereby generating the appropriate SQL. + * + * @return string + */ + public function walkJoinAssociationDeclaration($joinAssociationDeclaration, $joinType = AST\Join::JOIN_TYPE_INNER) + { + $sql = ''; + + $associationPathExpression = $joinAssociationDeclaration->joinAssociationPathExpression; + $joinedDqlAlias = $joinAssociationDeclaration->aliasIdentificationVariable; + $indexBy = $joinAssociationDeclaration->indexBy; + + $relation = $this->queryComponents[$joinedDqlAlias]['relation']; + $targetClass = $this->em->getClassMetadata($relation['targetEntity']); + $sourceClass = $this->em->getClassMetadata($relation['sourceEntity']); + $targetTableName = $targetClass->getQuotedTableName($this->platform); + + $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias); + $sourceTableAlias = $this->getSQLTableAlias($sourceClass->getTableName(), $associationPathExpression->identificationVariable); + + // Ensure we got the owning side, since it has all mapping info + $assoc = ( ! $relation['isOwningSide']) ? $targetClass->associationMappings[$relation['mappedBy']] : $relation; + + if ($this->query->getHint(Query::HINT_INTERNAL_ITERATION) == true && (!$this->query->getHint(self::HINT_DISTINCT) || isset($this->selectedClasses[$joinedDqlAlias]))) { + if ($relation['type'] == ClassMetadata::ONE_TO_MANY || $relation['type'] == ClassMetadata::MANY_TO_MANY) { + throw QueryException::iterateWithFetchJoinNotAllowed($assoc); + } + } + + // This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot + // be the owning side and previously we ensured that $assoc is always the owning side of the associations. + // The owning side is necessary at this point because only it contains the JoinColumn information. + switch (true) { + case ($assoc['type'] & ClassMetadata::TO_ONE): + $conditions = array(); + + foreach ($assoc['joinColumns'] as $joinColumn) { + $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); + $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); + + if ($relation['isOwningSide']) { + $conditions[] = $sourceTableAlias . '.' . $quotedSourceColumn . ' = ' . $targetTableAlias . '.' . $quotedTargetColumn; + + continue; + } + + $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $quotedSourceColumn; + } + + // Apply remaining inheritance restrictions + $discrSql = $this->_generateDiscriminatorColumnConditionSQL(array($joinedDqlAlias)); + + if ($discrSql) { + $conditions[] = $discrSql; + } + + // Apply the filters + $filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias); + + if ($filterExpr) { + $conditions[] = $filterExpr; + } + + $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions); + break; + + case ($assoc['type'] == ClassMetadata::MANY_TO_MANY): + // Join relation table + $joinTable = $assoc['joinTable']; + $joinTableAlias = $this->getSQLTableAlias($joinTable['name'], $joinedDqlAlias); + $joinTableName = $sourceClass->getQuotedJoinTableName($assoc, $this->platform); + + $conditions = array(); + $relationColumns = ($relation['isOwningSide']) + ? $assoc['joinTable']['joinColumns'] + : $assoc['joinTable']['inverseJoinColumns']; + + foreach ($relationColumns as $joinColumn) { + $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); + $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); + + $conditions[] = $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $quotedSourceColumn; + } + + $sql .= $joinTableName . ' ' . $joinTableAlias . ' ON ' . implode(' AND ', $conditions); + + // Join target table + $sql .= ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) ? ' LEFT JOIN ' : ' INNER JOIN '; + + $conditions = array(); + $relationColumns = ($relation['isOwningSide']) + ? $assoc['joinTable']['inverseJoinColumns'] + : $assoc['joinTable']['joinColumns']; + + foreach ($relationColumns as $joinColumn) { + $quotedSourceColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); + $quotedTargetColumn = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); + + $conditions[] = $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $quotedSourceColumn; + } + + // Apply remaining inheritance restrictions + $discrSql = $this->_generateDiscriminatorColumnConditionSQL(array($joinedDqlAlias)); + + if ($discrSql) { + $conditions[] = $discrSql; + } + + // Apply the filters + $filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias); + + if ($filterExpr) { + $conditions[] = $filterExpr; + } + + $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ' . implode(' AND ', $conditions); + break; + } + + // FIXME: these should either be nested or all forced to be left joins (DDC-XXX) + if ($targetClass->isInheritanceTypeJoined()) { + $sql .= $this->_generateClassTableInheritanceJoins($targetClass, $joinedDqlAlias); + } + + // Apply the indexes + if ($indexBy) { + // For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently. + $this->rsm->addIndexBy( + $indexBy->simpleStateFieldPathExpression->identificationVariable, + $indexBy->simpleStateFieldPathExpression->field + ); + } else if (isset($relation['indexBy'])) { + $this->rsm->addIndexBy($joinedDqlAlias, $relation['indexBy']); + } + + return $sql; + } + + /** + * Walks down a FunctionNode AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkFunction($function) + { + return $function->getSql($this); + } + + /** + * Walks down an OrderByClause AST node, thereby generating the appropriate SQL. + * + * @param OrderByClause + * @return string The SQL. + */ + public function walkOrderByClause($orderByClause) + { + $orderByItems = array_map(array($this, 'walkOrderByItem'), $orderByClause->orderByItems); + + if (($collectionOrderByItems = $this->_generateOrderedCollectionOrderByItems()) !== '') { + $orderByItems = array_merge($orderByItems, (array) $collectionOrderByItems); + } + + return ' ORDER BY ' . implode(', ', $orderByItems); + } + + /** + * Walks down an OrderByItem AST node, thereby generating the appropriate SQL. + * + * @param OrderByItem + * @return string The SQL. + */ + public function walkOrderByItem($orderByItem) + { + $expr = $orderByItem->expression; + $sql = ($expr instanceof AST\Node) + ? $expr->dispatch($this) + : $this->walkResultVariable($this->queryComponents[$expr]['token']['value']); + + return $sql . ' ' . strtoupper($orderByItem->type); + } + + /** + * Walks down a HavingClause AST node, thereby generating the appropriate SQL. + * + * @param HavingClause + * @return string The SQL. + */ + public function walkHavingClause($havingClause) + { + return ' HAVING ' . $this->walkConditionalExpression($havingClause->conditionalExpression); + } + + /** + * Walks down a Join AST node and creates the corresponding SQL. + * + * @return string The SQL. + */ + public function walkJoin($join) + { + $joinType = $join->joinType; + $joinDeclaration = $join->joinAssociationDeclaration; + + $sql = ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) + ? ' LEFT JOIN ' + : ' INNER JOIN '; + + switch (true) { + case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\RangeVariableDeclaration): + $sql .= $this->walkRangeVariableDeclaration($joinDeclaration) + . ' ON (' . $this->walkConditionalExpression($join->conditionalExpression) . ')'; + break; + + case ($joinDeclaration instanceof \Doctrine\ORM\Query\AST\JoinAssociationDeclaration): + $sql .= $this->walkJoinAssociationDeclaration($joinDeclaration, $joinType); + + // Handle WITH clause + if (($condExpr = $join->conditionalExpression) !== null) { + // Phase 2 AST optimization: Skip processment of ConditionalExpression + // if only one ConditionalTerm is defined + $sql .= ' AND (' . $this->walkConditionalExpression($condExpr) . ')'; + } + break; + } + + return $sql; + } + + /** + * Walks down a CaseExpression AST node and generates the corresponding SQL. + * + * @param CoalesceExpression|NullIfExpression|GeneralCaseExpression|SimpleCaseExpression $expression + * @return string The SQL. + */ + public function walkCaseExpression($expression) + { + switch (true) { + case ($expression instanceof AST\CoalesceExpression): + return $this->walkCoalesceExpression($expression); + + case ($expression instanceof AST\NullIfExpression): + return $this->walkNullIfExpression($expression); + + case ($expression instanceof AST\GeneralCaseExpression): + return $this->walkGeneralCaseExpression($expression); + + case ($expression instanceof AST\SimpleCaseExpression): + return $this->walkSimpleCaseExpression($expression); + + default: + return ''; + } + } + + /** + * Walks down a CoalesceExpression AST node and generates the corresponding SQL. + * + * @param CoalesceExpression $coalesceExpression + * @return string The SQL. + */ + public function walkCoalesceExpression($coalesceExpression) + { + $sql = 'COALESCE('; + + $scalarExpressions = array(); + + foreach ($coalesceExpression->scalarExpressions as $scalarExpression) { + $scalarExpressions[] = $this->walkSimpleArithmeticExpression($scalarExpression); + } + + $sql .= implode(', ', $scalarExpressions) . ')'; + + return $sql; + } + + /** + * Walks down a NullIfExpression AST node and generates the corresponding SQL. + * + * @param NullIfExpression $nullIfExpression + * @return string The SQL. + */ + public function walkNullIfExpression($nullIfExpression) + { + $firstExpression = is_string($nullIfExpression->firstExpression) + ? $this->conn->quote($nullIfExpression->firstExpression) + : $this->walkSimpleArithmeticExpression($nullIfExpression->firstExpression); + + $secondExpression = is_string($nullIfExpression->secondExpression) + ? $this->conn->quote($nullIfExpression->secondExpression) + : $this->walkSimpleArithmeticExpression($nullIfExpression->secondExpression); + + return 'NULLIF(' . $firstExpression . ', ' . $secondExpression . ')'; + } + + /** + * Walks down a GeneralCaseExpression AST node and generates the corresponding SQL. + * + * @param GeneralCaseExpression $generalCaseExpression + * @return string The SQL. + */ + public function walkGeneralCaseExpression(AST\GeneralCaseExpression $generalCaseExpression) + { + $sql = 'CASE'; + + foreach ($generalCaseExpression->whenClauses as $whenClause) { + $sql .= ' WHEN ' . $this->walkConditionalExpression($whenClause->caseConditionExpression); + $sql .= ' THEN ' . $this->walkSimpleArithmeticExpression($whenClause->thenScalarExpression); + } + + $sql .= ' ELSE ' . $this->walkSimpleArithmeticExpression($generalCaseExpression->elseScalarExpression) . ' END'; + + return $sql; + } + + /** + * Walks down a SimpleCaseExpression AST node and generates the corresponding SQL. + * + * @param SimpleCaseExpression $simpleCaseExpression + * @return string The SQL. + */ + public function walkSimpleCaseExpression($simpleCaseExpression) + { + $sql = 'CASE ' . $this->walkStateFieldPathExpression($simpleCaseExpression->caseOperand); + + foreach ($simpleCaseExpression->simpleWhenClauses as $simpleWhenClause) { + $sql .= ' WHEN ' . $this->walkSimpleArithmeticExpression($simpleWhenClause->caseScalarExpression); + $sql .= ' THEN ' . $this->walkSimpleArithmeticExpression($simpleWhenClause->thenScalarExpression); + } + + $sql .= ' ELSE ' . $this->walkSimpleArithmeticExpression($simpleCaseExpression->elseScalarExpression) . ' END'; + + return $sql; + } + + /** + * Walks down a SelectExpression AST node and generates the corresponding SQL. + * + * @param SelectExpression $selectExpression + * @return string The SQL. + */ + public function walkSelectExpression($selectExpression) + { + $sql = ''; + $expr = $selectExpression->expression; + $hidden = $selectExpression->hiddenAliasResultVariable; + + switch (true) { + case ($expr instanceof AST\PathExpression): + if ($expr->type !== AST\PathExpression::TYPE_STATE_FIELD) { + throw QueryException::invalidPathExpression($expr->type); + } + + $fieldName = $expr->field; + $dqlAlias = $expr->identificationVariable; + $qComp = $this->queryComponents[$dqlAlias]; + $class = $qComp['metadata']; + + $resultAlias = $selectExpression->fieldIdentificationVariable ?: $fieldName; + $tableName = ($class->isInheritanceTypeJoined()) + ? $this->em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName) + : $class->getTableName(); + + $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); + $columnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); + $columnAlias = $this->getSQLColumnAlias($class->fieldMappings[$fieldName]['columnName']); + + $col = $sqlTableAlias . '.' . $columnName; + + $fieldType = $class->getTypeOfField($fieldName); + + if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { + $type = Type::getType($fieldType); + $col = $type->convertToPHPValueSQL($col, $this->conn->getDatabasePlatform()); + } + + $sql .= $col . ' AS ' . $columnAlias; + + $this->scalarResultAliasMap[$resultAlias] = $columnAlias; + + if ( ! $hidden) { + $this->rsm->addScalarResult($columnAlias, $resultAlias, $fieldType); + $this->scalarFields[$dqlAlias][$fieldName] = $columnAlias; + } + break; + + case ($expr instanceof AST\AggregateExpression): + case ($expr instanceof AST\Functions\FunctionNode): + case ($expr instanceof AST\SimpleArithmeticExpression): + case ($expr instanceof AST\ArithmeticTerm): + case ($expr instanceof AST\ArithmeticFactor): + case ($expr instanceof AST\ArithmeticPrimary): + case ($expr instanceof AST\Literal): + case ($expr instanceof AST\NullIfExpression): + case ($expr instanceof AST\CoalesceExpression): + case ($expr instanceof AST\GeneralCaseExpression): + case ($expr instanceof AST\SimpleCaseExpression): + $columnAlias = $this->getSQLColumnAlias('sclr'); + $resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; + + $sql .= $expr->dispatch($this) . ' AS ' . $columnAlias; + + $this->scalarResultAliasMap[$resultAlias] = $columnAlias; + + if ( ! $hidden) { + // We cannot resolve field type here; assume 'string'. + $this->rsm->addScalarResult($columnAlias, $resultAlias, 'string'); + } + break; + + case ($expr instanceof AST\Subselect): + $columnAlias = $this->getSQLColumnAlias('sclr'); + $resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; + + $sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias; + + $this->scalarResultAliasMap[$resultAlias] = $columnAlias; + + if ( ! $hidden) { + // We cannot resolve field type here; assume 'string'. + $this->rsm->addScalarResult($columnAlias, $resultAlias, 'string'); + } + break; + + default: + // IdentificationVariable or PartialObjectExpression + if ($expr instanceof AST\PartialObjectExpression) { + $dqlAlias = $expr->identificationVariable; + $partialFieldSet = $expr->partialFieldSet; + } else { + $dqlAlias = $expr; + $partialFieldSet = array(); + } + + $queryComp = $this->queryComponents[$dqlAlias]; + $class = $queryComp['metadata']; + $resultAlias = $selectExpression->fieldIdentificationVariable ?: null; + + if ( ! isset($this->selectedClasses[$dqlAlias])) { + $this->selectedClasses[$dqlAlias] = array( + 'class' => $class, + 'dqlAlias' => $dqlAlias, + 'resultAlias' => $resultAlias + ); + } + + $sqlParts = array(); + + // Select all fields from the queried class + foreach ($class->fieldMappings as $fieldName => $mapping) { + if ($partialFieldSet && ! in_array($fieldName, $partialFieldSet)) { + continue; + } + + $tableName = (isset($mapping['inherited'])) + ? $this->em->getClassMetadata($mapping['inherited'])->getTableName() + : $class->getTableName(); + + $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); + $columnAlias = $this->getSQLColumnAlias($mapping['columnName']); + $quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform); + + $col = $sqlTableAlias . '.' . $quotedColumnName; + + if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { + $type = Type::getType($class->getTypeOfField($fieldName)); + $col = $type->convertToPHPValueSQL($col, $this->platform); + } + + $sqlParts[] = $col . ' AS '. $columnAlias; + + $this->scalarResultAliasMap[$resultAlias][] = $columnAlias; + + $this->rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name); + } + + // Add any additional fields of subclasses (excluding inherited fields) + // 1) on Single Table Inheritance: always, since its marginal overhead + // 2) on Class Table Inheritance only if partial objects are disallowed, + // since it requires outer joining subtables. + if ($class->isInheritanceTypeSingleTable() || ! $this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) { + foreach ($class->subClasses as $subClassName) { + $subClass = $this->em->getClassMetadata($subClassName); + $sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); + + foreach ($subClass->fieldMappings as $fieldName => $mapping) { + if (isset($mapping['inherited']) || $partialFieldSet && !in_array($fieldName, $partialFieldSet)) { + continue; + } + + $columnAlias = $this->getSQLColumnAlias($mapping['columnName']); + $quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $subClass, $this->platform); + + $col = $sqlTableAlias . '.' . $quotedColumnName; + + if (isset($subClass->fieldMappings[$fieldName]['requireSQLConversion'])) { + $type = Type::getType($subClass->getTypeOfField($fieldName)); + $col = $type->convertToPHPValueSQL($col, $this->platform); + } + + $sqlParts[] = $col . ' AS ' . $columnAlias; + + $this->scalarResultAliasMap[$resultAlias][] = $columnAlias; + + $this->rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName); + } + } + } + + $sql .= implode(', ', $sqlParts); + } + + return $sql; + } + + /** + * Walks down a QuantifiedExpression AST node, thereby generating the appropriate SQL. + * + * @param QuantifiedExpression + * @return string The SQL. + */ + public function walkQuantifiedExpression($qExpr) + { + return ' ' . strtoupper($qExpr->type) . '(' . $this->walkSubselect($qExpr->subselect) . ')'; + } + + /** + * Walks down a Subselect AST node, thereby generating the appropriate SQL. + * + * @param Subselect + * @return string The SQL. + */ + public function walkSubselect($subselect) + { + $useAliasesBefore = $this->useSqlTableAliases; + $rootAliasesBefore = $this->rootAliases; + + $this->rootAliases = array(); // reset the rootAliases for the subselect + $this->useSqlTableAliases = true; + + $sql = $this->walkSimpleSelectClause($subselect->simpleSelectClause); + $sql .= $this->walkSubselectFromClause($subselect->subselectFromClause); + $sql .= $this->walkWhereClause($subselect->whereClause); + + $sql .= $subselect->groupByClause ? $this->walkGroupByClause($subselect->groupByClause) : ''; + $sql .= $subselect->havingClause ? $this->walkHavingClause($subselect->havingClause) : ''; + $sql .= $subselect->orderByClause ? $this->walkOrderByClause($subselect->orderByClause) : ''; + + $this->rootAliases = $rootAliasesBefore; // put the main aliases back + $this->useSqlTableAliases = $useAliasesBefore; + + return $sql; + } + + /** + * Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL. + * + * @param SubselectFromClause + * @return string The SQL. + */ + public function walkSubselectFromClause($subselectFromClause) + { + $identificationVarDecls = $subselectFromClause->identificationVariableDeclarations; + $sqlParts = array (); + + foreach ($identificationVarDecls as $subselectIdVarDecl) { + $sql = $this->walkRangeVariableDeclaration($subselectIdVarDecl->rangeVariableDeclaration); + + foreach ($subselectIdVarDecl->joins as $join) { + $sql .= $this->walkJoin($join); + } + + $sqlParts[] = $this->platform->appendLockHint($sql, $this->query->getHint(Query::HINT_LOCK_MODE)); + } + + return ' FROM ' . implode(', ', $sqlParts); + } + + /** + * Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL. + * + * @param SimpleSelectClause + * @return string The SQL. + */ + public function walkSimpleSelectClause($simpleSelectClause) + { + return 'SELECT' . ($simpleSelectClause->isDistinct ? ' DISTINCT' : '') + . $this->walkSimpleSelectExpression($simpleSelectClause->simpleSelectExpression); + } + + /** + * Walks down a SimpleSelectExpression AST node, thereby generating the appropriate SQL. + * + * @param SimpleSelectExpression + * @return string The SQL. + */ + public function walkSimpleSelectExpression($simpleSelectExpression) + { + $expr = $simpleSelectExpression->expression; + $sql = ' '; + + switch (true) { + case ($expr instanceof AST\PathExpression): + $sql .= $this->walkPathExpression($expr); + break; + + case ($expr instanceof AST\AggregateExpression): + $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; + + $sql .= $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias; + break; + + case ($expr instanceof AST\Subselect): + $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; + + $columnAlias = 'sclr' . $this->aliasCounter++; + $this->scalarResultAliasMap[$alias] = $columnAlias; + + $sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias; + break; + + case ($expr instanceof AST\Functions\FunctionNode): + case ($expr instanceof AST\SimpleArithmeticExpression): + case ($expr instanceof AST\ArithmeticTerm): + case ($expr instanceof AST\ArithmeticFactor): + case ($expr instanceof AST\ArithmeticPrimary): + case ($expr instanceof AST\Literal): + case ($expr instanceof AST\NullIfExpression): + case ($expr instanceof AST\CoalesceExpression): + case ($expr instanceof AST\GeneralCaseExpression): + case ($expr instanceof AST\SimpleCaseExpression): + $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->scalarResultCounter++; + + $columnAlias = $this->getSQLColumnAlias('sclr'); + $this->scalarResultAliasMap[$alias] = $columnAlias; + + $sql .= $expr->dispatch($this) . ' AS ' . $columnAlias; + break; + + default: // IdentificationVariable + $sql .= $this->walkEntityIdentificationVariable($expr); + break; + } + + return $sql; + } + + /** + * Walks down an AggregateExpression AST node, thereby generating the appropriate SQL. + * + * @param AggregateExpression + * @return string The SQL. + */ + public function walkAggregateExpression($aggExpression) + { + return $aggExpression->functionName . '(' . ($aggExpression->isDistinct ? 'DISTINCT ' : '') + . $this->walkSimpleArithmeticExpression($aggExpression->pathExpression) . ')'; + } + + /** + * Walks down a GroupByClause AST node, thereby generating the appropriate SQL. + * + * @param GroupByClause + * @return string The SQL. + */ + public function walkGroupByClause($groupByClause) + { + $sqlParts = array(); + + foreach ($groupByClause->groupByItems as $groupByItem) { + $sqlParts[] = $this->walkGroupByItem($groupByItem); + } + + return ' GROUP BY ' . implode(', ', $sqlParts); + } + + /** + * Walks down a GroupByItem AST node, thereby generating the appropriate SQL. + * + * @param GroupByItem + * @return string The SQL. + */ + public function walkGroupByItem($groupByItem) + { + // StateFieldPathExpression + if ( ! is_string($groupByItem)) { + return $this->walkPathExpression($groupByItem); + } + + // ResultVariable + if (isset($this->queryComponents[$groupByItem]['resultVariable'])) { + return $this->walkResultVariable($groupByItem); + } + + // IdentificationVariable + $sqlParts = array(); + + foreach ($this->queryComponents[$groupByItem]['metadata']->fieldNames as $field) { + $item = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $field); + $item->type = AST\PathExpression::TYPE_STATE_FIELD; + + $sqlParts[] = $this->walkPathExpression($item); + } + + foreach ($this->queryComponents[$groupByItem]['metadata']->associationMappings as $mapping) { + if ($mapping['isOwningSide'] && $mapping['type'] & ClassMetadataInfo::TO_ONE) { + $item = new AST\PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $groupByItem, $mapping['fieldName']); + $item->type = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; + + $sqlParts[] = $this->walkPathExpression($item); + } + } + + return implode(', ', $sqlParts); + } + + /** + * Walks down a DeleteClause AST node, thereby generating the appropriate SQL. + * + * @param DeleteClause + * @return string The SQL. + */ + public function walkDeleteClause(AST\DeleteClause $deleteClause) + { + $class = $this->em->getClassMetadata($deleteClause->abstractSchemaName); + $tableName = $class->getTableName(); + $sql = 'DELETE FROM ' . $this->quoteStrategy->getTableName($class, $this->platform); + + $this->setSQLTableAlias($tableName, $tableName, $deleteClause->aliasIdentificationVariable); + $this->rootAliases[] = $deleteClause->aliasIdentificationVariable; + + return $sql; + } + + /** + * Walks down an UpdateClause AST node, thereby generating the appropriate SQL. + * + * @param UpdateClause + * @return string The SQL. + */ + public function walkUpdateClause($updateClause) + { + $class = $this->em->getClassMetadata($updateClause->abstractSchemaName); + $tableName = $class->getTableName(); + $sql = 'UPDATE ' . $this->quoteStrategy->getTableName($class, $this->platform); + + $this->setSQLTableAlias($tableName, $tableName, $updateClause->aliasIdentificationVariable); + $this->rootAliases[] = $updateClause->aliasIdentificationVariable; + + $sql .= ' SET ' . implode(', ', array_map(array($this, 'walkUpdateItem'), $updateClause->updateItems)); + + return $sql; + } + + /** + * Walks down an UpdateItem AST node, thereby generating the appropriate SQL. + * + * @param UpdateItem + * @return string The SQL. + */ + public function walkUpdateItem($updateItem) + { + $useTableAliasesBefore = $this->useSqlTableAliases; + $this->useSqlTableAliases = false; + + $sql = $this->walkPathExpression($updateItem->pathExpression) . ' = '; + $newValue = $updateItem->newValue; + + switch (true) { + case ($newValue instanceof AST\Node): + $sql .= $newValue->dispatch($this); + break; + + case ($newValue === null): + $sql .= 'NULL'; + break; + + default: + $sql .= $this->conn->quote($newValue); + break; + } + + $this->useSqlTableAliases = $useTableAliasesBefore; + + return $sql; + } + + /** + * Walks down a WhereClause AST node, thereby generating the appropriate SQL. + * WhereClause or not, the appropriate discriminator sql is added. + * + * @param WhereClause + * @return string The SQL. + */ + public function walkWhereClause($whereClause) + { + $condSql = null !== $whereClause ? $this->walkConditionalExpression($whereClause->conditionalExpression) : ''; + $discrSql = $this->_generateDiscriminatorColumnConditionSql($this->rootAliases); + + if ($this->em->hasFilters()) { + $filterClauses = array(); + foreach ($this->rootAliases as $dqlAlias) { + $class = $this->queryComponents[$dqlAlias]['metadata']; + $tableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias); + + if ($filterExpr = $this->generateFilterConditionSQL($class, $tableAlias)) { + $filterClauses[] = $filterExpr; + } + } + + if (count($filterClauses)) { + if ($condSql) { + $condSql .= ' AND '; + } + + $condSql .= implode(' AND ', $filterClauses); + } + } + + if ($condSql) { + return ' WHERE ' . (( ! $discrSql) ? $condSql : '(' . $condSql . ') AND ' . $discrSql); + } + + if ($discrSql) { + return ' WHERE ' . $discrSql; + } + + return ''; + } + + /** + * Walk down a ConditionalExpression AST node, thereby generating the appropriate SQL. + * + * @param ConditionalExpression + * @return string The SQL. + */ + public function walkConditionalExpression($condExpr) + { + // Phase 2 AST optimization: Skip processment of ConditionalExpression + // if only one ConditionalTerm is defined + if ( ! ($condExpr instanceof AST\ConditionalExpression)) { + return $this->walkConditionalTerm($condExpr); + } + + return implode(' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->conditionalTerms)); + } + + /** + * Walks down a ConditionalTerm AST node, thereby generating the appropriate SQL. + * + * @param ConditionalTerm + * @return string The SQL. + */ + public function walkConditionalTerm($condTerm) + { + // Phase 2 AST optimization: Skip processment of ConditionalTerm + // if only one ConditionalFactor is defined + if ( ! ($condTerm instanceof AST\ConditionalTerm)) { + return $this->walkConditionalFactor($condTerm); + } + + return implode(' AND ', array_map(array($this, 'walkConditionalFactor'), $condTerm->conditionalFactors)); + } + + /** + * Walks down a ConditionalFactor AST node, thereby generating the appropriate SQL. + * + * @param ConditionalFactor + * @return string The SQL. + */ + public function walkConditionalFactor($factor) + { + // Phase 2 AST optimization: Skip processment of ConditionalFactor + // if only one ConditionalPrimary is defined + return ( ! ($factor instanceof AST\ConditionalFactor)) + ? $this->walkConditionalPrimary($factor) + : ($factor->not ? 'NOT ' : '') . $this->walkConditionalPrimary($factor->conditionalPrimary); + } + + /** + * Walks down a ConditionalPrimary AST node, thereby generating the appropriate SQL. + * + * @param ConditionalPrimary + * @return string The SQL. + */ + public function walkConditionalPrimary($primary) + { + if ($primary->isSimpleConditionalExpression()) { + return $primary->simpleConditionalExpression->dispatch($this); + } + + if ($primary->isConditionalExpression()) { + $condExpr = $primary->conditionalExpression; + + return '(' . $this->walkConditionalExpression($condExpr) . ')'; + } + } + + /** + * Walks down an ExistsExpression AST node, thereby generating the appropriate SQL. + * + * @param ExistsExpression + * @return string The SQL. + */ + public function walkExistsExpression($existsExpr) + { + $sql = ($existsExpr->not) ? 'NOT ' : ''; + + $sql .= 'EXISTS (' . $this->walkSubselect($existsExpr->subselect) . ')'; + + return $sql; + } + + /** + * Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL. + * + * @param CollectionMemberExpression + * @return string The SQL. + */ + public function walkCollectionMemberExpression($collMemberExpr) + { + $sql = $collMemberExpr->not ? 'NOT ' : ''; + $sql .= 'EXISTS (SELECT 1 FROM '; + + $entityExpr = $collMemberExpr->entityExpression; + $collPathExpr = $collMemberExpr->collectionValuedPathExpression; + + $fieldName = $collPathExpr->field; + $dqlAlias = $collPathExpr->identificationVariable; + + $class = $this->queryComponents[$dqlAlias]['metadata']; + + switch (true) { + // InputParameter + case ($entityExpr instanceof AST\InputParameter): + $dqlParamKey = $entityExpr->name; + $entitySql = '?'; + break; + + // SingleValuedAssociationPathExpression | IdentificationVariable + case ($entityExpr instanceof AST\PathExpression): + $entitySql = $this->walkPathExpression($entityExpr); + break; + + default: + throw new \BadMethodCallException("Not implemented"); + } + + $assoc = $class->associationMappings[$fieldName]; + + if ($assoc['type'] == ClassMetadata::ONE_TO_MANY) { + $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); + $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName()); + $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); + + $sql .= $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' ' . $targetTableAlias . ' WHERE '; + + $owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']]; + $sqlParts = array(); + + foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) { + $targetColumn = $this->quoteStrategy->getColumnName($class->fieldNames[$targetColumn], $class, $this->platform); + + $sqlParts[] = $sourceTableAlias . '.' . $targetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn; + } + + foreach ($this->quoteStrategy->getIdentifierColumnNames($targetClass, $this->platform) as $targetColumnName) { + if (isset($dqlParamKey)) { + $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); + } + + $sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql; + } + + $sql .= implode(' AND ', $sqlParts); + } else { // many-to-many + $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); + + $owningAssoc = $assoc['isOwningSide'] ? $assoc : $targetClass->associationMappings[$assoc['mappedBy']]; + $joinTable = $owningAssoc['joinTable']; + + // SQL table aliases + $joinTableAlias = $this->getSQLTableAlias($joinTable['name']); + $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName()); + $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); + + // join to target table + $sql .= $this->quoteStrategy->getJoinTableName($owningAssoc, $targetClass, $this->platform) . ' ' . $joinTableAlias + . ' INNER JOIN ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' ' . $targetTableAlias . ' ON '; + + // join conditions + $joinColumns = $assoc['isOwningSide'] ? $joinTable['inverseJoinColumns'] : $joinTable['joinColumns']; + $joinSqlParts = array(); + + foreach ($joinColumns as $joinColumn) { + $targetColumn = $this->quoteStrategy->getColumnName($targetClass->fieldNames[$joinColumn['referencedColumnName']], $targetClass, $this->platform); + + $joinSqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $targetTableAlias . '.' . $targetColumn; + } + + $sql .= implode(' AND ', $joinSqlParts); + $sql .= ' WHERE '; + + $joinColumns = $assoc['isOwningSide'] ? $joinTable['joinColumns'] : $joinTable['inverseJoinColumns']; + $sqlParts = array(); + + foreach ($joinColumns as $joinColumn) { + $targetColumn = $this->quoteStrategy->getColumnName($class->fieldNames[$joinColumn['referencedColumnName']], $class, $this->platform); + + $sqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $sourceTableAlias . '.' . $targetColumn; + } + + foreach ($this->quoteStrategy->getIdentifierColumnNames($targetClass, $this->platform) as $targetColumnName) { + if (isset($dqlParamKey)) { + $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); + } + + $sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql; + } + + $sql .= implode(' AND ', $sqlParts); + } + + return $sql . ')'; + } + + /** + * Walks down an EmptyCollectionComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param EmptyCollectionComparisonExpression + * @return string The SQL. + */ + public function walkEmptyCollectionComparisonExpression($emptyCollCompExpr) + { + $sizeFunc = new AST\Functions\SizeFunction('size'); + $sizeFunc->collectionPathExpression = $emptyCollCompExpr->expression; + + return $sizeFunc->getSql($this) . ($emptyCollCompExpr->not ? ' > 0' : ' = 0'); + } + + /** + * Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param NullComparisonExpression + * @return string The SQL. + */ + public function walkNullComparisonExpression($nullCompExpr) + { + $sql = ''; + $innerExpr = $nullCompExpr->expression; + + if ($innerExpr instanceof AST\InputParameter) { + $dqlParamKey = $innerExpr->name; + $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); + $sql .= ' ?'; + } else { + $sql .= $this->walkPathExpression($innerExpr); + } + + $sql .= ' IS' . ($nullCompExpr->not ? ' NOT' : '') . ' NULL'; + + return $sql; + } + + /** + * Walks down an InExpression AST node, thereby generating the appropriate SQL. + * + * @param InExpression + * @return string The SQL. + */ + public function walkInExpression($inExpr) + { + $sql = $this->walkArithmeticExpression($inExpr->expression) . ($inExpr->not ? ' NOT' : '') . ' IN ('; + + $sql .= ($inExpr->subselect) + ? $this->walkSubselect($inExpr->subselect) + : implode(', ', array_map(array($this, 'walkInParameter'), $inExpr->literals)); + + $sql .= ')'; + + return $sql; + } + + /** + * Walks down an InstanceOfExpression AST node, thereby generating the appropriate SQL. + * + * @param InstanceOfExpression + * @return string The SQL. + */ + public function walkInstanceOfExpression($instanceOfExpr) + { + $sql = ''; + + $dqlAlias = $instanceOfExpr->identificationVariable; + $discrClass = $class = $this->queryComponents[$dqlAlias]['metadata']; + + if ($class->discriminatorColumn) { + $discrClass = $this->em->getClassMetadata($class->rootEntityName); + } + + if ($this->useSqlTableAliases) { + $sql .= $this->getSQLTableAlias($discrClass->getTableName(), $dqlAlias) . '.'; + } + + $sql .= $class->discriminatorColumn['name'] . ($instanceOfExpr->not ? ' NOT IN ' : ' IN '); + + $sqlParameterList = array(); + + foreach ($instanceOfExpr->value as $parameter) { + if ($parameter instanceof AST\InputParameter) { + // We need to modify the parameter value to be its correspondent mapped value + $dqlParamKey = $parameter->name; + $dqlParam = $this->query->getParameter($dqlParamKey); + $paramValue = $this->query->processParameterValue($dqlParam->getValue()); + + if ( ! ($paramValue instanceof \Doctrine\ORM\Mapping\ClassMetadata)) { + throw QueryException::invalidParameterType('ClassMetadata', get_class($paramValue)); + } + + $entityClassName = $paramValue->name; + } else { + // Get name from ClassMetadata to resolve aliases. + $entityClassName = $this->em->getClassMetadata($parameter)->name; + } + + if ($entityClassName == $class->name) { + $sqlParameterList[] = $this->conn->quote($class->discriminatorValue); + } else { + $discrMap = array_flip($class->discriminatorMap); + + if (!isset($discrMap[$entityClassName])) { + throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName); + } + + $sqlParameterList[] = $this->conn->quote($discrMap[$entityClassName]); + } + } + + $sql .= '(' . implode(', ', $sqlParameterList) . ')'; + + return $sql; + } + + /** + * Walks down an InParameter AST node, thereby generating the appropriate SQL. + * + * @param InParameter + * @return string The SQL. + */ + public function walkInParameter($inParam) + { + return $inParam instanceof AST\InputParameter + ? $this->walkInputParameter($inParam) + : $this->walkLiteral($inParam); + } + + /** + * Walks down a literal that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkLiteral($literal) + { + switch ($literal->type) { + case AST\Literal::STRING: + return $this->conn->quote($literal->value); + + case AST\Literal::BOOLEAN: + $bool = strtolower($literal->value) == 'true' ? true : false; + $boolVal = $this->conn->getDatabasePlatform()->convertBooleans($bool); + + return $boolVal; + + case AST\Literal::NUMERIC: + return $literal->value; + + default: + throw QueryException::invalidLiteral($literal); + } + } + + /** + * Walks down a BetweenExpression AST node, thereby generating the appropriate SQL. + * + * @param BetweenExpression + * @return string The SQL. + */ + public function walkBetweenExpression($betweenExpr) + { + $sql = $this->walkArithmeticExpression($betweenExpr->expression); + + if ($betweenExpr->not) $sql .= ' NOT'; + + $sql .= ' BETWEEN ' . $this->walkArithmeticExpression($betweenExpr->leftBetweenExpression) + . ' AND ' . $this->walkArithmeticExpression($betweenExpr->rightBetweenExpression); + + return $sql; + } + + /** + * Walks down a LikeExpression AST node, thereby generating the appropriate SQL. + * + * @param LikeExpression + * @return string The SQL. + */ + public function walkLikeExpression($likeExpr) + { + $stringExpr = $likeExpr->stringExpression; + $sql = $stringExpr->dispatch($this) . ($likeExpr->not ? ' NOT' : '') . ' LIKE '; + + if ($likeExpr->stringPattern instanceof AST\InputParameter) { + $inputParam = $likeExpr->stringPattern; + $dqlParamKey = $inputParam->name; + $this->parserResult->addParameterMapping($dqlParamKey, $this->sqlParamIndex++); + $sql .= '?'; + } elseif ($likeExpr->stringPattern instanceof AST\Functions\FunctionNode ) { + $sql .= $this->walkFunction($likeExpr->stringPattern); + } elseif ($likeExpr->stringPattern instanceof AST\PathExpression) { + $sql .= $this->walkPathExpression($likeExpr->stringPattern); + } else { + $sql .= $this->walkLiteral($likeExpr->stringPattern); + } + + if ($likeExpr->escapeChar) { + $sql .= ' ESCAPE ' . $this->walkLiteral($likeExpr->escapeChar); + } + + return $sql; + } + + /** + * Walks down a StateFieldPathExpression AST node, thereby generating the appropriate SQL. + * + * @param StateFieldPathExpression + * @return string The SQL. + */ + public function walkStateFieldPathExpression($stateFieldPathExpression) + { + return $this->walkPathExpression($stateFieldPathExpression); + } + + /** + * Walks down a ComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param ComparisonExpression + * @return string The SQL. + */ + public function walkComparisonExpression($compExpr) + { + $leftExpr = $compExpr->leftExpression; + $rightExpr = $compExpr->rightExpression; + $sql = ''; + + $sql .= ($leftExpr instanceof AST\Node) + ? $leftExpr->dispatch($this) + : (is_numeric($leftExpr) ? $leftExpr : $this->conn->quote($leftExpr)); + + $sql .= ' ' . $compExpr->operator . ' '; + + $sql .= ($rightExpr instanceof AST\Node) + ? $rightExpr->dispatch($this) + : (is_numeric($rightExpr) ? $rightExpr : $this->conn->quote($rightExpr)); + + return $sql; + } + + /** + * Walks down an InputParameter AST node, thereby generating the appropriate SQL. + * + * @param InputParameter + * @return string The SQL. + */ + public function walkInputParameter($inputParam) + { + $this->parserResult->addParameterMapping($inputParam->name, $this->sqlParamIndex++); + + return '?'; + } + + /** + * Walks down an ArithmeticExpression AST node, thereby generating the appropriate SQL. + * + * @param ArithmeticExpression + * @return string The SQL. + */ + public function walkArithmeticExpression($arithmeticExpr) + { + return ($arithmeticExpr->isSimpleArithmeticExpression()) + ? $this->walkSimpleArithmeticExpression($arithmeticExpr->simpleArithmeticExpression) + : '(' . $this->walkSubselect($arithmeticExpr->subselect) . ')'; + } + + /** + * Walks down an SimpleArithmeticExpression AST node, thereby generating the appropriate SQL. + * + * @param SimpleArithmeticExpression + * @return string The SQL. + */ + public function walkSimpleArithmeticExpression($simpleArithmeticExpr) + { + if ( ! ($simpleArithmeticExpr instanceof AST\SimpleArithmeticExpression)) { + return $this->walkArithmeticTerm($simpleArithmeticExpr); + } + + return implode(' ', array_map(array($this, 'walkArithmeticTerm'), $simpleArithmeticExpr->arithmeticTerms)); + } + + /** + * Walks down an ArithmeticTerm AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkArithmeticTerm($term) + { + if (is_string($term)) { + return (isset($this->queryComponents[$term])) + ? $this->walkResultVariable($this->queryComponents[$term]['token']['value']) + : $term; + } + + // Phase 2 AST optimization: Skip processment of ArithmeticTerm + // if only one ArithmeticFactor is defined + if ( ! ($term instanceof AST\ArithmeticTerm)) { + return $this->walkArithmeticFactor($term); + } + + return implode(' ', array_map(array($this, 'walkArithmeticFactor'), $term->arithmeticFactors)); + } + + /** + * Walks down an ArithmeticFactor that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkArithmeticFactor($factor) + { + if (is_string($factor)) { + return $factor; + } + + // Phase 2 AST optimization: Skip processment of ArithmeticFactor + // if only one ArithmeticPrimary is defined + if ( ! ($factor instanceof AST\ArithmeticFactor)) { + return $this->walkArithmeticPrimary($factor); + } + + $sign = $factor->isNegativeSigned() ? '-' : ($factor->isPositiveSigned() ? '+' : ''); + + return $sign . $this->walkArithmeticPrimary($factor->arithmeticPrimary); + } + + /** + * Walks down an ArithmeticPrimary that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkArithmeticPrimary($primary) + { + if ($primary instanceof AST\SimpleArithmeticExpression) { + return '(' . $this->walkSimpleArithmeticExpression($primary) . ')'; + } + + if ($primary instanceof AST\Node) { + return $primary->dispatch($this); + } + + return $this->walkEntityIdentificationVariable($primary); + } + + /** + * Walks down a StringPrimary that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkStringPrimary($stringPrimary) + { + return (is_string($stringPrimary)) + ? $this->conn->quote($stringPrimary) + : $stringPrimary->dispatch($this); + } + + /** + * Walks down a ResultVriable that represents an AST node, thereby generating the appropriate SQL. + * + * @param string $resultVariable + * @return string The SQL. + */ + public function walkResultVariable($resultVariable) + { + $resultAlias = $this->scalarResultAliasMap[$resultVariable]; + + if (is_array($resultAlias)) { + return implode(', ', $resultAlias); + } + + return $resultAlias; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalker.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalker.php new file mode 100644 index 0000000..c88ca13 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalker.php @@ -0,0 +1,409 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * Interface for walkers of DQL ASTs (abstract syntax trees). + * + * @author Roman Borschel + * @since 2.0 + */ +interface TreeWalker +{ + /** + * Initializes TreeWalker with important information about the ASTs to be walked + * + * @param Query $query The parsed Query. + * @param ParserResult $parserResult The result of the parsing process. + * @param array $queryComponents Query components (symbol table) + */ + public function __construct($query, $parserResult, array $queryComponents); + + /** + * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + function walkSelectStatement(AST\SelectStatement $AST); + + /** + * Walks down a SelectClause AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + function walkSelectClause($selectClause); + + /** + * Walks down a FromClause AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + function walkFromClause($fromClause); + + /** + * Walks down a FunctionNode AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + function walkFunction($function); + + /** + * Walks down an OrderByClause AST node, thereby generating the appropriate SQL. + * + * @param OrderByClause + * @return string The SQL. + */ + function walkOrderByClause($orderByClause); + + /** + * Walks down an OrderByItem AST node, thereby generating the appropriate SQL. + * + * @param OrderByItem + * @return string The SQL. + */ + function walkOrderByItem($orderByItem); + + /** + * Walks down a HavingClause AST node, thereby generating the appropriate SQL. + * + * @param HavingClause + * @return string The SQL. + */ + function walkHavingClause($havingClause); + + /** + * Walks down a Join AST node and creates the corresponding SQL. + * + * @param Join $joinVarDecl + * @return string The SQL. + */ + function walkJoin($join); + + /** + * Walks down a SelectExpression AST node and generates the corresponding SQL. + * + * @param SelectExpression $selectExpression + * @return string The SQL. + */ + function walkSelectExpression($selectExpression); + + /** + * Walks down a QuantifiedExpression AST node, thereby generating the appropriate SQL. + * + * @param QuantifiedExpression + * @return string The SQL. + */ + function walkQuantifiedExpression($qExpr); + + /** + * Walks down a Subselect AST node, thereby generating the appropriate SQL. + * + * @param Subselect + * @return string The SQL. + */ + function walkSubselect($subselect); + + /** + * Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL. + * + * @param SubselectFromClause + * @return string The SQL. + */ + function walkSubselectFromClause($subselectFromClause); + + /** + * Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL. + * + * @param SimpleSelectClause + * @return string The SQL. + */ + function walkSimpleSelectClause($simpleSelectClause); + + /** + * Walks down a SimpleSelectExpression AST node, thereby generating the appropriate SQL. + * + * @param SimpleSelectExpression + * @return string The SQL. + */ + function walkSimpleSelectExpression($simpleSelectExpression); + + /** + * Walks down an AggregateExpression AST node, thereby generating the appropriate SQL. + * + * @param AggregateExpression + * @return string The SQL. + */ + function walkAggregateExpression($aggExpression); + + /** + * Walks down a GroupByClause AST node, thereby generating the appropriate SQL. + * + * @param GroupByClause + * @return string The SQL. + */ + function walkGroupByClause($groupByClause); + + /** + * Walks down a GroupByItem AST node, thereby generating the appropriate SQL. + * + * @param GroupByItem + * @return string The SQL. + */ + function walkGroupByItem($groupByItem); + + /** + * Walks down an UpdateStatement AST node, thereby generating the appropriate SQL. + * + * @param UpdateStatement + * @return string The SQL. + */ + function walkUpdateStatement(AST\UpdateStatement $AST); + + /** + * Walks down a DeleteStatement AST node, thereby generating the appropriate SQL. + * + * @param DeleteStatement + * @return string The SQL. + */ + function walkDeleteStatement(AST\DeleteStatement $AST); + + /** + * Walks down a DeleteClause AST node, thereby generating the appropriate SQL. + * + * @param DeleteClause + * @return string The SQL. + */ + function walkDeleteClause(AST\DeleteClause $deleteClause); + + /** + * Walks down an UpdateClause AST node, thereby generating the appropriate SQL. + * + * @param UpdateClause + * @return string The SQL. + */ + function walkUpdateClause($updateClause); + + /** + * Walks down an UpdateItem AST node, thereby generating the appropriate SQL. + * + * @param UpdateItem + * @return string The SQL. + */ + function walkUpdateItem($updateItem); + + /** + * Walks down a WhereClause AST node, thereby generating the appropriate SQL. + * + * @param WhereClause + * @return string The SQL. + */ + function walkWhereClause($whereClause); + + /** + * Walks down a ConditionalExpression AST node, thereby generating the appropriate SQL. + * + * @param ConditionalExpression + * @return string The SQL. + */ + function walkConditionalExpression($condExpr); + + /** + * Walks down a ConditionalTerm AST node, thereby generating the appropriate SQL. + * + * @param ConditionalTerm + * @return string The SQL. + */ + function walkConditionalTerm($condTerm); + + /** + * Walks down a ConditionalFactor AST node, thereby generating the appropriate SQL. + * + * @param ConditionalFactor + * @return string The SQL. + */ + function walkConditionalFactor($factor); + + /** + * Walks down a ConditionalPrimary AST node, thereby generating the appropriate SQL. + * + * @param ConditionalPrimary + * @return string The SQL. + */ + function walkConditionalPrimary($primary); + + /** + * Walks down an ExistsExpression AST node, thereby generating the appropriate SQL. + * + * @param ExistsExpression + * @return string The SQL. + */ + function walkExistsExpression($existsExpr); + + /** + * Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL. + * + * @param CollectionMemberExpression + * @return string The SQL. + */ + function walkCollectionMemberExpression($collMemberExpr); + + /** + * Walks down an EmptyCollectionComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param EmptyCollectionComparisonExpression + * @return string The SQL. + */ + function walkEmptyCollectionComparisonExpression($emptyCollCompExpr); + + /** + * Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param NullComparisonExpression + * @return string The SQL. + */ + function walkNullComparisonExpression($nullCompExpr); + + /** + * Walks down an InExpression AST node, thereby generating the appropriate SQL. + * + * @param InExpression + * @return string The SQL. + */ + function walkInExpression($inExpr); + + /** + * Walks down an InstanceOfExpression AST node, thereby generating the appropriate SQL. + * + * @param InstanceOfExpression + * @return string The SQL. + */ + function walkInstanceOfExpression($instanceOfExpr); + + /** + * Walks down a literal that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + function walkLiteral($literal); + + /** + * Walks down a BetweenExpression AST node, thereby generating the appropriate SQL. + * + * @param BetweenExpression + * @return string The SQL. + */ + function walkBetweenExpression($betweenExpr); + + /** + * Walks down a LikeExpression AST node, thereby generating the appropriate SQL. + * + * @param LikeExpression + * @return string The SQL. + */ + function walkLikeExpression($likeExpr); + + /** + * Walks down a StateFieldPathExpression AST node, thereby generating the appropriate SQL. + * + * @param StateFieldPathExpression + * @return string The SQL. + */ + function walkStateFieldPathExpression($stateFieldPathExpression); + + /** + * Walks down a ComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param ComparisonExpression + * @return string The SQL. + */ + function walkComparisonExpression($compExpr); + + /** + * Walks down an InputParameter AST node, thereby generating the appropriate SQL. + * + * @param InputParameter + * @return string The SQL. + */ + function walkInputParameter($inputParam); + + /** + * Walks down an ArithmeticExpression AST node, thereby generating the appropriate SQL. + * + * @param ArithmeticExpression + * @return string The SQL. + */ + function walkArithmeticExpression($arithmeticExpr); + + /** + * Walks down an ArithmeticTerm AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + function walkArithmeticTerm($term); + + /** + * Walks down a StringPrimary that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + function walkStringPrimary($stringPrimary); + + /** + * Walks down an ArithmeticFactor that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + function walkArithmeticFactor($factor); + + /** + * Walks down an SimpleArithmeticExpression AST node, thereby generating the appropriate SQL. + * + * @param SimpleArithmeticExpression + * @return string The SQL. + */ + function walkSimpleArithmeticExpression($simpleArithmeticExpr); + + /** + * Walks down an PathExpression AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + function walkPathExpression($pathExpr); + + /** + * Walks down an ResultVariable AST node, thereby generating the appropriate SQL. + * + * @param string $resultVariable + * @return string The SQL. + */ + function walkResultVariable($resultVariable); + + /** + * Gets an executor that can be used to execute the result of this walker. + * + * @return AbstractExecutor + */ + function getExecutor($AST); +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalkerAdapter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalkerAdapter.php new file mode 100644 index 0000000..4446a85 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalkerAdapter.php @@ -0,0 +1,443 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * An adapter implementation of the TreeWalker interface. The methods in this class + * are empty. This class exists as convenience for creating tree walkers. + * + * @author Roman Borschel + * @since 2.0 + */ +abstract class TreeWalkerAdapter implements TreeWalker +{ + private $_query; + private $_parserResult; + private $_queryComponents; + + /** + * {@inheritdoc} + */ + public function __construct($query, $parserResult, array $queryComponents) + { + $this->_query = $query; + $this->_parserResult = $parserResult; + $this->_queryComponents = $queryComponents; + } + + /** + * @return array + */ + protected function _getQueryComponents() + { + return $this->_queryComponents; + } + + /** + * Retrieve Query Instance reponsible for the current walkers execution. + * + * @return \Doctrine\ORM\Query + */ + protected function _getQuery() + { + return $this->_query; + } + + /** + * Retrieve ParserResult + * + * @return \Doctrine\ORM\Query\ParserResult + */ + protected function _getParserResult() + { + return $this->_parserResult; + } + + /** + * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkSelectStatement(AST\SelectStatement $AST) {} + + /** + * Walks down a SelectClause AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkSelectClause($selectClause) {} + + /** + * Walks down a FromClause AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkFromClause($fromClause) {} + + /** + * Walks down a FunctionNode AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkFunction($function) {} + + /** + * Walks down an OrderByClause AST node, thereby generating the appropriate SQL. + * + * @param OrderByClause + * @return string The SQL. + */ + public function walkOrderByClause($orderByClause) {} + + /** + * Walks down an OrderByItem AST node, thereby generating the appropriate SQL. + * + * @param OrderByItem + * @return string The SQL. + */ + public function walkOrderByItem($orderByItem) {} + + /** + * Walks down a HavingClause AST node, thereby generating the appropriate SQL. + * + * @param HavingClause + * @return string The SQL. + */ + public function walkHavingClause($havingClause) {} + + /** + * Walks down a Join AST node and creates the corresponding SQL. + * + * @param Join $join + * @return string The SQL. + */ + public function walkJoin($join) {} + + /** + * Walks down a SelectExpression AST node and generates the corresponding SQL. + * + * @param SelectExpression $selectExpression + * @return string The SQL. + */ + public function walkSelectExpression($selectExpression) {} + + /** + * Walks down a QuantifiedExpression AST node, thereby generating the appropriate SQL. + * + * @param QuantifiedExpression + * @return string The SQL. + */ + public function walkQuantifiedExpression($qExpr) {} + + /** + * Walks down a Subselect AST node, thereby generating the appropriate SQL. + * + * @param Subselect + * @return string The SQL. + */ + public function walkSubselect($subselect) {} + + /** + * Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL. + * + * @param SubselectFromClause + * @return string The SQL. + */ + public function walkSubselectFromClause($subselectFromClause) {} + + /** + * Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL. + * + * @param SimpleSelectClause + * @return string The SQL. + */ + public function walkSimpleSelectClause($simpleSelectClause) {} + + /** + * Walks down a SimpleSelectExpression AST node, thereby generating the appropriate SQL. + * + * @param SimpleSelectExpression + * @return string The SQL. + */ + public function walkSimpleSelectExpression($simpleSelectExpression) {} + + /** + * Walks down an AggregateExpression AST node, thereby generating the appropriate SQL. + * + * @param AggregateExpression + * @return string The SQL. + */ + public function walkAggregateExpression($aggExpression) {} + + /** + * Walks down a GroupByClause AST node, thereby generating the appropriate SQL. + * + * @param GroupByClause + * @return string The SQL. + */ + public function walkGroupByClause($groupByClause) {} + + /** + * Walks down a GroupByItem AST node, thereby generating the appropriate SQL. + * + * @param GroupByItem + * @return string The SQL. + */ + public function walkGroupByItem($groupByItem) {} + + /** + * Walks down an UpdateStatement AST node, thereby generating the appropriate SQL. + * + * @param UpdateStatement + * @return string The SQL. + */ + public function walkUpdateStatement(AST\UpdateStatement $AST) {} + + /** + * Walks down a DeleteStatement AST node, thereby generating the appropriate SQL. + * + * @param DeleteStatement + * @return string The SQL. + */ + public function walkDeleteStatement(AST\DeleteStatement $AST) {} + + /** + * Walks down a DeleteClause AST node, thereby generating the appropriate SQL. + * + * @param DeleteClause + * @return string The SQL. + */ + public function walkDeleteClause(AST\DeleteClause $deleteClause) {} + + /** + * Walks down an UpdateClause AST node, thereby generating the appropriate SQL. + * + * @param UpdateClause + * @return string The SQL. + */ + public function walkUpdateClause($updateClause) {} + + /** + * Walks down an UpdateItem AST node, thereby generating the appropriate SQL. + * + * @param UpdateItem + * @return string The SQL. + */ + public function walkUpdateItem($updateItem) {} + + /** + * Walks down a WhereClause AST node, thereby generating the appropriate SQL. + * + * @param WhereClause + * @return string The SQL. + */ + public function walkWhereClause($whereClause) {} + + /** + * Walks down a ConditionalExpression AST node, thereby generating the appropriate SQL. + * + * @param ConditionalExpression + * @return string The SQL. + */ + public function walkConditionalExpression($condExpr) {} + + /** + * Walks down a ConditionalTerm AST node, thereby generating the appropriate SQL. + * + * @param ConditionalTerm + * @return string The SQL. + */ + public function walkConditionalTerm($condTerm) {} + + /** + * Walks down a ConditionalFactor AST node, thereby generating the appropriate SQL. + * + * @param ConditionalFactor + * @return string The SQL. + */ + public function walkConditionalFactor($factor) {} + + /** + * Walks down a ConditionalPrimary AST node, thereby generating the appropriate SQL. + * + * @param ConditionalPrimary + * @return string The SQL. + */ + public function walkConditionalPrimary($primary) {} + + /** + * Walks down an ExistsExpression AST node, thereby generating the appropriate SQL. + * + * @param ExistsExpression + * @return string The SQL. + */ + public function walkExistsExpression($existsExpr) {} + + /** + * Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL. + * + * @param CollectionMemberExpression + * @return string The SQL. + */ + public function walkCollectionMemberExpression($collMemberExpr) {} + + /** + * Walks down an EmptyCollectionComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param EmptyCollectionComparisonExpression + * @return string The SQL. + */ + public function walkEmptyCollectionComparisonExpression($emptyCollCompExpr) {} + + /** + * Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param NullComparisonExpression + * @return string The SQL. + */ + public function walkNullComparisonExpression($nullCompExpr) {} + + /** + * Walks down an InExpression AST node, thereby generating the appropriate SQL. + * + * @param InExpression + * @return string The SQL. + */ + public function walkInExpression($inExpr) {} + + /** + * Walks down an InstanceOfExpression AST node, thereby generating the appropriate SQL. + * + * @param InstanceOfExpression + * @return string The SQL. + */ + function walkInstanceOfExpression($instanceOfExpr) {} + + /** + * Walks down a literal that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkLiteral($literal) {} + + /** + * Walks down a BetweenExpression AST node, thereby generating the appropriate SQL. + * + * @param BetweenExpression + * @return string The SQL. + */ + public function walkBetweenExpression($betweenExpr) {} + + /** + * Walks down a LikeExpression AST node, thereby generating the appropriate SQL. + * + * @param LikeExpression + * @return string The SQL. + */ + public function walkLikeExpression($likeExpr) {} + + /** + * Walks down a StateFieldPathExpression AST node, thereby generating the appropriate SQL. + * + * @param StateFieldPathExpression + * @return string The SQL. + */ + public function walkStateFieldPathExpression($stateFieldPathExpression) {} + + /** + * Walks down a ComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param ComparisonExpression + * @return string The SQL. + */ + public function walkComparisonExpression($compExpr) {} + + /** + * Walks down an InputParameter AST node, thereby generating the appropriate SQL. + * + * @param InputParameter + * @return string The SQL. + */ + public function walkInputParameter($inputParam) {} + + /** + * Walks down an ArithmeticExpression AST node, thereby generating the appropriate SQL. + * + * @param ArithmeticExpression + * @return string The SQL. + */ + public function walkArithmeticExpression($arithmeticExpr) {} + + /** + * Walks down an ArithmeticTerm AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkArithmeticTerm($term) {} + + /** + * Walks down a StringPrimary that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkStringPrimary($stringPrimary) {} + + /** + * Walks down an ArithmeticFactor that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkArithmeticFactor($factor) {} + + /** + * Walks down an SimpleArithmeticExpression AST node, thereby generating the appropriate SQL. + * + * @param SimpleArithmeticExpression + * @return string The SQL. + */ + public function walkSimpleArithmeticExpression($simpleArithmeticExpr) {} + + /** + * Walks down an PathExpression AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkPathExpression($pathExpr) {} + + /** + * Walks down an ResultVariable AST node, thereby generating the appropriate SQL. + * + * @param string $resultVariable + * @return string The SQL. + */ + public function walkResultVariable($resultVariable) {} + + /** + * Gets an executor that can be used to execute the result of this walker. + * + * @return AbstractExecutor + */ + public function getExecutor($AST) {} +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalkerChain.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalkerChain.php new file mode 100644 index 0000000..13bbcde --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Query/TreeWalkerChain.php @@ -0,0 +1,662 @@ +. + */ + +namespace Doctrine\ORM\Query; + +/** + * Represents a chain of tree walkers that modify an AST and finally emit output. + * Only the last walker in the chain can emit output. Any previous walkers can modify + * the AST to influence the final output produced by the last walker. + * + * @author Roman Borschel + * @since 2.0 + */ +class TreeWalkerChain implements TreeWalker +{ + /** The tree walkers. */ + private $_walkers = array(); + /** The original Query. */ + private $_query; + /** The ParserResult of the original query that was produced by the Parser. */ + private $_parserResult; + /** The query components of the original query (the "symbol table") that was produced by the Parser. */ + private $_queryComponents; + + /** + * @inheritdoc + */ + public function __construct($query, $parserResult, array $queryComponents) + { + $this->_query = $query; + $this->_parserResult = $parserResult; + $this->_queryComponents = $queryComponents; + } + + /** + * Adds a tree walker to the chain. + * + * @param string $walkerClass The class of the walker to instantiate. + */ + public function addTreeWalker($walkerClass) + { + $this->_walkers[] = new $walkerClass($this->_query, $this->_parserResult, $this->_queryComponents); + } + + /** + * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkSelectStatement(AST\SelectStatement $AST) + { + foreach ($this->_walkers as $walker) { + $walker->walkSelectStatement($AST); + } + } + + /** + * Walks down a SelectClause AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkSelectClause($selectClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkSelectClause($selectClause); + } + } + + /** + * Walks down a FromClause AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkFromClause($fromClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkFromClause($fromClause); + } + } + + /** + * Walks down a FunctionNode AST node, thereby generating the appropriate SQL. + * + * @return string The SQL. + */ + public function walkFunction($function) + { + foreach ($this->_walkers as $walker) { + $walker->walkFunction($function); + } + } + + /** + * Walks down an OrderByClause AST node, thereby generating the appropriate SQL. + * + * @param OrderByClause + * @return string The SQL. + */ + public function walkOrderByClause($orderByClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkOrderByClause($orderByClause); + } + } + + /** + * Walks down an OrderByItem AST node, thereby generating the appropriate SQL. + * + * @param OrderByItem + * @return string The SQL. + */ + public function walkOrderByItem($orderByItem) + { + foreach ($this->_walkers as $walker) { + $walker->walkOrderByItem($orderByItem); + } + } + + /** + * Walks down a HavingClause AST node, thereby generating the appropriate SQL. + * + * @param HavingClause + * @return string The SQL. + */ + public function walkHavingClause($havingClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkHavingClause($havingClause); + } + } + + /** + * Walks down a Join AST node and creates the corresponding SQL. + * + * @param Join $join + * @return string The SQL. + */ + public function walkJoin($join) + { + foreach ($this->_walkers as $walker) { + $walker->walkJoin($join); + } + } + + /** + * Walks down a SelectExpression AST node and generates the corresponding SQL. + * + * @param SelectExpression $selectExpression + * @return string The SQL. + */ + public function walkSelectExpression($selectExpression) + { + foreach ($this->_walkers as $walker) { + $walker->walkSelectExpression($selectExpression); + } + } + + /** + * Walks down a QuantifiedExpression AST node, thereby generating the appropriate SQL. + * + * @param QuantifiedExpression + * @return string The SQL. + */ + public function walkQuantifiedExpression($qExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkQuantifiedExpression($qExpr); + } + } + + /** + * Walks down a Subselect AST node, thereby generating the appropriate SQL. + * + * @param Subselect + * @return string The SQL. + */ + public function walkSubselect($subselect) + { + foreach ($this->_walkers as $walker) { + $walker->walkSubselect($subselect); + } + } + + /** + * Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL. + * + * @param SubselectFromClause + * @return string The SQL. + */ + public function walkSubselectFromClause($subselectFromClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkSubselectFromClause($subselectFromClause); + } + } + + /** + * Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL. + * + * @param SimpleSelectClause + * @return string The SQL. + */ + public function walkSimpleSelectClause($simpleSelectClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkSimpleSelectClause($simpleSelectClause); + } + } + + /** + * Walks down a SimpleSelectExpression AST node, thereby generating the appropriate SQL. + * + * @param SimpleSelectExpression + * @return string The SQL. + */ + public function walkSimpleSelectExpression($simpleSelectExpression) + { + foreach ($this->_walkers as $walker) { + $walker->walkSimpleSelectExpression($simpleSelectExpression); + } + } + + /** + * Walks down an AggregateExpression AST node, thereby generating the appropriate SQL. + * + * @param AggregateExpression + * @return string The SQL. + */ + public function walkAggregateExpression($aggExpression) + { + foreach ($this->_walkers as $walker) { + $walker->walkAggregateExpression($aggExpression); + } + } + + /** + * Walks down a GroupByClause AST node, thereby generating the appropriate SQL. + * + * @param GroupByClause + * @return string The SQL. + */ + public function walkGroupByClause($groupByClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkGroupByClause($groupByClause); + } + } + + /** + * Walks down a GroupByItem AST node, thereby generating the appropriate SQL. + * + * @param GroupByItem + * @return string The SQL. + */ + public function walkGroupByItem($groupByItem) + { + foreach ($this->_walkers as $walker) { + $walker->walkGroupByItem($groupByItem); + } + } + + /** + * Walks down an UpdateStatement AST node, thereby generating the appropriate SQL. + * + * @param UpdateStatement + * @return string The SQL. + */ + public function walkUpdateStatement(AST\UpdateStatement $AST) + { + foreach ($this->_walkers as $walker) { + $walker->walkUpdateStatement($AST); + } + } + + /** + * Walks down a DeleteStatement AST node, thereby generating the appropriate SQL. + * + * @param DeleteStatement + * @return string The SQL. + */ + public function walkDeleteStatement(AST\DeleteStatement $AST) + { + foreach ($this->_walkers as $walker) { + $walker->walkDeleteStatement($AST); + } + } + + /** + * Walks down a DeleteClause AST node, thereby generating the appropriate SQL. + * + * @param DeleteClause + * @return string The SQL. + */ + public function walkDeleteClause(AST\DeleteClause $deleteClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkDeleteClause($deleteClause); + } + } + + /** + * Walks down an UpdateClause AST node, thereby generating the appropriate SQL. + * + * @param UpdateClause + * @return string The SQL. + */ + public function walkUpdateClause($updateClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkUpdateClause($updateClause); + } + } + + /** + * Walks down an UpdateItem AST node, thereby generating the appropriate SQL. + * + * @param UpdateItem + * @return string The SQL. + */ + public function walkUpdateItem($updateItem) + { + foreach ($this->_walkers as $walker) { + $walker->walkUpdateItem($updateItem); + } + } + + /** + * Walks down a WhereClause AST node, thereby generating the appropriate SQL. + * + * @param WhereClause + * @return string The SQL. + */ + public function walkWhereClause($whereClause) + { + foreach ($this->_walkers as $walker) { + $walker->walkWhereClause($whereClause); + } + } + + /** + * Walks down a ConditionalExpression AST node, thereby generating the appropriate SQL. + * + * @param ConditionalExpression + * @return string The SQL. + */ + public function walkConditionalExpression($condExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkConditionalExpression($condExpr); + } + } + + /** + * Walks down a ConditionalTerm AST node, thereby generating the appropriate SQL. + * + * @param ConditionalTerm + * @return string The SQL. + */ + public function walkConditionalTerm($condTerm) + { + foreach ($this->_walkers as $walker) { + $walker->walkConditionalTerm($condTerm); + } + } + + /** + * Walks down a ConditionalFactor AST node, thereby generating the appropriate SQL. + * + * @param ConditionalFactor + * @return string The SQL. + */ + public function walkConditionalFactor($factor) + { + foreach ($this->_walkers as $walker) { + $walker->walkConditionalFactor($factor); + } + } + + /** + * Walks down a ConditionalPrimary AST node, thereby generating the appropriate SQL. + * + * @param ConditionalPrimary + * @return string The SQL. + */ + public function walkConditionalPrimary($condPrimary) + { + foreach ($this->_walkers as $walker) { + $walker->walkConditionalPrimary($condPrimary); + } + } + + /** + * Walks down an ExistsExpression AST node, thereby generating the appropriate SQL. + * + * @param ExistsExpression + * @return string The SQL. + */ + public function walkExistsExpression($existsExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkExistsExpression($existsExpr); + } + } + + /** + * Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL. + * + * @param CollectionMemberExpression + * @return string The SQL. + */ + public function walkCollectionMemberExpression($collMemberExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkCollectionMemberExpression($collMemberExpr); + } + } + + /** + * Walks down an EmptyCollectionComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param EmptyCollectionComparisonExpression + * @return string The SQL. + */ + public function walkEmptyCollectionComparisonExpression($emptyCollCompExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkEmptyCollectionComparisonExpression($emptyCollCompExpr); + } + } + + /** + * Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param NullComparisonExpression + * @return string The SQL. + */ + public function walkNullComparisonExpression($nullCompExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkNullComparisonExpression($nullCompExpr); + } + } + + /** + * Walks down an InExpression AST node, thereby generating the appropriate SQL. + * + * @param InExpression + * @return string The SQL. + */ + public function walkInExpression($inExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkInExpression($inExpr); + } + } + + /** + * Walks down an InstanceOfExpression AST node, thereby generating the appropriate SQL. + * + * @param InstanceOfExpression + * @return string The SQL. + */ + function walkInstanceOfExpression($instanceOfExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkInstanceOfExpression($instanceOfExpr); + } + } + + /** + * Walks down a literal that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkLiteral($literal) + { + foreach ($this->_walkers as $walker) { + $walker->walkLiteral($literal); + } + } + + /** + * Walks down a BetweenExpression AST node, thereby generating the appropriate SQL. + * + * @param BetweenExpression + * @return string The SQL. + */ + public function walkBetweenExpression($betweenExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkBetweenExpression($betweenExpr); + } + } + + /** + * Walks down a LikeExpression AST node, thereby generating the appropriate SQL. + * + * @param LikeExpression + * @return string The SQL. + */ + public function walkLikeExpression($likeExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkLikeExpression($likeExpr); + } + } + + /** + * Walks down a StateFieldPathExpression AST node, thereby generating the appropriate SQL. + * + * @param StateFieldPathExpression + * @return string The SQL. + */ + public function walkStateFieldPathExpression($stateFieldPathExpression) + { + foreach ($this->_walkers as $walker) { + $walker->walkStateFieldPathExpression($stateFieldPathExpression); + } + } + + /** + * Walks down a ComparisonExpression AST node, thereby generating the appropriate SQL. + * + * @param ComparisonExpression + * @return string The SQL. + */ + public function walkComparisonExpression($compExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkComparisonExpression($compExpr); + } + } + + /** + * Walks down an InputParameter AST node, thereby generating the appropriate SQL. + * + * @param InputParameter + * @return string The SQL. + */ + public function walkInputParameter($inputParam) + { + foreach ($this->_walkers as $walker) { + $walker->walkInputParameter($inputParam); + } + } + + /** + * Walks down an ArithmeticExpression AST node, thereby generating the appropriate SQL. + * + * @param ArithmeticExpression + * @return string The SQL. + */ + public function walkArithmeticExpression($arithmeticExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkArithmeticExpression($arithmeticExpr); + } + } + + /** + * Walks down an ArithmeticTerm AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkArithmeticTerm($term) + { + foreach ($this->_walkers as $walker) { + $walker->walkArithmeticTerm($term); + } + } + + /** + * Walks down a StringPrimary that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkStringPrimary($stringPrimary) + { + foreach ($this->_walkers as $walker) { + $walker->walkStringPrimary($stringPrimary); + } + } + + /** + * Walks down an ArithmeticFactor that represents an AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkArithmeticFactor($factor) + { + foreach ($this->_walkers as $walker) { + $walker->walkArithmeticFactor($factor); + } + } + + /** + * Walks down an SimpleArithmeticExpression AST node, thereby generating the appropriate SQL. + * + * @param SimpleArithmeticExpression + * @return string The SQL. + */ + public function walkSimpleArithmeticExpression($simpleArithmeticExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkSimpleArithmeticExpression($simpleArithmeticExpr); + } + } + + /** + * Walks down an PathExpression AST node, thereby generating the appropriate SQL. + * + * @param mixed + * @return string The SQL. + */ + public function walkPathExpression($pathExpr) + { + foreach ($this->_walkers as $walker) { + $walker->walkPathExpression($pathExpr); + } + } + + /** + * Walks down an ResultVariable AST node, thereby generating the appropriate SQL. + * + * @param string $resultVariable + * @return string The SQL. + */ + public function walkResultVariable($resultVariable) + { + foreach ($this->_walkers as $walker) { + $walker->walkResultVariable($resultVariable); + } + } + + /** + * Gets an executor that can be used to execute the result of this walker. + * + * @return AbstractExecutor + */ + public function getExecutor($AST) + {} +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/QueryBuilder.php b/vendor/doctrine/orm/lib/Doctrine/ORM/QueryBuilder.php new file mode 100644 index 0000000..51ef277 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/QueryBuilder.php @@ -0,0 +1,1181 @@ +. + */ + +namespace Doctrine\ORM; + +use Doctrine\Common\Collections\ArrayCollection; + +use Doctrine\ORM\Query\Expr; + +/** + * This class is responsible for building DQL query strings via an object oriented + * PHP interface. + * + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class QueryBuilder +{ + /* The query types. */ + const SELECT = 0; + const DELETE = 1; + const UPDATE = 2; + + /** The builder states. */ + const STATE_DIRTY = 0; + const STATE_CLEAN = 1; + + /** + * @var EntityManager The EntityManager used by this QueryBuilder. + */ + private $_em; + + /** + * @var array The array of DQL parts collected. + */ + private $_dqlParts = array( + 'distinct' => false, + 'select' => array(), + 'from' => array(), + 'join' => array(), + 'set' => array(), + 'where' => null, + 'groupBy' => array(), + 'having' => null, + 'orderBy' => array() + ); + + /** + * @var integer The type of query this is. Can be select, update or delete. + */ + private $_type = self::SELECT; + + /** + * @var integer The state of the query object. Can be dirty or clean. + */ + private $_state = self::STATE_CLEAN; + + /** + * @var string The complete DQL string for this query. + */ + private $_dql; + + /** + * @var \Doctrine\Common\Collections\ArrayCollection The query parameters. + */ + private $parameters = array(); + + /** + * @var integer The index of the first result to retrieve. + */ + private $_firstResult = null; + + /** + * @var integer The maximum number of results to retrieve. + */ + private $_maxResults = null; + + /** + * @var array Keeps root entity alias names for join entities. + */ + private $joinRootAliases = array(); + + /** + * Initializes a new QueryBuilder that uses the given EntityManager. + * + * @param EntityManager $em The EntityManager to use. + */ + public function __construct(EntityManager $em) + { + $this->_em = $em; + $this->parameters = new ArrayCollection(); + } + + /** + * Gets an ExpressionBuilder used for object-oriented construction of query expressions. + * This producer method is intended for convenient inline usage. Example: + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where($qb->expr()->eq('u.id', 1)); + * + * + * For more complex expression construction, consider storing the expression + * builder object in a local variable. + * + * @return Query\Expr + */ + public function expr() + { + return $this->_em->getExpressionBuilder(); + } + + /** + * Get the type of the currently built query. + * + * @return integer + */ + public function getType() + { + return $this->_type; + } + + /** + * Get the associated EntityManager for this query builder. + * + * @return EntityManager + */ + public function getEntityManager() + { + return $this->_em; + } + + /** + * Get the state of this query builder instance. + * + * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN. + */ + public function getState() + { + return $this->_state; + } + + /** + * Get the complete DQL string formed by the current specifications of this QueryBuilder. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * echo $qb->getDql(); // SELECT u FROM User u + * + * + * @return string The DQL query string. + */ + public function getDQL() + { + if ($this->_dql !== null && $this->_state === self::STATE_CLEAN) { + return $this->_dql; + } + + $dql = ''; + + switch ($this->_type) { + case self::DELETE: + $dql = $this->_getDQLForDelete(); + break; + + case self::UPDATE: + $dql = $this->_getDQLForUpdate(); + break; + + case self::SELECT: + default: + $dql = $this->_getDQLForSelect(); + break; + } + + $this->_state = self::STATE_CLEAN; + $this->_dql = $dql; + + return $dql; + } + + /** + * Constructs a Query instance from the current specifications of the builder. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u'); + * $q = $qb->getQuery(); + * $results = $q->execute(); + * + * + * @return Query + */ + public function getQuery() + { + $parameters = clone $this->parameters; + + return $this->_em->createQuery($this->getDQL()) + ->setParameters($parameters) + ->setFirstResult($this->_firstResult) + ->setMaxResults($this->_maxResults); + } + + /** + * Finds the root entity alias of the joined entity. + * + * @param string $alias The alias of the new join entity + * @param string $parentAlias The parent entity alias of the join relationship + * @return string + */ + private function findRootAlias($alias, $parentAlias) + { + $rootAlias = null; + + if (in_array($parentAlias, $this->getRootAliases())) { + $rootAlias = $parentAlias; + } elseif (isset($this->joinRootAliases[$parentAlias])) { + $rootAlias = $this->joinRootAliases[$parentAlias]; + } else { + // Should never happen with correct joining order. Might be + // thoughtful to throw exception instead. + $rootAlias = $this->getRootAlias(); + } + + $this->joinRootAliases[$alias] = $rootAlias; + + return $rootAlias; + } + + /** + * Gets the FIRST root alias of the query. This is the first entity alias involved + * in the construction of the query. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u'); + * + * echo $qb->getRootAlias(); // u + * + * + * @deprecated Please use $qb->getRootAliases() instead. + * @return string $rootAlias + */ + public function getRootAlias() + { + $aliases = $this->getRootAliases(); + return $aliases[0]; + } + + /** + * Gets the root aliases of the query. This is the entity aliases involved + * in the construction of the query. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u'); + * + * $qb->getRootAliases(); // array('u') + * + * + * @return array $rootAliases + */ + public function getRootAliases() + { + $aliases = array(); + + foreach ($this->_dqlParts['from'] as &$fromClause) { + if (is_string($fromClause)) { + $spacePos = strrpos($fromClause, ' '); + $from = substr($fromClause, 0, $spacePos); + $alias = substr($fromClause, $spacePos + 1); + + $fromClause = new Query\Expr\From($from, $alias); + } + + $aliases[] = $fromClause->getAlias(); + } + + return $aliases; + } + + /** + * Gets the root entities of the query. This is the entity aliases involved + * in the construction of the query. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u'); + * + * $qb->getRootEntities(); // array('User') + * + * + * @return array $rootEntities + */ + public function getRootEntities() + { + $entities = array(); + + foreach ($this->_dqlParts['from'] as &$fromClause) { + if (is_string($fromClause)) { + $spacePos = strrpos($fromClause, ' '); + $from = substr($fromClause, 0, $spacePos); + $alias = substr($fromClause, $spacePos + 1); + + $fromClause = new Query\Expr\From($from, $alias); + } + + $entities[] = $fromClause->getFrom(); + } + + return $entities; + } + + /** + * Sets a query parameter for the query being constructed. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.id = :user_id') + * ->setParameter('user_id', 1); + * + * + * @param string|integer $key The parameter position or name. + * @param mixed $value The parameter value. + * @param string|null $type PDO::PARAM_* or \Doctrine\DBAL\Types\Type::* constant + * @return QueryBuilder This QueryBuilder instance. + */ + public function setParameter($key, $value, $type = null) + { + $filteredParameters = $this->parameters->filter( + function ($parameter) use ($key) + { + // Must not be identical because of string to integer conversion + return ($key == $parameter->getName()); + } + ); + + if (count($filteredParameters)) { + $parameter = $filteredParameters->first(); + $parameter->setValue($value, $type); + + return $this; + } + + $parameter = new Query\Parameter($key, $value, $type); + + $this->parameters->add($parameter); + + return $this; + } + + /** + * Sets a collection of query parameters for the query being constructed. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.id = :user_id1 OR u.id = :user_id2') + * ->setParameters(new ArrayCollection(array( + * new Parameter('user_id1', 1), + * new Parameter('user_id2', 2) + ))); + * + * + * @param \Doctrine\Common\Collections\ArrayCollection|array $params The query parameters to set. + * @return QueryBuilder This QueryBuilder instance. + */ + public function setParameters($parameters) + { + // BC compatibility with 2.3- + if (is_array($parameters)) { + $parameterCollection = new ArrayCollection(); + + foreach ($parameters as $key => $value) { + $parameter = new Query\Parameter($key, $value); + + $parameterCollection->add($parameter); + } + + $parameters = $parameterCollection; + } + + $this->parameters = $parameters; + + return $this; + } + + /** + * Gets all defined query parameters for the query being constructed. + * + * @return \Doctrine\Common\Collections\ArrayCollection The currently defined query parameters. + */ + public function getParameters() + { + return $this->parameters; + } + + /** + * Gets a (previously set) query parameter of the query being constructed. + * + * @param mixed $key The key (index or name) of the bound parameter. + * + * @return Query\Parameter|null The value of the bound parameter. + */ + public function getParameter($key) + { + $filteredParameters = $this->parameters->filter( + function ($parameter) use ($key) + { + // Must not be identical because of string to integer conversion + return ($key == $parameter->getName()); + } + ); + + return count($filteredParameters) ? $filteredParameters->first() : null; + } + + /** + * Sets the position of the first result to retrieve (the "offset"). + * + * @param integer $firstResult The first result to return. + * @return QueryBuilder This QueryBuilder instance. + */ + public function setFirstResult($firstResult) + { + $this->_firstResult = $firstResult; + + return $this; + } + + /** + * Gets the position of the first result the query object was set to retrieve (the "offset"). + * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder. + * + * @return integer The position of the first result. + */ + public function getFirstResult() + { + return $this->_firstResult; + } + + /** + * Sets the maximum number of results to retrieve (the "limit"). + * + * @param integer $maxResults The maximum number of results to retrieve. + * @return QueryBuilder This QueryBuilder instance. + */ + public function setMaxResults($maxResults) + { + $this->_maxResults = $maxResults; + + return $this; + } + + /** + * Gets the maximum number of results the query object was set to retrieve (the "limit"). + * Returns NULL if {@link setMaxResults} was not applied to this query builder. + * + * @return integer Maximum number of results. + */ + public function getMaxResults() + { + return $this->_maxResults; + } + + /** + * Either appends to or replaces a single, generic query part. + * + * The available parts are: 'select', 'from', 'join', 'set', 'where', + * 'groupBy', 'having' and 'orderBy'. + * + * @param string $dqlPartName + * @param string $dqlPart + * @param string $append + * @return QueryBuilder This QueryBuilder instance. + */ + public function add($dqlPartName, $dqlPart, $append = false) + { + $isMultiple = is_array($this->_dqlParts[$dqlPartName]); + + // This is introduced for backwards compatibility reasons. + // TODO: Remove for 3.0 + if ($dqlPartName == 'join') { + $newDqlPart = array(); + + foreach ($dqlPart as $k => $v) { + $k = is_numeric($k) ? $this->getRootAlias() : $k; + + $newDqlPart[$k] = $v; + } + + $dqlPart = $newDqlPart; + } + + if ($append && $isMultiple) { + if (is_array($dqlPart)) { + $key = key($dqlPart); + + $this->_dqlParts[$dqlPartName][$key][] = $dqlPart[$key]; + } else { + $this->_dqlParts[$dqlPartName][] = $dqlPart; + } + } else { + $this->_dqlParts[$dqlPartName] = ($isMultiple) ? array($dqlPart) : $dqlPart; + } + + $this->_state = self::STATE_DIRTY; + + return $this; + } + + /** + * Specifies an item that is to be returned in the query result. + * Replaces any previously specified selections, if any. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u', 'p') + * ->from('User', 'u') + * ->leftJoin('u.Phonenumbers', 'p'); + * + * + * @param mixed $select The selection expressions. + * @return QueryBuilder This QueryBuilder instance. + */ + public function select($select = null) + { + $this->_type = self::SELECT; + + if (empty($select)) { + return $this; + } + + $selects = is_array($select) ? $select : func_get_args(); + + return $this->add('select', new Expr\Select($selects), false); + } + + /** + * Add a DISTINCT flag to this query. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->distinct() + * ->from('User', 'u'); + * + * + * @param bool + * @return QueryBuilder + */ + public function distinct($flag = true) + { + $this->_dqlParts['distinct'] = (bool) $flag; + + return $this; + } + + /** + * Adds an item that is to be returned in the query result. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->addSelect('p') + * ->from('User', 'u') + * ->leftJoin('u.Phonenumbers', 'p'); + * + * + * @param mixed $select The selection expression. + * @return QueryBuilder This QueryBuilder instance. + */ + public function addSelect($select = null) + { + $this->_type = self::SELECT; + + if (empty($select)) { + return $this; + } + + $selects = is_array($select) ? $select : func_get_args(); + + return $this->add('select', new Expr\Select($selects), true); + } + + /** + * Turns the query being built into a bulk delete query that ranges over + * a certain entity type. + * + * + * $qb = $em->createQueryBuilder() + * ->delete('User', 'u') + * ->where('u.id = :user_id'); + * ->setParameter('user_id', 1); + * + * + * @param string $delete The class/type whose instances are subject to the deletion. + * @param string $alias The class/type alias used in the constructed query. + * @return QueryBuilder This QueryBuilder instance. + */ + public function delete($delete = null, $alias = null) + { + $this->_type = self::DELETE; + + if ( ! $delete) { + return $this; + } + + return $this->add('from', new Expr\From($delete, $alias)); + } + + /** + * Turns the query being built into a bulk update query that ranges over + * a certain entity type. + * + * + * $qb = $em->createQueryBuilder() + * ->update('User', 'u') + * ->set('u.password', md5('password')) + * ->where('u.id = ?'); + * + * + * @param string $update The class/type whose instances are subject to the update. + * @param string $alias The class/type alias used in the constructed query. + * @return QueryBuilder This QueryBuilder instance. + */ + public function update($update = null, $alias = null) + { + $this->_type = self::UPDATE; + + if ( ! $update) { + return $this; + } + + return $this->add('from', new Expr\From($update, $alias)); + } + + /** + * Create and add a query root corresponding to the entity identified by the given alias, + * forming a cartesian product with any existing query roots. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * + * + * @param string $from The class name. + * @param string $alias The alias of the class. + * @param string $indexBy The index for the from. + * @return QueryBuilder This QueryBuilder instance. + */ + public function from($from, $alias, $indexBy = null) + { + return $this->add('from', new Expr\From($from, $alias, $indexBy), true); + } + + /** + * Creates and adds a join over an entity association to the query. + * + * The entities in the joined association will be fetched as part of the query + * result if the alias used for the joined association is placed in the select + * expressions. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); + * + * + * @param string $join The relationship to join + * @param string $alias The alias of the join + * @param string $conditionType The condition type constant. Either ON or WITH. + * @param string $condition The condition for the join + * @param string $indexBy The index for the join + * @return QueryBuilder This QueryBuilder instance. + */ + public function join($join, $alias, $conditionType = null, $condition = null, $indexBy = null) + { + return $this->innerJoin($join, $alias, $conditionType, $condition, $indexBy); + } + + /** + * Creates and adds a join over an entity association to the query. + * + * The entities in the joined association will be fetched as part of the query + * result if the alias used for the joined association is placed in the select + * expressions. + * + * [php] + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); + * + * @param string $join The relationship to join + * @param string $alias The alias of the join + * @param string $conditionType The condition type constant. Either ON or WITH. + * @param string $condition The condition for the join + * @param string $indexBy The index for the join + * @return QueryBuilder This QueryBuilder instance. + */ + public function innerJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null) + { + $parentAlias = substr($join, 0, strpos($join, '.')); + + $rootAlias = $this->findRootAlias($alias, $parentAlias); + + $join = new Expr\Join( + Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy + ); + + return $this->add('join', array($rootAlias => $join), true); + } + + /** + * Creates and adds a left join over an entity association to the query. + * + * The entities in the joined association will be fetched as part of the query + * result if the alias used for the joined association is placed in the select + * expressions. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1'); + * + * + * @param string $join The relationship to join + * @param string $alias The alias of the join + * @param string $conditionType The condition type constant. Either ON or WITH. + * @param string $condition The condition for the join + * @param string $indexBy The index for the join + * @return QueryBuilder This QueryBuilder instance. + */ + public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null) + { + $parentAlias = substr($join, 0, strpos($join, '.')); + + $rootAlias = $this->findRootAlias($alias, $parentAlias); + + $join = new Expr\Join( + Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy + ); + + return $this->add('join', array($rootAlias => $join), true); + } + + /** + * Sets a new value for a field in a bulk update query. + * + * + * $qb = $em->createQueryBuilder() + * ->update('User', 'u') + * ->set('u.password', md5('password')) + * ->where('u.id = ?'); + * + * + * @param string $key The key/field to set. + * @param string $value The value, expression, placeholder, etc. + * @return QueryBuilder This QueryBuilder instance. + */ + public function set($key, $value) + { + return $this->add('set', new Expr\Comparison($key, Expr\Comparison::EQ, $value), true); + } + + /** + * Specifies one or more restrictions to the query result. + * Replaces any previously specified restrictions, if any. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.id = ?'); + * + * // You can optionally programatically build and/or expressions + * $qb = $em->createQueryBuilder(); + * + * $or = $qb->expr()->orx(); + * $or->add($qb->expr()->eq('u.id', 1)); + * $or->add($qb->expr()->eq('u.id', 2)); + * + * $qb->update('User', 'u') + * ->set('u.password', md5('password')) + * ->where($or); + * + * + * @param mixed $predicates The restriction predicates. + * @return QueryBuilder This QueryBuilder instance. + */ + public function where($predicates) + { + if ( ! (func_num_args() == 1 && $predicates instanceof Expr\Composite)) { + $predicates = new Expr\Andx(func_get_args()); + } + + return $this->add('where', $predicates); + } + + /** + * Adds one or more restrictions to the query results, forming a logical + * conjunction with any previously specified restrictions. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.username LIKE ?') + * ->andWhere('u.is_active = 1'); + * + * + * @param mixed $where The query restrictions. + * @return QueryBuilder This QueryBuilder instance. + * @see where() + */ + public function andWhere($where) + { + $where = $this->getDQLPart('where'); + $args = func_get_args(); + + if ($where instanceof Expr\Andx) { + $where->addMultiple($args); + } else { + array_unshift($args, $where); + $where = new Expr\Andx($args); + } + + return $this->add('where', $where, true); + } + + /** + * Adds one or more restrictions to the query results, forming a logical + * disjunction with any previously specified restrictions. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->where('u.id = 1') + * ->orWhere('u.id = 2'); + * + * + * @param mixed $where The WHERE statement + * @return QueryBuilder $qb + * @see where() + */ + public function orWhere($where) + { + $where = $this->getDqlPart('where'); + $args = func_get_args(); + + if ($where instanceof Expr\Orx) { + $where->addMultiple($args); + } else { + array_unshift($args, $where); + $where = new Expr\Orx($args); + } + + return $this->add('where', $where, true); + } + + /** + * Specifies a grouping over the results of the query. + * Replaces any previously specified groupings, if any. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->groupBy('u.id'); + * + * + * @param string $groupBy The grouping expression. + * @return QueryBuilder This QueryBuilder instance. + */ + public function groupBy($groupBy) + { + return $this->add('groupBy', new Expr\GroupBy(func_get_args())); + } + + + /** + * Adds a grouping expression to the query. + * + * + * $qb = $em->createQueryBuilder() + * ->select('u') + * ->from('User', 'u') + * ->groupBy('u.lastLogin'); + * ->addGroupBy('u.createdAt') + * + * + * @param string $groupBy The grouping expression. + * @return QueryBuilder This QueryBuilder instance. + */ + public function addGroupBy($groupBy) + { + return $this->add('groupBy', new Expr\GroupBy(func_get_args()), true); + } + + /** + * Specifies a restriction over the groups of the query. + * Replaces any previous having restrictions, if any. + * + * @param mixed $having The restriction over the groups. + * @return QueryBuilder This QueryBuilder instance. + */ + public function having($having) + { + if ( ! (func_num_args() == 1 && ($having instanceof Expr\Andx || $having instanceof Expr\Orx))) { + $having = new Expr\Andx(func_get_args()); + } + + return $this->add('having', $having); + } + + /** + * Adds a restriction over the groups of the query, forming a logical + * conjunction with any existing having restrictions. + * + * @param mixed $having The restriction to append. + * @return QueryBuilder This QueryBuilder instance. + */ + public function andHaving($having) + { + $having = $this->getDqlPart('having'); + $args = func_get_args(); + + if ($having instanceof Expr\Andx) { + $having->addMultiple($args); + } else { + array_unshift($args, $having); + $having = new Expr\Andx($args); + } + + return $this->add('having', $having); + } + + /** + * Adds a restriction over the groups of the query, forming a logical + * disjunction with any existing having restrictions. + * + * @param mixed $having The restriction to add. + * @return QueryBuilder This QueryBuilder instance. + */ + public function orHaving($having) + { + $having = $this->getDqlPart('having'); + $args = func_get_args(); + + if ($having instanceof Expr\Orx) { + $having->addMultiple($args); + } else { + array_unshift($args, $having); + $having = new Expr\Orx($args); + } + + return $this->add('having', $having); + } + + /** + * Specifies an ordering for the query results. + * Replaces any previously specified orderings, if any. + * + * @param string $sort The ordering expression. + * @param string $order The ordering direction. + * @return QueryBuilder This QueryBuilder instance. + */ + public function orderBy($sort, $order = null) + { + $orderBy = ($sort instanceof Expr\OrderBy) ? $sort : new Expr\OrderBy($sort, $order); + + return $this->add('orderBy', $orderBy); + } + + /** + * Adds an ordering to the query results. + * + * @param string $sort The ordering expression. + * @param string $order The ordering direction. + * @return QueryBuilder This QueryBuilder instance. + */ + public function addOrderBy($sort, $order = null) + { + return $this->add('orderBy', new Expr\OrderBy($sort, $order), true); + } + + /** + * Get a query part by its name. + * + * @param string $queryPartName + * @return mixed $queryPart + * @todo Rename: getQueryPart (or remove?) + */ + public function getDQLPart($queryPartName) + { + return $this->_dqlParts[$queryPartName]; + } + + /** + * Get all query parts. + * + * @return array $dqlParts + * @todo Rename: getQueryParts (or remove?) + */ + public function getDQLParts() + { + return $this->_dqlParts; + } + + private function _getDQLForDelete() + { + return 'DELETE' + . $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', ')) + . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE ')) + . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', ')); + } + + private function _getDQLForUpdate() + { + return 'UPDATE' + . $this->_getReducedDQLQueryPart('from', array('pre' => ' ', 'separator' => ', ')) + . $this->_getReducedDQLQueryPart('set', array('pre' => ' SET ', 'separator' => ', ')) + . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE ')) + . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', ')); + } + + private function _getDQLForSelect() + { + $dql = 'SELECT' + . ($this->_dqlParts['distinct']===true ? ' DISTINCT' : '') + . $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', ')); + + $fromParts = $this->getDQLPart('from'); + $joinParts = $this->getDQLPart('join'); + $fromClauses = array(); + + // Loop through all FROM clauses + if ( ! empty($fromParts)) { + $dql .= ' FROM '; + + foreach ($fromParts as $from) { + $fromClause = (string) $from; + + if ($from instanceof Expr\From && isset($joinParts[$from->getAlias()])) { + foreach ($joinParts[$from->getAlias()] as $join) { + $fromClause .= ' ' . ((string) $join); + } + } + + $fromClauses[] = $fromClause; + } + } + + $dql .= implode(', ', $fromClauses) + . $this->_getReducedDQLQueryPart('where', array('pre' => ' WHERE ')) + . $this->_getReducedDQLQueryPart('groupBy', array('pre' => ' GROUP BY ', 'separator' => ', ')) + . $this->_getReducedDQLQueryPart('having', array('pre' => ' HAVING ')) + . $this->_getReducedDQLQueryPart('orderBy', array('pre' => ' ORDER BY ', 'separator' => ', ')); + + return $dql; + } + + private function _getReducedDQLQueryPart($queryPartName, $options = array()) + { + $queryPart = $this->getDQLPart($queryPartName); + + if (empty($queryPart)) { + return (isset($options['empty']) ? $options['empty'] : ''); + } + + return (isset($options['pre']) ? $options['pre'] : '') + . (is_array($queryPart) ? implode($options['separator'], $queryPart) : $queryPart) + . (isset($options['post']) ? $options['post'] : ''); + } + + /** + * Reset DQL parts + * + * @param array $parts + * @return QueryBuilder + */ + public function resetDQLParts($parts = null) + { + if (is_null($parts)) { + $parts = array_keys($this->_dqlParts); + } + + foreach ($parts as $part) { + $this->resetDQLPart($part); + } + + return $this; + } + + /** + * Reset single DQL part + * + * @param string $part + * @return QueryBuilder; + */ + public function resetDQLPart($part) + { + $this->_dqlParts[$part] = is_array($this->_dqlParts[$part]) ? array() : null; + $this->_state = self::STATE_DIRTY; + + return $this; + } + + /** + * Gets a string representation of this QueryBuilder which corresponds to + * the final DQL query being constructed. + * + * @return string The string representation of this QueryBuilder. + */ + public function __toString() + { + return $this->getDQL(); + } + + /** + * Deep clone of all expression objects in the DQL parts. + * + * @return void + */ + public function __clone() + { + foreach ($this->_dqlParts as $part => $elements) { + if (is_array($this->_dqlParts[$part])) { + foreach ($this->_dqlParts[$part] as $idx => $element) { + if (is_object($element)) { + $this->_dqlParts[$part][$idx] = clone $element; + } + } + } else if (is_object($elements)) { + $this->_dqlParts[$part] = clone $elements; + } + } + + $parameters = array(); + + foreach ($this->parameters as $parameter) { + $parameters[] = clone $parameter; + } + + $this->parameters = new ArrayCollection($parameters); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/README.markdown b/vendor/doctrine/orm/lib/Doctrine/ORM/README.markdown new file mode 100644 index 0000000..e69de29 diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php new file mode 100644 index 0000000..c01d964 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php @@ -0,0 +1,103 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\ClearCache; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console, + Doctrine\Common\Cache; + +/** + * Command to clear the metadata cache of the various cache drivers. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class MetadataCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:clear-cache:metadata') + ->setDescription('Clear all metadata cache of the various cache drivers.') + ->setDefinition(array( + new InputOption( + 'flush', null, InputOption::VALUE_NONE, + 'If defined, cache entries will be flushed instead of deleted/invalidated.' + ) + )); + + $this->setHelp(<<%command.name% command is meant to clear the metadata cache of associated Entity Manager. +It is possible to invalidate all cache entries at once - called delete -, or flushes the cache provider +instance completely. + +The execution type differ on how you execute the command. +If you want to invalidate the entries (and not delete from cache instance), this command would do the work: + +%command.name% + +Alternatively, if you want to flush the cache provider using this command: + +%command.name% --flush + +Finally, be aware that if --flush option is passed, not all cache providers are able to flush entries, +because of a limitation of its execution nature. +EOT + ); + } + + /** + * @see Console\Command\Command + */ + protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output) + { + $em = $this->getHelper('em')->getEntityManager(); + $cacheDriver = $em->getConfiguration()->getMetadataCacheImpl(); + + if ( ! $cacheDriver) { + throw new \InvalidArgumentException('No Metadata cache driver is configured on given EntityManager.'); + } + + if ($cacheDriver instanceof Cache\ApcCache) { + throw new \LogicException("Cannot clear APC Cache from Console, its shared in the Webserver memory and not accessible from the CLI."); + } + + $output->write('Clearing ALL Metadata cache entries' . PHP_EOL); + + $result = $cacheDriver->deleteAll(); + $message = ($result) ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.'; + + if (true === $input->getOption('flush')) { + $result = $cacheDriver->flushAll(); + $message = ($result) ? 'Successfully flushed cache entries.' : $message; + } + + $output->write($message . PHP_EOL); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php new file mode 100644 index 0000000..a984b96 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php @@ -0,0 +1,103 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\ClearCache; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console, + Doctrine\Common\Cache; + +/** + * Command to clear the query cache of the various cache drivers. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class QueryCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:clear-cache:query') + ->setDescription('Clear all query cache of the various cache drivers.') + ->setDefinition(array( + new InputOption( + 'flush', null, InputOption::VALUE_NONE, + 'If defined, cache entries will be flushed instead of deleted/invalidated.' + ) + )); + + $this->setHelp(<<%command.name% command is meant to clear the query cache of associated Entity Manager. +It is possible to invalidate all cache entries at once - called delete -, or flushes the cache provider +instance completely. + +The execution type differ on how you execute the command. +If you want to invalidate the entries (and not delete from cache instance), this command would do the work: + +%command.name% + +Alternatively, if you want to flush the cache provider using this command: + +%command.name% --flush + +Finally, be aware that if --flush option is passed, not all cache providers are able to flush entries, +because of a limitation of its execution nature. +EOT + ); + } + + /** + * @see Console\Command\Command + */ + protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output) + { + $em = $this->getHelper('em')->getEntityManager(); + $cacheDriver = $em->getConfiguration()->getQueryCacheImpl(); + + if ( ! $cacheDriver) { + throw new \InvalidArgumentException('No Query cache driver is configured on given EntityManager.'); + } + + if ($cacheDriver instanceof Cache\ApcCache) { + throw new \LogicException("Cannot clear APC Cache from Console, its shared in the Webserver memory and not accessible from the CLI."); + } + + $output->write('Clearing ALL Query cache entries' . PHP_EOL); + + $result = $cacheDriver->deleteAll(); + $message = ($result) ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.'; + + if (true === $input->getOption('flush')) { + $result = $cacheDriver->flushAll(); + $message = ($result) ? 'Successfully flushed cache entries.' : $message; + } + + $output->write($message . PHP_EOL); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php new file mode 100644 index 0000000..096aa53 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php @@ -0,0 +1,103 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\ClearCache; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console, + Doctrine\Common\Cache; + +/** + * Command to clear the result cache of the various cache drivers. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ResultCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:clear-cache:result') + ->setDescription('Clear all result cache of the various cache drivers.') + ->setDefinition(array( + new InputOption( + 'flush', null, InputOption::VALUE_NONE, + 'If defined, cache entries will be flushed instead of deleted/invalidated.' + ) + )); + + $this->setHelp(<<%command.name% command is meant to clear the result cache of associated Entity Manager. +It is possible to invalidate all cache entries at once - called delete -, or flushes the cache provider +instance completely. + +The execution type differ on how you execute the command. +If you want to invalidate the entries (and not delete from cache instance), this command would do the work: + +%command.name% + +Alternatively, if you want to flush the cache provider using this command: + +%command.name% --flush + +Finally, be aware that if --flush option is passed, not all cache providers are able to flush entries, +because of a limitation of its execution nature. +EOT + ); + } + + /** + * @see Console\Command\Command + */ + protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output) + { + $em = $this->getHelper('em')->getEntityManager(); + $cacheDriver = $em->getConfiguration()->getResultCacheImpl(); + + if ( ! $cacheDriver) { + throw new \InvalidArgumentException('No Result cache driver is configured on given EntityManager.'); + } + + if ($cacheDriver instanceof Cache\ApcCache) { + throw new \LogicException("Cannot clear APC Cache from Console, its shared in the Webserver memory and not accessible from the CLI."); + } + + $output->write('Clearing ALL Result cache entries' . PHP_EOL); + + $result = $cacheDriver->deleteAll(); + $message = ($result) ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.'; + + if (true === $input->getOption('flush')) { + $result = $cacheDriver->flushAll(); + $message = ($result) ? 'Successfully flushed cache entries.' : $message; + } + + $output->write($message . PHP_EOL); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php new file mode 100644 index 0000000..a964299 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php @@ -0,0 +1,220 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console, + Doctrine\ORM\Tools\Export\ClassMetadataExporter, + Doctrine\ORM\Tools\ConvertDoctrine1Schema, + Doctrine\ORM\Tools\EntityGenerator; + +/** + * Command to convert a Doctrine 1 schema to a Doctrine 2 mapping file. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConvertDoctrine1SchemaCommand extends Console\Command\Command +{ + /** + * @var EntityGenerator + */ + private $entityGenerator = null; + + /** + * @var ClassMetadataExporter + */ + private $metadataExporter = null; + + /** + * @return EntityGenerator + */ + public function getEntityGenerator() + { + if ($this->entityGenerator == null) { + $this->entityGenerator = new EntityGenerator(); + } + + return $this->entityGenerator; + } + + /** + * @param EntityGenerator $entityGenerator + */ + public function setEntityGenerator(EntityGenerator $entityGenerator) + { + $this->entityGenerator = $entityGenerator; + } + + /** + * @return ClassMetadataExporter + */ + public function getMetadataExporter() + { + if ($this->metadataExporter == null) { + $this->metadataExporter = new ClassMetadataExporter(); + } + + return $this->metadataExporter; + } + + /** + * @param ClassMetadataExporter $metadataExporter + */ + public function setMetadataExporter(ClassMetadataExporter $metadataExporter) + { + $this->metadataExporter = $metadataExporter; + } + + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:convert-d1-schema') + ->setDescription('Converts Doctrine 1.X schema into a Doctrine 2.X schema.') + ->setDefinition(array( + new InputArgument( + 'from-path', InputArgument::REQUIRED, 'The path of Doctrine 1.X schema information.' + ), + new InputArgument( + 'to-type', InputArgument::REQUIRED, 'The destination Doctrine 2.X mapping type.' + ), + new InputArgument( + 'dest-path', InputArgument::REQUIRED, + 'The path to generate your Doctrine 2.X mapping information.' + ), + new InputOption( + 'from', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Optional paths of Doctrine 1.X schema information.', + array() + ), + new InputOption( + 'extend', null, InputOption::VALUE_OPTIONAL, + 'Defines a base class to be extended by generated entity classes.' + ), + new InputOption( + 'num-spaces', null, InputOption::VALUE_OPTIONAL, + 'Defines the number of indentation spaces', 4 + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + // Process source directories + $fromPaths = array_merge(array($input->getArgument('from-path')), $input->getOption('from')); + + // Process destination directory + $destPath = realpath($input->getArgument('dest-path')); + + $toType = $input->getArgument('to-type'); + $extend = $input->getOption('extend'); + $numSpaces = $input->getOption('num-spaces'); + + $this->convertDoctrine1Schema($em, $fromPaths, $destPath, $toType, $numSpaces, $extend, $output); + } + + /** + * @param \Doctrine\ORM\EntityManager $em + * @param array $fromPaths + * @param string $destPath + * @param string $toType + * @param int $numSpaces + * @param string|null $extend + * @param Console\Output\OutputInterface $output + */ + public function convertDoctrine1Schema($em, $fromPaths, $destPath, $toType, $numSpaces, $extend, $output) + { + foreach ($fromPaths as &$dirName) { + $dirName = realpath($dirName); + + if ( ! file_exists($dirName)) { + throw new \InvalidArgumentException( + sprintf("Doctrine 1.X schema directory '%s' does not exist.", $dirName) + ); + } else if ( ! is_readable($dirName)) { + throw new \InvalidArgumentException( + sprintf("Doctrine 1.X schema directory '%s' does not have read permissions.", $dirName) + ); + } + } + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Doctrine 2.X mapping destination directory '%s' does not exist.", $destPath) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Doctrine 2.X mapping destination directory '%s' does not have write permissions.", $destPath) + ); + } + + $cme = $this->getMetadataExporter(); + $exporter = $cme->getExporter($toType, $destPath); + + if (strtolower($toType) === 'annotation') { + $entityGenerator = $this->getEntityGenerator(); + $exporter->setEntityGenerator($entityGenerator); + + $entityGenerator->setNumSpaces($numSpaces); + + if ($extend !== null) { + $entityGenerator->setClassToExtend($extend); + } + } + + $converter = new ConvertDoctrine1Schema($fromPaths); + $metadata = $converter->getMetadata(); + + if ($metadata) { + $output->write(PHP_EOL); + + foreach ($metadata as $class) { + $output->write(sprintf('Processing entity "%s"', $class->name) . PHP_EOL); + } + + $exporter->setMetadata($metadata); + $exporter->export(); + + $output->write(PHP_EOL . sprintf( + 'Converting Doctrine 1.X schema to "%s" mapping type in "%s"', $toType, $destPath + )); + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php new file mode 100644 index 0000000..84070fb --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php @@ -0,0 +1,183 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console, + Doctrine\ORM\Tools\Console\MetadataFilter, + Doctrine\ORM\Tools\Export\ClassMetadataExporter, + Doctrine\ORM\Tools\EntityGenerator, + Doctrine\ORM\Tools\DisconnectedClassMetadataFactory; + +/** + * Command to convert your mapping information between the various formats. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConvertMappingCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:convert-mapping') + ->setDescription('Convert mapping information between supported formats.') + ->setDefinition(array( + new InputOption( + 'filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'A string pattern used to match entities that should be processed.' + ), + new InputArgument( + 'to-type', InputArgument::REQUIRED, 'The mapping type to be converted.' + ), + new InputArgument( + 'dest-path', InputArgument::REQUIRED, + 'The path to generate your entities classes.' + ), + new InputOption( + 'force', null, InputOption::VALUE_NONE, + 'Force to overwrite existing mapping files.' + ), + new InputOption( + 'from-database', null, null, 'Whether or not to convert mapping information from existing database.' + ), + new InputOption( + 'extend', null, InputOption::VALUE_OPTIONAL, + 'Defines a base class to be extended by generated entity classes.' + ), + new InputOption( + 'num-spaces', null, InputOption::VALUE_OPTIONAL, + 'Defines the number of indentation spaces', 4 + ), + new InputOption( + 'namespace', null, InputOption::VALUE_OPTIONAL, + 'Defines a namespace for the generated entity classes, if converted from database.' + ), + )) + ->setHelp(<<one-time command. It should not be necessary for +you to call this method multiple times, escpecially when using the --from-database +flag. + +Converting an existing databsae schema into mapping files only solves about 70-80% +of the necessary mapping information. Additionally the detection from an existing +database cannot detect inverse associations, inheritance types, +entities with foreign keys as primary keys and many of the +semantical operations on associations such as cascade. + +Hint: There is no need to convert YAML or XML mapping files to annotations +every time you make changes. All mapping drivers are first class citizens +in Doctrine 2 and can be used as runtime mapping for the ORM. +EOT + ); + } + + /** + * @see Console\Command\Command + */ + protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output) + { + $em = $this->getHelper('em')->getEntityManager(); + + if ($input->getOption('from-database') === true) { + $databaseDriver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver( + $em->getConnection()->getSchemaManager() + ); + + $em->getConfiguration()->setMetadataDriverImpl( + $databaseDriver + ); + + if (($namespace = $input->getOption('namespace')) !== null) { + $databaseDriver->setNamespace($namespace); + } + } + + $cmf = new DisconnectedClassMetadataFactory(); + $cmf->setEntityManager($em); + $metadata = $cmf->getAllMetadata(); + $metadata = MetadataFilter::filter($metadata, $input->getOption('filter')); + + // Process destination directory + if ( ! is_dir($destPath = $input->getArgument('dest-path'))) { + mkdir($destPath, 0777, true); + } + $destPath = realpath($destPath); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Mapping destination directory '%s' does not exist.", $input->getArgument('dest-path')) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Mapping destination directory '%s' does not have write permissions.", $destPath) + ); + } + + $toType = strtolower($input->getArgument('to-type')); + + $exporter = $this->getExporter($toType, $destPath); + $exporter->setOverwriteExistingFiles( ($input->getOption('force') !== false) ); + + if ($toType == 'annotation') { + $entityGenerator = new EntityGenerator(); + $exporter->setEntityGenerator($entityGenerator); + + $entityGenerator->setNumSpaces($input->getOption('num-spaces')); + + if (($extend = $input->getOption('extend')) !== null) { + $entityGenerator->setClassToExtend($extend); + } + } + + if (count($metadata)) { + foreach ($metadata as $class) { + $output->write(sprintf('Processing entity "%s"', $class->name) . PHP_EOL); + } + + $exporter->setMetadata($metadata); + $exporter->export(); + + $output->write(PHP_EOL . sprintf( + 'Exporting "%s" mapping information to "%s"' . PHP_EOL, $toType, $destPath + )); + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } + + protected function getExporter($toType, $destPath) + { + $cme = new ClassMetadataExporter(); + + return $cme->getExporter($toType, $destPath); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/EnsureProductionSettingsCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/EnsureProductionSettingsCommand.php new file mode 100644 index 0000000..53f90b2 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/EnsureProductionSettingsCommand.php @@ -0,0 +1,83 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console; + +/** + * Command to ensure that Doctrine is properly configured for a production environment. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EnsureProductionSettingsCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:ensure-production-settings') + ->setDescription('Verify that Doctrine is properly configured for a production environment.') + ->setDefinition(array( + new InputOption( + 'complete', null, InputOption::VALUE_NONE, + 'Flag to also inspect database connection existance.' + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + $error = false; + try { + $em->getConfiguration()->ensureProductionSettings(); + + if ($input->getOption('complete') !== null) { + $em->getConnection()->connect(); + } + } catch (\Exception $e) { + $error = true; + $output->writeln('' . $e->getMessage() . ''); + } + + if ($error === false) { + $output->write('Environment is correctly configured for production.' . PHP_EOL); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php new file mode 100644 index 0000000..7210b6b --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php @@ -0,0 +1,160 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console, + Doctrine\ORM\Tools\Console\MetadataFilter, + Doctrine\ORM\Tools\EntityGenerator, + Doctrine\ORM\Tools\DisconnectedClassMetadataFactory; + +/** + * Command to generate entity classes and method stubs from your mapping information. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GenerateEntitiesCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:generate-entities') + ->setDescription('Generate entity classes and method stubs from your mapping information.') + ->setDefinition(array( + new InputOption( + 'filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'A string pattern used to match entities that should be processed.' + ), + new InputArgument( + 'dest-path', InputArgument::REQUIRED, 'The path to generate your entity classes.' + ), + new InputOption( + 'generate-annotations', null, InputOption::VALUE_OPTIONAL, + 'Flag to define if generator should generate annotation metadata on entities.', false + ), + new InputOption( + 'generate-methods', null, InputOption::VALUE_OPTIONAL, + 'Flag to define if generator should generate stub methods on entities.', true + ), + new InputOption( + 'regenerate-entities', null, InputOption::VALUE_OPTIONAL, + 'Flag to define if generator should regenerate entity if it exists.', false + ), + new InputOption( + 'update-entities', null, InputOption::VALUE_OPTIONAL, + 'Flag to define if generator should only update entity if it exists.', true + ), + new InputOption( + 'extend', null, InputOption::VALUE_OPTIONAL, + 'Defines a base class to be extended by generated entity classes.' + ), + new InputOption( + 'num-spaces', null, InputOption::VALUE_OPTIONAL, + 'Defines the number of indentation spaces', 4 + ) + )) + ->setHelp(<<--update-entities or --regenerate-entities flags your existing +code gets overwritten. The EntityGenerator will only append new code to your +file and will not delete the old code. However this approach may still be prone +to error and we suggest you use code repositories such as GIT or SVN to make +backups of your code. + +It makes sense to generate the entity code if you are using entities as Data +Access Objects only and dont put much additional logic on them. If you are +however putting much more logic on the entities you should refrain from using +the entity-generator and code your entities manually. + +Important: Even if you specified Inheritance options in your +XML or YAML Mapping files the generator cannot generate the base and +child classes for you correctly, because it doesn't know which +class is supposed to extend which. You have to adjust the entity +code manually for inheritance to work! +EOT + ); + } + + /** + * @see Console\Command\Command + */ + protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output) + { + $em = $this->getHelper('em')->getEntityManager(); + + $cmf = new DisconnectedClassMetadataFactory(); + $cmf->setEntityManager($em); + $metadatas = $cmf->getAllMetadata(); + $metadatas = MetadataFilter::filter($metadatas, $input->getOption('filter')); + + // Process destination directory + $destPath = realpath($input->getArgument('dest-path')); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Entities destination directory '%s' does not exist.", $input->getArgument('dest-path')) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Entities destination directory '%s' does not have write permissions.", $destPath) + ); + } + + if (count($metadatas)) { + // Create EntityGenerator + $entityGenerator = new EntityGenerator(); + + $entityGenerator->setGenerateAnnotations($input->getOption('generate-annotations')); + $entityGenerator->setGenerateStubMethods($input->getOption('generate-methods')); + $entityGenerator->setRegenerateEntityIfExists($input->getOption('regenerate-entities')); + $entityGenerator->setUpdateEntityIfExists($input->getOption('update-entities')); + $entityGenerator->setNumSpaces($input->getOption('num-spaces')); + + if (($extend = $input->getOption('extend')) !== null) { + $entityGenerator->setClassToExtend($extend); + } + + foreach ($metadatas as $metadata) { + $output->write( + sprintf('Processing entity "%s"', $metadata->name) . PHP_EOL + ); + } + + // Generating Entities + $entityGenerator->generate($metadatas, $destPath); + + // Outputting information message + $output->write(PHP_EOL . sprintf('Entity classes generated to "%s"', $destPath) . PHP_EOL); + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php new file mode 100644 index 0000000..2a7de9d --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php @@ -0,0 +1,112 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console, + Doctrine\ORM\Tools\Console\MetadataFilter; + +/** + * Command to (re)generate the proxy classes used by doctrine. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GenerateProxiesCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:generate-proxies') + ->setDescription('Generates proxy classes for entity classes.') + ->setDefinition(array( + new InputOption( + 'filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'A string pattern used to match entities that should be processed.' + ), + new InputArgument( + 'dest-path', InputArgument::OPTIONAL, + 'The path to generate your proxy classes. If none is provided, it will attempt to grab from configuration.' + ), + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + $metadatas = $em->getMetadataFactory()->getAllMetadata(); + $metadatas = MetadataFilter::filter($metadatas, $input->getOption('filter')); + + // Process destination directory + if (($destPath = $input->getArgument('dest-path')) === null) { + $destPath = $em->getConfiguration()->getProxyDir(); + } + + if ( ! is_dir($destPath)) { + mkdir($destPath, 0777, true); + } + + $destPath = realpath($destPath); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Proxies destination directory '%s' does not exist.", $em->getConfiguration()->getProxyDir()) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Proxies destination directory '%s' does not have write permissions.", $destPath) + ); + } + + if ( count($metadatas)) { + foreach ($metadatas as $metadata) { + $output->write( + sprintf('Processing entity "%s"', $metadata->name) . PHP_EOL + ); + } + + // Generating Proxies + $em->getProxyFactory()->generateProxyClasses($metadatas, $destPath); + + // Outputting information message + $output->write(PHP_EOL . sprintf('Proxy classes generated to "%s"', $destPath) . PHP_EOL); + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php new file mode 100644 index 0000000..b716aee --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php @@ -0,0 +1,113 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console, + Doctrine\ORM\Tools\Console\MetadataFilter, + Doctrine\ORM\Tools\EntityRepositoryGenerator; + +/** + * Command to generate repository classes for mapping information. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class GenerateRepositoriesCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:generate-repositories') + ->setDescription('Generate repository classes from your mapping information.') + ->setDefinition(array( + new InputOption( + 'filter', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'A string pattern used to match entities that should be processed.' + ), + new InputArgument( + 'dest-path', InputArgument::REQUIRED, 'The path to generate your repository classes.' + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + $metadatas = $em->getMetadataFactory()->getAllMetadata(); + $metadatas = MetadataFilter::filter($metadatas, $input->getOption('filter')); + + // Process destination directory + $destPath = realpath($input->getArgument('dest-path')); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Entities destination directory '%s' does not exist.", $input->getArgument('dest-path')) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Entities destination directory '%s' does not have write permissions.", $destPath) + ); + } + + if (count($metadatas)) { + $numRepositories = 0; + $generator = new EntityRepositoryGenerator(); + + foreach ($metadatas as $metadata) { + if ($metadata->customRepositoryClassName) { + $output->write( + sprintf('Processing repository "%s"', $metadata->customRepositoryClassName) . PHP_EOL + ); + + $generator->writeEntityRepositoryClass($metadata->customRepositoryClassName, $destPath); + + $numRepositories++; + } + } + + if ($numRepositories) { + // Outputting information message + $output->write(PHP_EOL . sprintf('Repository classes generated to "%s"', $destPath) . PHP_EOL); + } else { + $output->write('No Repository classes were found to be processed.' . PHP_EOL); + } + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/InfoCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/InfoCommand.php new file mode 100644 index 0000000..b0902ba --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/InfoCommand.php @@ -0,0 +1,79 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Doctrine\ORM\Mapping\MappingException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Command\Command; + +/** + * Show information about mapped entities + * + * + * @link www.doctrine-project.org + * @since 2.1 + * @author Benjamin Eberlei + */ +class InfoCommand extends Command +{ + protected function configure() + { + $this + ->setName('orm:info') + ->setDescription('Show basic information about all mapped entities') + ->setHelp(<<%command.name% shows basic information about which +entities exist and possibly if their mapping information contains errors or +not. +EOT + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + /* @var $entityManager \Doctrine\ORM\EntityManager */ + $entityManager = $this->getHelper('em')->getEntityManager(); + + $entityClassNames = $entityManager->getConfiguration() + ->getMetadataDriverImpl() + ->getAllClassNames(); + + if (!$entityClassNames) { + throw new \Exception( + 'You do not have any mapped Doctrine ORM entities according to the current configuration. '. + 'If you have entities or mapping files you should check your mapping configuration for errors.' + ); + } + + $output->writeln(sprintf("Found %d mapped entities:", count($entityClassNames))); + + foreach ($entityClassNames as $entityClassName) { + try { + $entityManager->getClassMetadata($entityClassName); + $output->writeln(sprintf("[OK] %s", $entityClassName)); + } catch (MappingException $e) { + $output->writeln("[FAIL] ".$entityClassName); + $output->writeln(sprintf("%s", $e->getMessage())); + $output->writeln(''); + } + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php new file mode 100644 index 0000000..c9af93f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php @@ -0,0 +1,121 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console; + +/** + * Command to execute DQL queries in a given EntityManager. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class RunDqlCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:run-dql') + ->setDescription('Executes arbitrary DQL directly from the command line.') + ->setDefinition(array( + new InputArgument('dql', InputArgument::REQUIRED, 'The DQL to execute.'), + new InputOption( + 'hydrate', null, InputOption::VALUE_REQUIRED, + 'Hydration mode of result set. Should be either: object, array, scalar or single-scalar.', + 'object' + ), + new InputOption( + 'first-result', null, InputOption::VALUE_REQUIRED, + 'The first result in the result set.' + ), + new InputOption( + 'max-result', null, InputOption::VALUE_REQUIRED, + 'The maximum number of results in the result set.' + ), + new InputOption( + 'depth', null, InputOption::VALUE_REQUIRED, + 'Dumping depth of Entity graph.', 7 + ) + )) + ->setHelp(<<getHelper('em')->getEntityManager(); + + if (($dql = $input->getArgument('dql')) === null) { + throw new \RuntimeException("Argument 'DQL' is required in order to execute this command correctly."); + } + + $depth = $input->getOption('depth'); + + if ( ! is_numeric($depth)) { + throw new \LogicException("Option 'depth' must contains an integer value"); + } + + $hydrationModeName = $input->getOption('hydrate'); + $hydrationMode = 'Doctrine\ORM\Query::HYDRATE_' . strtoupper(str_replace('-', '_', $hydrationModeName)); + + if ( ! defined($hydrationMode)) { + throw new \RuntimeException( + "Hydration mode '$hydrationModeName' does not exist. It should be either: object. array, scalar or single-scalar." + ); + } + + $query = $em->createQuery($dql); + + if (($firstResult = $input->getOption('first-result')) !== null) { + if ( ! is_numeric($firstResult)) { + throw new \LogicException("Option 'first-result' must contains an integer value"); + } + + $query->setFirstResult((int) $firstResult); + } + + if (($maxResult = $input->getOption('max-result')) !== null) { + if ( ! is_numeric($maxResult)) { + throw new \LogicException("Option 'max-result' must contains an integer value"); + } + + $query->setMaxResults((int) $maxResult); + } + + $resultSet = $query->execute(array(), constant($hydrationMode)); + + \Doctrine\Common\Util\Debug::dump($resultSet, $input->getOption('depth')); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/AbstractCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/AbstractCommand.php new file mode 100644 index 0000000..a87eb20 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/AbstractCommand.php @@ -0,0 +1,58 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; + +use Symfony\Component\Console\Input\InputInterface, + Symfony\Component\Console\Output\OutputInterface, + Symfony\Component\Console\Command\Command, + Doctrine\ORM\Tools\SchemaTool; + +abstract class AbstractCommand extends Command +{ + /** + * @param InputInterface $input + * @param OutputInterface $output + * @param SchemaTool $schemaTool + * @param array $metadatas + */ + abstract protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas); + + /** + * @see Console\Command\Command + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $emHelper = $this->getHelper('em'); + + /* @var $em \Doctrine\ORM\EntityManager */ + $em = $emHelper->getEntityManager(); + + $metadatas = $em->getMetadataFactory()->getAllMetadata(); + + if ( ! empty($metadatas)) { + // Create SchemaTool + $tool = new \Doctrine\ORM\Tools\SchemaTool($em); + + $this->executeSchemaCommand($input, $output, $tool, $metadatas); + } else { + $output->write('No Metadata Classes to process.' . PHP_EOL); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php new file mode 100644 index 0000000..69d3f36 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/CreateCommand.php @@ -0,0 +1,76 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console\Input\InputInterface, + Symfony\Component\Console\Output\OutputInterface, + Doctrine\ORM\Tools\SchemaTool; + +/** + * Command to create the database schema for a set of classes based on their mappings. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class CreateCommand extends AbstractCommand +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:schema-tool:create') + ->setDescription( + 'Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output.' + ) + ->setDefinition(array( + new InputOption( + 'dump-sql', null, InputOption::VALUE_NONE, + 'Instead of try to apply generated SQLs into EntityManager Storage Connection, output them.' + ) + )) + ->setHelp(<<getOption('dump-sql') === true) { + $sqls = $schemaTool->getCreateSchemaSql($metadatas); + $output->write(implode(';' . PHP_EOL, $sqls) . ';' . PHP_EOL); + } else { + $output->write('ATTENTION: This operation should not be executed in a production environment.' . PHP_EOL . PHP_EOL); + + $output->write('Creating database schema...' . PHP_EOL); + $schemaTool->createSchema($metadatas); + $output->write('Database schema created successfully!' . PHP_EOL); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php new file mode 100644 index 0000000..50fa645 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/DropCommand.php @@ -0,0 +1,108 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console\Input\InputInterface, + Symfony\Component\Console\Output\OutputInterface, + Doctrine\ORM\Tools\SchemaTool; + +/** + * Command to drop the database schema for a set of classes based on their mappings. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class DropCommand extends AbstractCommand +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:schema-tool:drop') + ->setDescription( + 'Drop the complete database schema of EntityManager Storage Connection or generate the corresponding SQL output.' + ) + ->setDefinition(array( + new InputOption( + 'dump-sql', null, InputOption::VALUE_NONE, + 'Instead of try to apply generated SQLs into EntityManager Storage Connection, output them.' + ), + new InputOption( + 'force', null, InputOption::VALUE_NONE, + "Don't ask for the deletion of the database, but force the operation to run." + ), + new InputOption( + 'full-database', null, InputOption::VALUE_NONE, + 'Instead of using the Class Metadata to detect the database table schema, drop ALL assets that the database contains.' + ), + )) + ->setHelp(<<getOption('full-database')); + + if ($input->getOption('dump-sql') === true) { + if ($isFullDatabaseDrop) { + $sqls = $schemaTool->getDropDatabaseSQL(); + } else { + $sqls = $schemaTool->getDropSchemaSQL($metadatas); + } + $output->write(implode(';' . PHP_EOL, $sqls) . PHP_EOL); + } else if ($input->getOption('force') === true) { + $output->write('Dropping database schema...' . PHP_EOL); + if ($isFullDatabaseDrop) { + $schemaTool->dropDatabase(); + } else { + $schemaTool->dropSchema($metadatas); + } + $output->write('Database schema dropped successfully!' . PHP_EOL); + } else { + $output->write('ATTENTION: This operation should not be executed in a production environment.' . PHP_EOL . PHP_EOL); + + if ($isFullDatabaseDrop) { + $sqls = $schemaTool->getDropDatabaseSQL(); + } else { + $sqls = $schemaTool->getDropSchemaSQL($metadatas); + } + + if (count($sqls)) { + $output->write('Schema-Tool would execute ' . count($sqls) . ' queries to drop the database.' . PHP_EOL); + $output->write('Please run the operation with --force to execute these queries or use --dump-sql to see them.' . PHP_EOL); + } else { + $output->write('Nothing to drop. The database is empty!' . PHP_EOL); + } + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php new file mode 100644 index 0000000..26552cc --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php @@ -0,0 +1,131 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command\SchemaTool; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console\Input\InputInterface, + Symfony\Component\Console\Output\OutputInterface, + Doctrine\ORM\Tools\SchemaTool; + +/** + * Command to generate the SQL needed to update the database schema to match + * the current mapping information. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Ryan Weaver + */ +class UpdateCommand extends AbstractCommand +{ + protected $name = 'orm:schema-tool:update'; + + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName($this->name) + ->setDescription( + 'Executes (or dumps) the SQL needed to update the database schema to match the current mapping metadata.' + ) + ->setDefinition(array( + new InputOption( + 'complete', null, InputOption::VALUE_NONE, + 'If defined, all assets of the database which are not relevant to the current metadata will be dropped.' + ), + + new InputOption( + 'dump-sql', null, InputOption::VALUE_NONE, + 'Dumps the generated SQL statements to the screen (does not execute them).' + ), + new InputOption( + 'force', null, InputOption::VALUE_NONE, + 'Causes the generated SQL statements to be physically executed against your database.' + ), + )); + + $this->setHelp(<<%command.name% command generates the SQL needed to +synchronize the database schema with the current mapping metadata of the +default entity manager. + +For example, if you add metadata for a new column to an entity, this command +would generate and output the SQL needed to add the new column to the database: + +%command.name% --dump-sql + +Alternatively, you can execute the generated queries: + +%command.name% --force + +Finally, be aware that if the --complete option is passed, this +task will drop all database assets (e.g. tables, etc) that are *not* described +by the current metadata. In other words, without this option, this task leaves +untouched any "extra" tables that exist in the database, but which aren't +described by any metadata. +EOT + ); + } + + protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas) + { + // Defining if update is complete or not (--complete not defined means $saveMode = true) + $saveMode = ($input->getOption('complete') !== true); + + $sqls = $schemaTool->getUpdateSchemaSql($metadatas, $saveMode); + if (0 == count($sqls)) { + $output->writeln('Nothing to update - your database is already in sync with the current entity metadata.'); + + return; + } + + $dumpSql = (true === $input->getOption('dump-sql')); + $force = (true === $input->getOption('force')); + if ($dumpSql && $force) { + throw new \InvalidArgumentException('You can pass either the --dump-sql or the --force option (but not both simultaneously).'); + } + + if ($dumpSql) { + $output->writeln(implode(';' . PHP_EOL, $sqls)); + } else if ($force) { + $output->writeln('Updating database schema...'); + $schemaTool->updateSchema($metadatas, $saveMode); + $output->writeln(sprintf('Database schema updated successfully! "%s" queries were executed', count($sqls))); + } else { + $output->writeln('ATTENTION: This operation should not be executed in a production environment.'); + $output->writeln(' Use the incremental update to detect changes during development and use'); + $output->writeln(' the SQL DDL provided to manually update your database in production.'); + $output->writeln(''); + + $output->writeln(sprintf('The Schema-Tool would execute "%s" queries to update the database.', count($sqls))); + $output->writeln('Please run the operation by passing one of the following options:'); + + $output->writeln(sprintf(' %s --force to execute the command', $this->getName())); + $output->writeln(sprintf(' %s --dump-sql to dump the SQL statements to the screen', $this->getName())); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php new file mode 100644 index 0000000..3dbc54f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php @@ -0,0 +1,86 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Command; + +use Symfony\Component\Console\Input\InputArgument, + Symfony\Component\Console\Input\InputOption, + Symfony\Component\Console; + +/** + * Validate that the current mapping is valid + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ValidateSchemaCommand extends Console\Command\Command +{ + /** + * @see Console\Command\Command + */ + protected function configure() + { + $this + ->setName('orm:validate-schema') + ->setDescription('Validate the mapping files.') + ->setHelp(<<getHelper('em')->getEntityManager(); + + $validator = new \Doctrine\ORM\Tools\SchemaValidator($em); + $errors = $validator->validateMapping(); + + $exit = 0; + if ($errors) { + foreach ($errors as $className => $errorMessages) { + $output->write("[Mapping] FAIL - The entity-class '" . $className . "' mapping is invalid:\n"); + foreach ($errorMessages as $errorMessage) { + $output->write('* ' . $errorMessage . "\n"); + } + $output->write("\n"); + } + $exit += 1; + } else { + $output->write('[Mapping] OK - The mapping files are correct.' . "\n"); + } + + if (!$validator->schemaInSyncWithMetadata()) { + $output->write('[Database] FAIL - The database schema is not in sync with the current mapping file.' . "\n"); + $exit += 2; + } else { + $output->write('[Database] OK - The database schema is in sync with the mapping files.' . "\n"); + } + + return $exit; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php new file mode 100644 index 0000000..e8bc6ec --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php @@ -0,0 +1,72 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Helper\HelperSet; + +class ConsoleRunner +{ + /** + * Run console with the given helperset. + * + * @param \Symfony\Component\Console\Helper\HelperSet $helperSet + * @param \Symfony\Component\Console\Command\Command[] $commands + * @return void + */ + static public function run(HelperSet $helperSet, $commands = array()) + { + $cli = new Application('Doctrine Command Line Interface', \Doctrine\ORM\Version::VERSION); + $cli->setCatchExceptions(true); + $cli->setHelperSet($helperSet); + self::addCommands($cli); + $cli->addCommands($commands); + $cli->run(); + } + + /** + * @param Application $cli + */ + static public function addCommands(Application $cli) + { + $cli->addCommands(array( + // DBAL Commands + new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(), + new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(), + + // ORM Commands + new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(), + new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(), + new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(), + new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(), + new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(), + new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(), + new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(), + new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(), + new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(), + new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(), + new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(), + new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(), + new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(), + new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(), + new \Doctrine\ORM\Tools\Console\Command\InfoCommand() + )); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php new file mode 100644 index 0000000..a5da041 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php @@ -0,0 +1,71 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console\Helper; + +use Symfony\Component\Console\Helper\Helper, + Doctrine\ORM\EntityManager; + +/** + * Doctrine CLI Connection Helper. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EntityManagerHelper extends Helper +{ + /** + * Doctrine ORM EntityManager + * @var EntityManager + */ + protected $_em; + + /** + * Constructor + * + * @param Connection $connection Doctrine Database Connection + */ + public function __construct(EntityManager $em) + { + $this->_em = $em; + } + + /** + * Retrieves Doctrine ORM EntityManager + * + * @return EntityManager + */ + public function getEntityManager() + { + return $this->_em; + } + + /** + * @see Helper + */ + public function getName() + { + return 'entityManager'; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/MetadataFilter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/MetadataFilter.php new file mode 100644 index 0000000..72c753e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/MetadataFilter.php @@ -0,0 +1,77 @@ +. + */ + +namespace Doctrine\ORM\Tools\Console; + +/** + * Used by CLI Tools to restrict entity-based commands to given patterns. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class MetadataFilter extends \FilterIterator implements \Countable +{ + /** + * Filter Metadatas by one or more filter options. + * + * @param array $metadatas + * @param array|string $filter + * @return array + */ + static public function filter(array $metadatas, $filter) + { + $metadatas = new MetadataFilter(new \ArrayIterator($metadatas), $filter); + return iterator_to_array($metadatas); + } + + private $_filter = array(); + + public function __construct(\ArrayIterator $metadata, $filter) + { + $this->_filter = (array)$filter; + parent::__construct($metadata); + } + + public function accept() + { + if (count($this->_filter) == 0) { + return true; + } + + $it = $this->getInnerIterator(); + $metadata = $it->current(); + + foreach ($this->_filter as $filter) { + if (strpos($metadata->name, $filter) !== false) { + return true; + } + } + return false; + } + + public function count() + { + return count($this->getInnerIterator()); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php new file mode 100644 index 0000000..46f358a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php @@ -0,0 +1,271 @@ +. + */ + +namespace Doctrine\ORM\Tools; + +use Doctrine\ORM\Mapping\ClassMetadataInfo, + Doctrine\ORM\Tools\Export\Driver\AbstractExporter, + Doctrine\Common\Util\Inflector; + +/** + * Class to help with converting Doctrine 1 schema files to Doctrine 2 mapping files + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class ConvertDoctrine1Schema +{ + private $_legacyTypeMap = array( + // TODO: This list may need to be updated + 'clob' => 'text', + 'timestamp' => 'datetime', + 'enum' => 'string' + ); + + /** + * Constructor passes the directory or array of directories + * to convert the Doctrine 1 schema files from + * + * @param array $from + * @author Jonathan Wage + */ + public function __construct($from) + { + $this->_from = (array) $from; + } + + /** + * Get an array of ClassMetadataInfo instances from the passed + * Doctrine 1 schema + * + * @return array $metadatas An array of ClassMetadataInfo instances + */ + public function getMetadata() + { + $schema = array(); + foreach ($this->_from as $path) { + if (is_dir($path)) { + $files = glob($path . '/*.yml'); + foreach ($files as $file) { + $schema = array_merge($schema, (array) \Symfony\Component\Yaml\Yaml::parse($file)); + } + } else { + $schema = array_merge($schema, (array) \Symfony\Component\Yaml\Yaml::parse($path)); + } + } + + $metadatas = array(); + foreach ($schema as $className => $mappingInformation) { + $metadatas[] = $this->_convertToClassMetadataInfo($className, $mappingInformation); + } + + return $metadatas; + } + + private function _convertToClassMetadataInfo($className, $mappingInformation) + { + $metadata = new ClassMetadataInfo($className); + + $this->_convertTableName($className, $mappingInformation, $metadata); + $this->_convertColumns($className, $mappingInformation, $metadata); + $this->_convertIndexes($className, $mappingInformation, $metadata); + $this->_convertRelations($className, $mappingInformation, $metadata); + + return $metadata; + } + + private function _convertTableName($className, array $model, ClassMetadataInfo $metadata) + { + if (isset($model['tableName']) && $model['tableName']) { + $e = explode('.', $model['tableName']); + + if (count($e) > 1) { + $metadata->table['schema'] = $e[0]; + $metadata->table['name'] = $e[1]; + } else { + $metadata->table['name'] = $e[0]; + } + } + } + + private function _convertColumns($className, array $model, ClassMetadataInfo $metadata) + { + $id = false; + + if (isset($model['columns']) && $model['columns']) { + foreach ($model['columns'] as $name => $column) { + $fieldMapping = $this->_convertColumn($className, $name, $column, $metadata); + + if (isset($fieldMapping['id']) && $fieldMapping['id']) { + $id = true; + } + } + } + + if ( ! $id) { + $fieldMapping = array( + 'fieldName' => 'id', + 'columnName' => 'id', + 'type' => 'integer', + 'id' => true + ); + $metadata->mapField($fieldMapping); + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); + } + } + + private function _convertColumn($className, $name, $column, ClassMetadataInfo $metadata) + { + if (is_string($column)) { + $string = $column; + $column = array(); + $column['type'] = $string; + } + if ( ! isset($column['name'])) { + $column['name'] = $name; + } + // check if a column alias was used (column_name as field_name) + if (preg_match("/(\w+)\sas\s(\w+)/i", $column['name'], $matches)) { + $name = $matches[1]; + $column['name'] = $name; + $column['alias'] = $matches[2]; + } + if (preg_match("/([a-zA-Z]+)\(([0-9]+)\)/", $column['type'], $matches)) { + $column['type'] = $matches[1]; + $column['length'] = $matches[2]; + } + $column['type'] = strtolower($column['type']); + // check if legacy column type (1.x) needs to be mapped to a 2.0 one + if (isset($this->_legacyTypeMap[$column['type']])) { + $column['type'] = $this->_legacyTypeMap[$column['type']]; + } + if ( ! \Doctrine\DBAL\Types\Type::hasType($column['type'])) { + throw ToolsException::couldNotMapDoctrine1Type($column['type']); + } + + $fieldMapping = array(); + if (isset($column['primary'])) { + $fieldMapping['id'] = true; + } + $fieldMapping['fieldName'] = isset($column['alias']) ? $column['alias'] : $name; + $fieldMapping['columnName'] = $column['name']; + $fieldMapping['type'] = $column['type']; + if (isset($column['length'])) { + $fieldMapping['length'] = $column['length']; + } + $allowed = array('precision', 'scale', 'unique', 'options', 'notnull', 'version'); + foreach ($column as $key => $value) { + if (in_array($key, $allowed)) { + $fieldMapping[$key] = $value; + } + } + + $metadata->mapField($fieldMapping); + + if (isset($column['autoincrement'])) { + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); + } else if (isset($column['sequence'])) { + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE); + $definition = array( + 'sequenceName' => is_array($column['sequence']) ? $column['sequence']['name']:$column['sequence'] + ); + if (isset($column['sequence']['size'])) { + $definition['allocationSize'] = $column['sequence']['size']; + } + if (isset($column['sequence']['value'])) { + $definition['initialValue'] = $column['sequence']['value']; + } + $metadata->setSequenceGeneratorDefinition($definition); + } + return $fieldMapping; + } + + private function _convertIndexes($className, array $model, ClassMetadataInfo $metadata) + { + if (isset($model['indexes']) && $model['indexes']) { + foreach ($model['indexes'] as $name => $index) { + $type = (isset($index['type']) && $index['type'] == 'unique') + ? 'uniqueConstraints' : 'indexes'; + + $metadata->table[$type][$name] = array( + 'columns' => $index['fields'] + ); + } + } + } + + private function _convertRelations($className, array $model, ClassMetadataInfo $metadata) + { + if (isset($model['relations']) && $model['relations']) { + foreach ($model['relations'] as $name => $relation) { + if ( ! isset($relation['alias'])) { + $relation['alias'] = $name; + } + if ( ! isset($relation['class'])) { + $relation['class'] = $name; + } + if ( ! isset($relation['local'])) { + $relation['local'] = Inflector::tableize($relation['class']); + } + if ( ! isset($relation['foreign'])) { + $relation['foreign'] = 'id'; + } + if ( ! isset($relation['foreignAlias'])) { + $relation['foreignAlias'] = $className; + } + + if (isset($relation['refClass'])) { + $type = 'many'; + $foreignType = 'many'; + $joinColumns = array(); + } else { + $type = isset($relation['type']) ? $relation['type'] : 'one'; + $foreignType = isset($relation['foreignType']) ? $relation['foreignType'] : 'many'; + $joinColumns = array( + array( + 'name' => $relation['local'], + 'referencedColumnName' => $relation['foreign'], + 'onDelete' => isset($relation['onDelete']) ? $relation['onDelete'] : null, + ) + ); + } + + if ($type == 'one' && $foreignType == 'one') { + $method = 'mapOneToOne'; + } else if ($type == 'many' && $foreignType == 'many') { + $method = 'mapManyToMany'; + } else { + $method = 'mapOneToMany'; + } + + $associationMapping = array(); + $associationMapping['fieldName'] = $relation['alias']; + $associationMapping['targetEntity'] = $relation['class']; + $associationMapping['mappedBy'] = $relation['foreignAlias']; + $associationMapping['joinColumns'] = $joinColumns; + + $metadata->$method($associationMapping); + } + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/DebugUnitOfWorkListener.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/DebugUnitOfWorkListener.php new file mode 100644 index 0000000..c2bb0fd --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/DebugUnitOfWorkListener.php @@ -0,0 +1,151 @@ +. + */ + +namespace Doctrine\ORM\Tools; + +use Doctrine\ORM\Event\OnFlushEventArgs; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\PersistentCollection; +use Doctrine\ORM\UnitOfWork; + +/** + * Use this logger to dump the identity map during the onFlush event. This is useful for debugging + * weird UnitOfWork behavior with complex operations. + */ +class DebugUnitOfWorkListener +{ + private $file; + private $context; + + /** + * Pass a stream and contet information for the debugging session. + * + * The stream can be php://output to print to the screen. + * + * @param string $file + * @param string $context + */ + public function __construct($file = 'php://output', $context = '') + { + $this->file = $file; + $this->context = $context; + } + + public function onFlush(OnFlushEventArgs $args) + { + $this->dumpIdentityMap($args->getEntityManager()); + } + + /** + * Dump the contents of the identity map into a stream. + * + * @param EntityManager $em + * @return void + */ + public function dumpIdentityMap(EntityManager $em) + { + $uow = $em->getUnitOfWork(); + $identityMap = $uow->getIdentityMap(); + + $fh = fopen($this->file, "x+"); + if (count($identityMap) == 0) { + fwrite($fh, "Flush Operation [".$this->context."] - Empty identity map.\n"); + return; + } + + fwrite($fh, "Flush Operation [".$this->context."] - Dumping identity map:\n"); + foreach ($identityMap as $className => $map) { + fwrite($fh, "Class: ". $className . "\n"); + foreach ($map as $entity) { + fwrite($fh, " Entity: " . $this->getIdString($entity, $uow) . " " . spl_object_hash($entity)."\n"); + fwrite($fh, " Associations:\n"); + + $cm = $em->getClassMetadata($className); + foreach ($cm->associationMappings as $field => $assoc) { + fwrite($fh, " " . $field . " "); + $value = $cm->reflFields[$field]->getValue($entity); + + if ($assoc['type'] & ClassMetadata::TO_ONE) { + if ($value === null) { + fwrite($fh, " NULL\n"); + } else { + if ($value instanceof Proxy && !$value->__isInitialized__) { + fwrite($fh, "[PROXY] "); + } + + fwrite($fh, $this->getIdString($value, $uow) . " " . spl_object_hash($value) . "\n"); + } + } else { + $initialized = !($value instanceof PersistentCollection) || $value->isInitialized(); + if ($value === null) { + fwrite($fh, " NULL\n"); + } else if ($initialized) { + fwrite($fh, "[INITIALIZED] " . $this->getType($value). " " . count($value) . " elements\n"); + foreach ($value as $obj) { + fwrite($fh, " " . $this->getIdString($obj, $uow) . " " . spl_object_hash($obj)."\n"); + } + } else { + fwrite($fh, "[PROXY] " . $this->getType($value) . " unknown element size\n"); + foreach ($value->unwrap() as $obj) { + fwrite($fh, " " . $this->getIdString($obj, $uow) . " " . spl_object_hash($obj)."\n"); + } + } + } + } + } + } + fclose($fh); + } + + private function getType($var) + { + if (is_object($var)) { + $refl = new \ReflectionObject($var); + return $refl->getShortname(); + } else { + return gettype($var); + } + } + + private function getIdString($entity, $uow) + { + if ($uow->isInIdentityMap($entity)) { + $ids = $uow->getEntityIdentifier($entity); + $idstring = ""; + foreach ($ids as $k => $v) { + $idstring .= $k."=".$v; + } + } else { + $idstring = "NEWOBJECT "; + } + + $state = $uow->getEntityState($entity); + if ($state == UnitOfWork::STATE_NEW) { + $idstring .= " [NEW]"; + } else if ($state == UnitOfWork::STATE_REMOVED) { + $idstring .= " [REMOVED]"; + } else if ($state == UnitOfWork::STATE_MANAGED) { + $idstring .= " [MANAGED]"; + } else if ($state == UnitOfwork::STATE_DETACHED) { + $idstring .= " [DETACHED]"; + } + + return $idstring; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/DisconnectedClassMetadataFactory.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/DisconnectedClassMetadataFactory.php new file mode 100644 index 0000000..e44f99f --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/DisconnectedClassMetadataFactory.php @@ -0,0 +1,45 @@ +. + */ + +namespace Doctrine\ORM\Tools; + +use Doctrine\ORM\Mapping\ClassMetadataFactory; +use Doctrine\ORM\Mapping\ClassMetadataInfo; + +/** + * The DisconnectedClassMetadataFactory is used to create ClassMetadataInfo objects + * that do not require the entity class actually exist. This allows us to + * load some mapping information and use it to do things like generate code + * from the mapping information. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class DisconnectedClassMetadataFactory extends ClassMetadataFactory +{ + public function getReflectionService() + { + return new \Doctrine\Common\Persistence\Mapping\StaticReflectionService; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/EntityGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/EntityGenerator.php new file mode 100644 index 0000000..3e20ee5 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/EntityGenerator.php @@ -0,0 +1,1265 @@ +. + */ + +namespace Doctrine\ORM\Tools; + +use Doctrine\ORM\Mapping\ClassMetadataInfo, + Doctrine\Common\Util\Inflector, + Doctrine\DBAL\Types\Type; + +/** + * Generic class used to generate PHP5 entity classes from ClassMetadataInfo instances + * + * [php] + * $classes = $em->getClassMetadataFactory()->getAllMetadata(); + * + * $generator = new \Doctrine\ORM\Tools\EntityGenerator(); + * $generator->setGenerateAnnotations(true); + * $generator->setGenerateStubMethods(true); + * $generator->setRegenerateEntityIfExists(false); + * $generator->setUpdateEntityIfExists(true); + * $generator->generate($classes, '/path/to/generate/entities'); + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EntityGenerator +{ + /** + * Specifies class fields should be protected + */ + const FIELD_VISIBLE_PROTECTED = 'protected'; + + /** + * Specifies class fields should be private + */ + const FIELD_VISIBLE_PRIVATE = 'private'; + + /** + * @var bool + */ + private $backupExisting = true; + + /** + * The extension to use for written php files + * + * @var string + */ + private $extension = '.php'; + + /** + * Whether or not the current ClassMetadataInfo instance is new or old + * + * @var boolean + */ + private $isNew = true; + + /** + * @var array + */ + private $staticReflection = array(); + + /** + * Number of spaces to use for indention in generated code + */ + private $numSpaces = 4; + + /** + * The actual spaces to use for indention + * + * @var string + */ + private $spaces = ' '; + + /** + * The class all generated entities should extend + * + * @var string + */ + private $classToExtend; + + /** + * Whether or not to generation annotations + * + * @var boolean + */ + private $generateAnnotations = false; + + /** + * @var string + */ + private $annotationsPrefix = ''; + + /** + * Whether or not to generated sub methods + * + * @var boolean + */ + private $generateEntityStubMethods = false; + + /** + * Whether or not to update the entity class if it exists already + * + * @var boolean + */ + private $updateEntityIfExists = false; + + /** + * Whether or not to re-generate entity class if it exists already + * + * @var boolean + */ + private $regenerateEntityIfExists = false; + + /** + * @var boolean + */ + private $fieldVisibility = 'private'; + + /** + * Hash-map for handle types + * + * @var array + */ + private $typeAlias = array( + Type::DATETIMETZ => '\DateTime', + Type::DATETIME => '\DateTime', + Type::DATE => '\DateTime', + Type::TIME => '\DateTime', + Type::OBJECT => '\stdClass', + Type::BIGINT => 'integer', + Type::SMALLINT => 'integer', + Type::TEXT => 'string', + Type::BLOB => 'string', + Type::DECIMAL => 'float', + Type::JSON_ARRAY => 'array', + Type::SIMPLE_ARRAY => 'array', + ); + + /** + * @var string + */ + private static $classTemplate = +' + +use Doctrine\ORM\Mapping as ORM; + + + +{ + +} +'; + + /** + * @var string + */ + private static $getMethodTemplate = +'/** + * + * + * @return + */ +public function () +{ +return $this->; +}'; + + /** + * @var string + */ + private static $setMethodTemplate = +'/** + * + * + * @param $ + * @return + */ +public function ($) +{ +$this-> = $; + +return $this; +}'; + + /** + * @var string + */ + private static $addMethodTemplate = +'/** + * + * + * @param $ + * @return + */ +public function ($) +{ +$this->[] = $; + +return $this; +}'; + + /** + * @var string + */ + private static $removeMethodTemplate = +'/** + * + * + * @param $ + */ +public function ($) +{ +$this->->removeElement($); +}'; + + /** + * @var string + */ + private static $lifecycleCallbackMethodTemplate = +'/** + * @ + */ +public function () +{ +// Add your code here +}'; + + /** + * @var string + */ + private static $constructorMethodTemplate = +'/** + * Constructor + */ +public function __construct() +{ + +} +'; + + public function __construct() + { + if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) { + $this->annotationsPrefix = 'ORM\\'; + } + } + + /** + * Generate and write entity classes for the given array of ClassMetadataInfo instances + * + * @param array $metadatas + * @param string $outputDirectory + * @return void + */ + public function generate(array $metadatas, $outputDirectory) + { + foreach ($metadatas as $metadata) { + $this->writeEntityClass($metadata, $outputDirectory); + } + } + + /** + * Generated and write entity class to disk for the given ClassMetadataInfo instance + * + * @param ClassMetadataInfo $metadata + * @param string $outputDirectory + * @return void + */ + public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory) + { + $path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->extension; + $dir = dirname($path); + + if ( ! is_dir($dir)) { + mkdir($dir, 0777, true); + } + + $this->isNew = !file_exists($path) || (file_exists($path) && $this->regenerateEntityIfExists); + + if ( ! $this->isNew) { + $this->parseTokensInEntityFile(file_get_contents($path)); + } else { + $this->staticReflection[$metadata->name] = array('properties' => array(), 'methods' => array()); + } + + if ($this->backupExisting && file_exists($path)) { + $backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~"; + if (!copy($path, $backupPath)) { + throw new \RuntimeException("Attempt to backup overwritten entity file but copy operation failed."); + } + } + + // If entity doesn't exist or we're re-generating the entities entirely + if ($this->isNew) { + file_put_contents($path, $this->generateEntityClass($metadata)); + // If entity exists and we're allowed to update the entity class + } else if ( ! $this->isNew && $this->updateEntityIfExists) { + file_put_contents($path, $this->generateUpdatedEntityClass($metadata, $path)); + } + } + + /** + * Generate a PHP5 Doctrine 2 entity class from the given ClassMetadataInfo instance + * + * @param ClassMetadataInfo $metadata + * @return string $code + */ + public function generateEntityClass(ClassMetadataInfo $metadata) + { + $placeHolders = array( + '', + '', + '', + '' + ); + + $replacements = array( + $this->generateEntityNamespace($metadata), + $this->generateEntityDocBlock($metadata), + $this->generateEntityClassName($metadata), + $this->generateEntityBody($metadata) + ); + + $code = str_replace($placeHolders, $replacements, self::$classTemplate); + return str_replace('', $this->spaces, $code); + } + + /** + * Generate the updated code for the given ClassMetadataInfo and entity at path + * + * @param ClassMetadataInfo $metadata + * @param string $path + * @return string $code; + */ + public function generateUpdatedEntityClass(ClassMetadataInfo $metadata, $path) + { + $currentCode = file_get_contents($path); + + $body = $this->generateEntityBody($metadata); + $body = str_replace('', $this->spaces, $body); + $last = strrpos($currentCode, '}'); + + return substr($currentCode, 0, $last) . $body . (strlen($body) > 0 ? "\n" : ''). "}"; + } + + /** + * Set the number of spaces the exported class should have + * + * @param integer $numSpaces + * @return void + */ + public function setNumSpaces($numSpaces) + { + $this->spaces = str_repeat(' ', $numSpaces); + $this->numSpaces = $numSpaces; + } + + /** + * Set the extension to use when writing php files to disk + * + * @param string $extension + * @return void + */ + public function setExtension($extension) + { + $this->extension = $extension; + } + + /** + * Set the name of the class the generated classes should extend from + * + * @return void + */ + public function setClassToExtend($classToExtend) + { + $this->classToExtend = $classToExtend; + } + + /** + * Set whether or not to generate annotations for the entity + * + * @param bool $bool + * @return void + */ + public function setGenerateAnnotations($bool) + { + $this->generateAnnotations = $bool; + } + + /** + * Set the class fields visibility for the entity (can either be private or protected) + * + * @param bool $bool + * @return void + */ + public function setFieldVisibility($visibility) + { + if ($visibility !== self::FIELD_VISIBLE_PRIVATE && $visibility !== self::FIELD_VISIBLE_PROTECTED) { + throw new \InvalidArgumentException('Invalid provided visibilty (only private and protected are allowed): ' . $visibility); + } + + $this->fieldVisibility = $visibility; + } + + /** + * Set an annotation prefix. + * + * @param string $prefix + */ + public function setAnnotationPrefix($prefix) + { + $this->annotationsPrefix = $prefix; + } + + /** + * Set whether or not to try and update the entity if it already exists + * + * @param bool $bool + * @return void + */ + public function setUpdateEntityIfExists($bool) + { + $this->updateEntityIfExists = $bool; + } + + /** + * Set whether or not to regenerate the entity if it exists + * + * @param bool $bool + * @return void + */ + public function setRegenerateEntityIfExists($bool) + { + $this->regenerateEntityIfExists = $bool; + } + + /** + * Set whether or not to generate stub methods for the entity + * + * @param bool $bool + * @return void + */ + public function setGenerateStubMethods($bool) + { + $this->generateEntityStubMethods = $bool; + } + + /** + * Should an existing entity be backed up if it already exists? + */ + public function setBackupExisting($bool) + { + $this->backupExisting = $bool; + } + + /** + * @param string $type + * @return string + */ + private function getType($type) + { + if (isset($this->typeAlias[$type])) { + return $this->typeAlias[$type]; + } + + return $type; + } + + private function generateEntityNamespace(ClassMetadataInfo $metadata) + { + if ($this->hasNamespace($metadata)) { + return 'namespace ' . $this->getNamespace($metadata) .';'; + } + } + + private function generateEntityClassName(ClassMetadataInfo $metadata) + { + return 'class ' . $this->getClassName($metadata) . + ($this->extendsClass() ? ' extends ' . $this->getClassToExtendName() : null); + } + + private function generateEntityBody(ClassMetadataInfo $metadata) + { + $fieldMappingProperties = $this->generateEntityFieldMappingProperties($metadata); + $associationMappingProperties = $this->generateEntityAssociationMappingProperties($metadata); + $stubMethods = $this->generateEntityStubMethods ? $this->generateEntityStubMethods($metadata) : null; + $lifecycleCallbackMethods = $this->generateEntityLifecycleCallbackMethods($metadata); + + $code = array(); + + if ($fieldMappingProperties) { + $code[] = $fieldMappingProperties; + } + + if ($associationMappingProperties) { + $code[] = $associationMappingProperties; + } + + $code[] = $this->generateEntityConstructor($metadata); + + if ($stubMethods) { + $code[] = $stubMethods; + } + + if ($lifecycleCallbackMethods) { + $code[] = $lifecycleCallbackMethods; + } + + return implode("\n", $code); + } + + private function generateEntityConstructor(ClassMetadataInfo $metadata) + { + if ($this->hasMethod('__construct', $metadata)) { + return ''; + } + + $collections = array(); + + foreach ($metadata->associationMappings as $mapping) { + if ($mapping['type'] & ClassMetadataInfo::TO_MANY) { + $collections[] = '$this->'.$mapping['fieldName'].' = new \Doctrine\Common\Collections\ArrayCollection();'; + } + } + + if ($collections) { + return $this->prefixCodeWithSpaces(str_replace("", implode("\n".$this->spaces, $collections), self::$constructorMethodTemplate)); + } + + return ''; + } + + /** + * @todo this won't work if there is a namespace in brackets and a class outside of it. + * @param string $src + */ + private function parseTokensInEntityFile($src) + { + $tokens = token_get_all($src); + $lastSeenNamespace = ""; + $lastSeenClass = false; + + $inNamespace = false; + $inClass = false; + for ($i = 0; $i < count($tokens); $i++) { + $token = $tokens[$i]; + if (in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT))) { + continue; + } + + if ($inNamespace) { + if ($token[0] == T_NS_SEPARATOR || $token[0] == T_STRING) { + $lastSeenNamespace .= $token[1]; + } else if (is_string($token) && in_array($token, array(';', '{'))) { + $inNamespace = false; + } + } + + if ($inClass) { + $inClass = false; + $lastSeenClass = $lastSeenNamespace . ($lastSeenNamespace ? '\\' : '') . $token[1]; + $this->staticReflection[$lastSeenClass]['properties'] = array(); + $this->staticReflection[$lastSeenClass]['methods'] = array(); + } + + if ($token[0] == T_NAMESPACE) { + $lastSeenNamespace = ""; + $inNamespace = true; + } else if ($token[0] == T_CLASS) { + $inClass = true; + } else if ($token[0] == T_FUNCTION) { + if ($tokens[$i+2][0] == T_STRING) { + $this->staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+2][1]; + } else if ($tokens[$i+2] == "&" && $tokens[$i+3][0] == T_STRING) { + $this->staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+3][1]; + } + } else if (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED)) && $tokens[$i+2][0] != T_FUNCTION) { + $this->staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i+2][1], 1); + } + } + } + + private function hasProperty($property, ClassMetadataInfo $metadata) + { + if ($this->extendsClass()) { + // don't generate property if its already on the base class. + $reflClass = new \ReflectionClass($this->getClassToExtend()); + if ($reflClass->hasProperty($property)) { + return true; + } + } + + return ( + isset($this->staticReflection[$metadata->name]) && + in_array($property, $this->staticReflection[$metadata->name]['properties']) + ); + } + + private function hasMethod($method, ClassMetadataInfo $metadata) + { + if ($this->extendsClass()) { + // don't generate method if its already on the base class. + $reflClass = new \ReflectionClass($this->getClassToExtend()); + if ($reflClass->hasMethod($method)) { + return true; + } + } + + return ( + isset($this->staticReflection[$metadata->name]) && + in_array($method, $this->staticReflection[$metadata->name]['methods']) + ); + } + + private function hasNamespace(ClassMetadataInfo $metadata) + { + return strpos($metadata->name, '\\') ? true : false; + } + + private function extendsClass() + { + return $this->classToExtend ? true : false; + } + + private function getClassToExtend() + { + return $this->classToExtend; + } + + private function getClassToExtendName() + { + $refl = new \ReflectionClass($this->getClassToExtend()); + + return '\\' . $refl->getName(); + } + + private function getClassName(ClassMetadataInfo $metadata) + { + return ($pos = strrpos($metadata->name, '\\')) + ? substr($metadata->name, $pos + 1, strlen($metadata->name)) : $metadata->name; + } + + private function getNamespace(ClassMetadataInfo $metadata) + { + return substr($metadata->name, 0, strrpos($metadata->name, '\\')); + } + + private function generateEntityDocBlock(ClassMetadataInfo $metadata) + { + $lines = array(); + $lines[] = '/**'; + $lines[] = ' * '.$metadata->name; + + if ($this->generateAnnotations) { + $lines[] = ' *'; + + $methods = array( + 'generateTableAnnotation', + 'generateInheritanceAnnotation', + 'generateDiscriminatorColumnAnnotation', + 'generateDiscriminatorMapAnnotation' + ); + + foreach ($methods as $method) { + if ($code = $this->$method($metadata)) { + $lines[] = ' * ' . $code; + } + } + + if ($metadata->isMappedSuperclass) { + $lines[] = ' * @' . $this->annotationsPrefix . 'MappedSuperClass'; + } else { + $lines[] = ' * @' . $this->annotationsPrefix . 'Entity'; + } + + if ($metadata->customRepositoryClassName) { + $lines[count($lines) - 1] .= '(repositoryClass="' . $metadata->customRepositoryClassName . '")'; + } + + if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) { + $lines[] = ' * @' . $this->annotationsPrefix . 'HasLifecycleCallbacks'; + } + } + + $lines[] = ' */'; + + return implode("\n", $lines); + } + + private function generateTableAnnotation($metadata) + { + $table = array(); + + if (isset($metadata->table['schema'])) { + $table[] = 'schema="' . $metadata->table['schema'] . '"'; + } + + if (isset($metadata->table['name'])) { + $table[] = 'name="' . $metadata->table['name'] . '"'; + } + + if (isset($metadata->table['uniqueConstraints']) && $metadata->table['uniqueConstraints']) { + $constraints = $this->generateTableConstraints('UniqueConstraint', $metadata->table['uniqueConstraints']); + $table[] = 'uniqueConstraints={' . $constraints . '}'; + } + + if (isset($metadata->table['indexes']) && $metadata->table['indexes']) { + $constraints = $this->generateTableConstraints('Index', $metadata->table['indexes']); + $table[] = 'indexes={' . $constraints . '}'; + } + + return '@' . $this->annotationsPrefix . 'Table(' . implode(', ', $table) . ')'; + } + + private function generateTableConstraints($constraintName, $constraints) + { + $annotations = array(); + foreach ($constraints as $name => $constraint) { + $columns = array(); + foreach ($constraint['columns'] as $column) { + $columns[] = '"' . $column . '"'; + } + $annotations[] = '@' . $this->annotationsPrefix . $constraintName . '(name="' . $name . '", columns={' . implode(', ', $columns) . '})'; + } + return implode(', ', $annotations); + } + + private function generateInheritanceAnnotation($metadata) + { + if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) { + return '@' . $this->annotationsPrefix . 'InheritanceType("'.$this->getInheritanceTypeString($metadata->inheritanceType).'")'; + } + } + + private function generateDiscriminatorColumnAnnotation($metadata) + { + if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) { + $discrColumn = $metadata->discriminatorValue; + $columnDefinition = 'name="' . $discrColumn['name'] + . '", type="' . $discrColumn['type'] + . '", length=' . $discrColumn['length']; + + return '@' . $this->annotationsPrefix . 'DiscriminatorColumn(' . $columnDefinition . ')'; + } + } + + private function generateDiscriminatorMapAnnotation($metadata) + { + if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) { + $inheritanceClassMap = array(); + + foreach ($metadata->discriminatorMap as $type => $class) { + $inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"'; + } + + return '@' . $this->annotationsPrefix . 'DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})'; + } + } + + private function generateEntityStubMethods(ClassMetadataInfo $metadata) + { + $methods = array(); + + foreach ($metadata->fieldMappings as $fieldMapping) { + if ( ! isset($fieldMapping['id']) || ! $fieldMapping['id'] || $metadata->generatorType == ClassMetadataInfo::GENERATOR_TYPE_NONE) { + if ($code = $this->generateEntityStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'])) { + $methods[] = $code; + } + } + + if ($code = $this->generateEntityStubMethod($metadata, 'get', $fieldMapping['fieldName'], $fieldMapping['type'])) { + $methods[] = $code; + } + } + + foreach ($metadata->associationMappings as $associationMapping) { + if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) { + $nullable = $this->isAssociationIsNullable($associationMapping) ? 'null' : null; + if ($code = $this->generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'], $nullable)) { + $methods[] = $code; + } + if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'])) { + $methods[] = $code; + } + } else if ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) { + if ($code = $this->generateEntityStubMethod($metadata, 'add', $associationMapping['fieldName'], $associationMapping['targetEntity'])) { + $methods[] = $code; + } + if ($code = $this->generateEntityStubMethod($metadata, 'remove', $associationMapping['fieldName'], $associationMapping['targetEntity'])) { + $methods[] = $code; + } + if ($code = $this->generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], 'Doctrine\Common\Collections\Collection')) { + $methods[] = $code; + } + } + } + + return implode("\n\n", $methods); + } + + private function isAssociationIsNullable($associationMapping) + { + if (isset($associationMapping['id']) && $associationMapping['id']) { + return false; + } + if (isset($associationMapping['joinColumns'])) { + $joinColumns = $associationMapping['joinColumns']; + } else { + //@todo thereis no way to retreive targetEntity metadata + $joinColumns = array(); + } + foreach ($joinColumns as $joinColumn) { + if(isset($joinColumn['nullable']) && !$joinColumn['nullable']) { + return false; + } + } + return true; + } + + private function generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata) + { + if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) { + $methods = array(); + + foreach ($metadata->lifecycleCallbacks as $name => $callbacks) { + foreach ($callbacks as $callback) { + if ($code = $this->generateLifecycleCallbackMethod($name, $callback, $metadata)) { + $methods[] = $code; + } + } + } + + return implode("\n\n", $methods); + } + + return ""; + } + + private function generateEntityAssociationMappingProperties(ClassMetadataInfo $metadata) + { + $lines = array(); + + foreach ($metadata->associationMappings as $associationMapping) { + if ($this->hasProperty($associationMapping['fieldName'], $metadata)) { + continue; + } + + $lines[] = $this->generateAssociationMappingPropertyDocBlock($associationMapping, $metadata); + $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $associationMapping['fieldName'] + . ($associationMapping['type'] == 'manyToMany' ? ' = array()' : null) . ";\n"; + } + + return implode("\n", $lines); + } + + private function generateEntityFieldMappingProperties(ClassMetadataInfo $metadata) + { + $lines = array(); + + foreach ($metadata->fieldMappings as $fieldMapping) { + if ($this->hasProperty($fieldMapping['fieldName'], $metadata) || + $metadata->isInheritedField($fieldMapping['fieldName'])) { + continue; + } + + $lines[] = $this->generateFieldMappingPropertyDocBlock($fieldMapping, $metadata); + $lines[] = $this->spaces . $this->fieldVisibility . ' $' . $fieldMapping['fieldName'] + . (isset($fieldMapping['default']) ? ' = ' . var_export($fieldMapping['default'], true) : null) . ";\n"; + } + + return implode("\n", $lines); + } + + private function generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null) + { + $methodName = $type . Inflector::classify($fieldName); + if (in_array($type, array("add", "remove")) && substr($methodName, -1) == "s") { + $methodName = substr($methodName, 0, -1); + } + + if ($this->hasMethod($methodName, $metadata)) { + return; + } + $this->staticReflection[$metadata->name]['methods'][] = $methodName; + + $var = sprintf('%sMethodTemplate', $type); + $template = self::$$var; + + $types = Type::getTypesMap(); + $variableType = $typeHint ? $this->getType($typeHint) . ' ' : null; + $methodTypeHint = $typeHint && ! isset($types[$typeHint]) ? '\\' . $typeHint . ' ' : null; + + $replacements = array( + '' => ucfirst($type) . ' ' . $fieldName, + '' => $methodTypeHint, + '' => $variableType, + '' => Inflector::camelize($fieldName), + '' => $methodName, + '' => $fieldName, + '' => ($defaultValue !== null ) ? (' = '.$defaultValue) : '', + '' => $this->getClassName($metadata) + ); + + $method = str_replace( + array_keys($replacements), + array_values($replacements), + $template + ); + + return $this->prefixCodeWithSpaces($method); + } + + private function generateLifecycleCallbackMethod($name, $methodName, $metadata) + { + if ($this->hasMethod($methodName, $metadata)) { + return; + } + $this->staticReflection[$metadata->name]['methods'][] = $methodName; + + $replacements = array( + '' => $this->annotationsPrefix . ucfirst($name), + '' => $methodName, + ); + + $method = str_replace( + array_keys($replacements), + array_values($replacements), + self::$lifecycleCallbackMethodTemplate + ); + + return $this->prefixCodeWithSpaces($method); + } + + private function generateJoinColumnAnnotation(array $joinColumn) + { + $joinColumnAnnot = array(); + + if (isset($joinColumn['name'])) { + $joinColumnAnnot[] = 'name="' . $joinColumn['name'] . '"'; + } + + if (isset($joinColumn['referencedColumnName'])) { + $joinColumnAnnot[] = 'referencedColumnName="' . $joinColumn['referencedColumnName'] . '"'; + } + + if (isset($joinColumn['unique']) && $joinColumn['unique']) { + $joinColumnAnnot[] = 'unique=' . ($joinColumn['unique'] ? 'true' : 'false'); + } + + if (isset($joinColumn['nullable'])) { + $joinColumnAnnot[] = 'nullable=' . ($joinColumn['nullable'] ? 'true' : 'false'); + } + + if (isset($joinColumn['onDelete'])) { + $joinColumnAnnot[] = 'onDelete="' . ($joinColumn['onDelete'] . '"'); + } + + if (isset($joinColumn['columnDefinition'])) { + $joinColumnAnnot[] = 'columnDefinition="' . $joinColumn['columnDefinition'] . '"'; + } + + return '@' . $this->annotationsPrefix . 'JoinColumn(' . implode(', ', $joinColumnAnnot) . ')'; + } + + private function generateAssociationMappingPropertyDocBlock(array $associationMapping, ClassMetadataInfo $metadata) + { + $lines = array(); + $lines[] = $this->spaces . '/**'; + + if ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) { + $lines[] = $this->spaces . ' * @var \Doctrine\Common\Collections\ArrayCollection'; + } else { + $lines[] = $this->spaces . ' * @var ' . $associationMapping['targetEntity']; + } + + if ($this->generateAnnotations) { + $lines[] = $this->spaces . ' *'; + + if (isset($associationMapping['id']) && $associationMapping['id']) { + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id'; + + if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) { + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")'; + } + } + + $type = null; + switch ($associationMapping['type']) { + case ClassMetadataInfo::ONE_TO_ONE: + $type = 'OneToOne'; + break; + case ClassMetadataInfo::MANY_TO_ONE: + $type = 'ManyToOne'; + break; + case ClassMetadataInfo::ONE_TO_MANY: + $type = 'OneToMany'; + break; + case ClassMetadataInfo::MANY_TO_MANY: + $type = 'ManyToMany'; + break; + } + $typeOptions = array(); + + if (isset($associationMapping['targetEntity'])) { + $typeOptions[] = 'targetEntity="' . $associationMapping['targetEntity'] . '"'; + } + + if (isset($associationMapping['inversedBy'])) { + $typeOptions[] = 'inversedBy="' . $associationMapping['inversedBy'] . '"'; + } + + if (isset($associationMapping['mappedBy'])) { + $typeOptions[] = 'mappedBy="' . $associationMapping['mappedBy'] . '"'; + } + + if ($associationMapping['cascade']) { + $cascades = array(); + + if ($associationMapping['isCascadePersist']) $cascades[] = '"persist"'; + if ($associationMapping['isCascadeRemove']) $cascades[] = '"remove"'; + if ($associationMapping['isCascadeDetach']) $cascades[] = '"detach"'; + if ($associationMapping['isCascadeMerge']) $cascades[] = '"merge"'; + if ($associationMapping['isCascadeRefresh']) $cascades[] = '"refresh"'; + + $typeOptions[] = 'cascade={' . implode(',', $cascades) . '}'; + } + + if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']) { + $typeOptions[] = 'orphanRemoval=' . ($associationMapping['orphanRemoval'] ? 'true' : 'false'); + } + + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . '' . $type . '(' . implode(', ', $typeOptions) . ')'; + + if (isset($associationMapping['joinColumns']) && $associationMapping['joinColumns']) { + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinColumns({'; + + $joinColumnsLines = array(); + + foreach ($associationMapping['joinColumns'] as $joinColumn) { + if ($joinColumnAnnot = $this->generateJoinColumnAnnotation($joinColumn)) { + $joinColumnsLines[] = $this->spaces . ' * ' . $joinColumnAnnot; + } + } + + $lines[] = implode(",\n", $joinColumnsLines); + $lines[] = $this->spaces . ' * })'; + } + + if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) { + $joinTable = array(); + $joinTable[] = 'name="' . $associationMapping['joinTable']['name'] . '"'; + + if (isset($associationMapping['joinTable']['schema'])) { + $joinTable[] = 'schema="' . $associationMapping['joinTable']['schema'] . '"'; + } + + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'JoinTable(' . implode(', ', $joinTable) . ','; + $lines[] = $this->spaces . ' * joinColumns={'; + + foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) { + $lines[] = $this->spaces . ' * ' . $this->generateJoinColumnAnnotation($joinColumn); + } + + $lines[] = $this->spaces . ' * },'; + $lines[] = $this->spaces . ' * inverseJoinColumns={'; + + foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $joinColumn) { + $lines[] = $this->spaces . ' * ' . $this->generateJoinColumnAnnotation($joinColumn); + } + + $lines[] = $this->spaces . ' * }'; + $lines[] = $this->spaces . ' * )'; + } + + if (isset($associationMapping['orderBy'])) { + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'OrderBy({'; + + foreach ($associationMapping['orderBy'] as $name => $direction) { + $lines[] = $this->spaces . ' * "' . $name . '"="' . $direction . '",'; + } + + $lines[count($lines) - 1] = substr($lines[count($lines) - 1], 0, strlen($lines[count($lines) - 1]) - 1); + $lines[] = $this->spaces . ' * })'; + } + } + + $lines[] = $this->spaces . ' */'; + + return implode("\n", $lines); + } + + private function generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata) + { + $lines = array(); + $lines[] = $this->spaces . '/**'; + $lines[] = $this->spaces . ' * @var ' . $this->getType($fieldMapping['type']) . ' $' . $fieldMapping['fieldName']; + + if ($this->generateAnnotations) { + $lines[] = $this->spaces . ' *'; + + $column = array(); + if (isset($fieldMapping['columnName'])) { + $column[] = 'name="' . $fieldMapping['columnName'] . '"'; + } + + if (isset($fieldMapping['type'])) { + $column[] = 'type="' . $fieldMapping['type'] . '"'; + } + + if (isset($fieldMapping['length'])) { + $column[] = 'length=' . $fieldMapping['length']; + } + + if (isset($fieldMapping['precision'])) { + $column[] = 'precision=' . $fieldMapping['precision']; + } + + if (isset($fieldMapping['scale'])) { + $column[] = 'scale=' . $fieldMapping['scale']; + } + + if (isset($fieldMapping['nullable'])) { + $column[] = 'nullable=' . var_export($fieldMapping['nullable'], true); + } + + if (isset($fieldMapping['columnDefinition'])) { + $column[] = 'columnDefinition="' . $fieldMapping['columnDefinition'] . '"'; + } + + if (isset($fieldMapping['unique'])) { + $column[] = 'unique=' . var_export($fieldMapping['unique'], true); + } + + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Column(' . implode(', ', $column) . ')'; + + if (isset($fieldMapping['id']) && $fieldMapping['id']) { + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Id'; + + if ($generatorType = $this->getIdGeneratorTypeString($metadata->generatorType)) { + $lines[] = $this->spaces.' * @' . $this->annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")'; + } + + if ($metadata->sequenceGeneratorDefinition) { + $sequenceGenerator = array(); + + if (isset($metadata->sequenceGeneratorDefinition['sequenceName'])) { + $sequenceGenerator[] = 'sequenceName="' . $metadata->sequenceGeneratorDefinition['sequenceName'] . '"'; + } + + if (isset($metadata->sequenceGeneratorDefinition['allocationSize'])) { + $sequenceGenerator[] = 'allocationSize=' . $metadata->sequenceGeneratorDefinition['allocationSize']; + } + + if (isset($metadata->sequenceGeneratorDefinition['initialValue'])) { + $sequenceGenerator[] = 'initialValue=' . $metadata->sequenceGeneratorDefinition['initialValue']; + } + + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'SequenceGenerator(' . implode(', ', $sequenceGenerator) . ')'; + } + } + + if (isset($fieldMapping['version']) && $fieldMapping['version']) { + $lines[] = $this->spaces . ' * @' . $this->annotationsPrefix . 'Version'; + } + } + + $lines[] = $this->spaces . ' */'; + + return implode("\n", $lines); + } + + private function prefixCodeWithSpaces($code, $num = 1) + { + $lines = explode("\n", $code); + + foreach ($lines as $key => $value) { + $lines[$key] = str_repeat($this->spaces, $num) . $lines[$key]; + } + + return implode("\n", $lines); + } + + private function getInheritanceTypeString($type) + { + switch ($type) { + case ClassMetadataInfo::INHERITANCE_TYPE_NONE: + return 'NONE'; + + case ClassMetadataInfo::INHERITANCE_TYPE_JOINED: + return 'JOINED'; + + case ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE: + return 'SINGLE_TABLE'; + + case ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS: + return 'PER_CLASS'; + + default: + throw new \InvalidArgumentException('Invalid provided InheritanceType: ' . $type); + } + } + + private function getChangeTrackingPolicyString($policy) + { + switch ($policy) { + case ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT: + return 'DEFERRED_IMPLICIT'; + + case ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT: + return 'DEFERRED_EXPLICIT'; + + case ClassMetadataInfo::CHANGETRACKING_NOTIFY: + return 'NOTIFY'; + + default: + throw new \InvalidArgumentException('Invalid provided ChangeTrackingPolicy: ' . $policy); + } + } + + private function getIdGeneratorTypeString($type) + { + switch ($type) { + case ClassMetadataInfo::GENERATOR_TYPE_AUTO: + return 'AUTO'; + + case ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE: + return 'SEQUENCE'; + + case ClassMetadataInfo::GENERATOR_TYPE_TABLE: + return 'TABLE'; + + case ClassMetadataInfo::GENERATOR_TYPE_IDENTITY: + return 'IDENTITY'; + + case ClassMetadataInfo::GENERATOR_TYPE_NONE: + return 'NONE'; + + default: + throw new \InvalidArgumentException('Invalid provided IdGeneratorType: ' . $type); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/EntityRepositoryGenerator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/EntityRepositoryGenerator.php new file mode 100644 index 0000000..e696abc --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/EntityRepositoryGenerator.php @@ -0,0 +1,81 @@ +. + */ + +namespace Doctrine\ORM\Tools; + +/** + * Class to generate entity repository classes + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class EntityRepositoryGenerator +{ + protected static $_template = +'; + +use Doctrine\ORM\EntityRepository; + +/** + * + * + * This class was generated by the Doctrine ORM. Add your own custom + * repository methods below. + */ +class extends EntityRepository +{ +} +'; + + public function generateEntityRepositoryClass($fullClassName) + { + $namespace = substr($fullClassName, 0, strrpos($fullClassName, '\\')); + $className = substr($fullClassName, strrpos($fullClassName, '\\') + 1, strlen($fullClassName)); + + $variables = array( + '' => $namespace, + '' => $className + ); + return str_replace(array_keys($variables), array_values($variables), self::$_template); + } + + public function writeEntityRepositoryClass($fullClassName, $outputDirectory) + { + $code = $this->generateEntityRepositoryClass($fullClassName); + + $path = $outputDirectory . DIRECTORY_SEPARATOR + . str_replace('\\', \DIRECTORY_SEPARATOR, $fullClassName) . '.php'; + $dir = dirname($path); + + if ( ! is_dir($dir)) { + mkdir($dir, 0777, true); + } + + if ( ! file_exists($path)) { + file_put_contents($path, $code); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Event/GenerateSchemaEventArgs.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Event/GenerateSchemaEventArgs.php new file mode 100644 index 0000000..0473111 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Event/GenerateSchemaEventArgs.php @@ -0,0 +1,62 @@ +. + */ + +namespace Doctrine\ORM\Tools\Event; + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\ORM\EntityManager; + +/** + * Event Args used for the Events::postGenerateSchema event. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @author Benjamin Eberlei + */ +class GenerateSchemaEventArgs extends \Doctrine\Common\EventArgs +{ + private $_em = null; + private $_schema = null; + + /** + * @param ClassMetadata $classMetadata + * @param Schema $schema + * @param Table $classTable + */ + public function __construct(EntityManager $em, Schema $schema) + { + $this->_em = $em; + $this->_schema = $schema; + } + + /** + * @return EntityManager + */ + public function getEntityManager() { + return $this->_em; + } + + /** + * @return Schema + */ + public function getSchema() { + return $this->_schema; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Event/GenerateSchemaTableEventArgs.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Event/GenerateSchemaTableEventArgs.php new file mode 100644 index 0000000..060c554 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Event/GenerateSchemaTableEventArgs.php @@ -0,0 +1,71 @@ +. + */ +namespace Doctrine\ORM\Tools\Event; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Schema\Table; + +/** + * Event Args used for the Events::postGenerateSchemaTable event. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @author Benjamin Eberlei + */ +class GenerateSchemaTableEventArgs extends \Doctrine\Common\EventArgs +{ + private $_classMetadata = null; + private $_schema = null; + private $_classTable = null; + + /** + * @param ClassMetadata $classMetadata + * @param Schema $schema + * @param Table $classTable + */ + public function __construct(ClassMetadata $classMetadata, Schema $schema, Table $classTable) + { + $this->_classMetadata = $classMetadata; + $this->_schema = $schema; + $this->_classTable = $classTable; + } + + /** + * @return ClassMetadata + */ + public function getClassMetadata() { + return $this->_classMetadata; + } + + /** + * @return Schema + */ + public function getSchema() { + return $this->_schema; + } + + /** + * @return Table + */ + public function getClassTable() { + return $this->_classTable; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php new file mode 100644 index 0000000..843c004 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/ClassMetadataExporter.php @@ -0,0 +1,72 @@ +. + */ + +namespace Doctrine\ORM\Tools\Export; + +use Doctrine\ORM\Tools\Export\ExportException, + Doctrine\ORM\EntityManager; + +/** + * Class used for converting your mapping information between the + * supported formats: yaml, xml, and php/annotation. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Jonathan Wage + */ +class ClassMetadataExporter +{ + private static $_exporterDrivers = array( + 'xml' => 'Doctrine\ORM\Tools\Export\Driver\XmlExporter', + 'yaml' => 'Doctrine\ORM\Tools\Export\Driver\YamlExporter', + 'yml' => 'Doctrine\ORM\Tools\Export\Driver\YamlExporter', + 'php' => 'Doctrine\ORM\Tools\Export\Driver\PhpExporter', + 'annotation' => 'Doctrine\ORM\Tools\Export\Driver\AnnotationExporter' + ); + + /** + * Register a new exporter driver class under a specified name + * + * @param string $name + * @param string $class + */ + public static function registerExportDriver($name, $class) + { + self::$_exporterDrivers[$name] = $class; + } + + /** + * Get a exporter driver instance + * + * @param string $type The type to get (yml, xml, etc.) + * @param string $source The directory where the exporter will export to + * @return AbstractExporter $exporter + */ + public function getExporter($type, $dest = null) + { + if ( ! isset(self::$_exporterDrivers[$type])) { + throw ExportException::invalidExporterDriverType($type); + } + + $class = self::$_exporterDrivers[$type]; + + return new $class($dest); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php new file mode 100644 index 0000000..7c13397 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php @@ -0,0 +1,213 @@ +. + */ + +namespace Doctrine\ORM\Tools\Export\Driver; + +use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Tools\Export\ExportException; + +/** + * Abstract base class which is to be used for the Exporter drivers + * which can be found in \Doctrine\ORM\Tools\Export\Driver + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Jonathan Wage + */ +abstract class AbstractExporter +{ + protected $_metadata = array(); + protected $_outputDir; + protected $_extension; + protected $_overwriteExistingFiles = false; + + public function __construct($dir = null) + { + $this->_outputDir = $dir; + } + + public function setOverwriteExistingFiles($overwrite) + { + $this->_overwriteExistingFiles = $overwrite; + } + + /** + * Converts a single ClassMetadata instance to the exported format + * and returns it + * + * @param ClassMetadataInfo $metadata + * @return mixed $exported + */ + abstract public function exportClassMetadata(ClassMetadataInfo $metadata); + + /** + * Set the array of ClassMetadataInfo instances to export + * + * @param array $metadata + * @return void + */ + public function setMetadata(array $metadata) + { + $this->_metadata = $metadata; + } + + /** + * Get the extension used to generated the path to a class + * + * @return string $extension + */ + public function getExtension() + { + return $this->_extension; + } + + /** + * Set the directory to output the mapping files to + * + * [php] + * $exporter = new YamlExporter($metadata); + * $exporter->setOutputDir(__DIR__ . '/yaml'); + * $exporter->export(); + * + * @param string $dir + * @return void + */ + public function setOutputDir($dir) + { + $this->_outputDir = $dir; + } + + /** + * Export each ClassMetadata instance to a single Doctrine Mapping file + * named after the entity + * + * @return void + */ + public function export() + { + if ( ! is_dir($this->_outputDir)) { + mkdir($this->_outputDir, 0777, true); + } + + foreach ($this->_metadata as $metadata) { + //In case output is returned, write it to a file, skip otherwise + if($output = $this->exportClassMetadata($metadata)){ + $path = $this->_generateOutputPath($metadata); + $dir = dirname($path); + if ( ! is_dir($dir)) { + mkdir($dir, 0777, true); + } + if (file_exists($path) && !$this->_overwriteExistingFiles) { + throw ExportException::attemptOverwriteExistingFile($path); + } + file_put_contents($path, $output); + } + } + } + + /** + * Generate the path to write the class for the given ClassMetadataInfo instance + * + * @param ClassMetadataInfo $metadata + * @return string $path + */ + protected function _generateOutputPath(ClassMetadataInfo $metadata) + { + return $this->_outputDir . '/' . str_replace('\\', '.', $metadata->name) . $this->_extension; + } + + /** + * Set the directory to output the mapping files to + * + * [php] + * $exporter = new YamlExporter($metadata, __DIR__ . '/yaml'); + * $exporter->setExtension('.yml'); + * $exporter->export(); + * + * @param string $extension + * @return void + */ + public function setExtension($extension) + { + $this->_extension = $extension; + } + + protected function _getInheritanceTypeString($type) + { + switch ($type) + { + case ClassMetadataInfo::INHERITANCE_TYPE_NONE: + return 'NONE'; + break; + + case ClassMetadataInfo::INHERITANCE_TYPE_JOINED: + return 'JOINED'; + break; + + case ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE: + return 'SINGLE_TABLE'; + break; + + case ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS: + return 'PER_CLASS'; + break; + } + } + + protected function _getChangeTrackingPolicyString($policy) + { + switch ($policy) + { + case ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT: + return 'DEFERRED_IMPLICIT'; + break; + + case ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT: + return 'DEFERRED_EXPLICIT'; + break; + + case ClassMetadataInfo::CHANGETRACKING_NOTIFY: + return 'NOTIFY'; + break; + } + } + + protected function _getIdGeneratorTypeString($type) + { + switch ($type) + { + case ClassMetadataInfo::GENERATOR_TYPE_AUTO: + return 'AUTO'; + break; + + case ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE: + return 'SEQUENCE'; + break; + + case ClassMetadataInfo::GENERATOR_TYPE_TABLE: + return 'TABLE'; + break; + + case ClassMetadataInfo::GENERATOR_TYPE_IDENTITY: + return 'IDENTITY'; + break; + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php new file mode 100644 index 0000000..d1ec92a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php @@ -0,0 +1,67 @@ +. + */ + +namespace Doctrine\ORM\Tools\Export\Driver; + +use Doctrine\ORM\Mapping\ClassMetadataInfo, + Doctrine\ORM\Tools\EntityGenerator; + +/** + * ClassMetadata exporter for PHP classes with annotations + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Jonathan Wage + */ +class AnnotationExporter extends AbstractExporter +{ + protected $_extension = '.php'; + private $_entityGenerator; + + /** + * Converts a single ClassMetadata instance to the exported format + * and returns it + * + * @param ClassMetadataInfo $metadata + * @return string $exported + */ + public function exportClassMetadata(ClassMetadataInfo $metadata) + { + if ( ! $this->_entityGenerator) { + throw new \RuntimeException('For the AnnotationExporter you must set an EntityGenerator instance with the setEntityGenerator() method.'); + } + $this->_entityGenerator->setGenerateAnnotations(true); + $this->_entityGenerator->setGenerateStubMethods(false); + $this->_entityGenerator->setRegenerateEntityIfExists(false); + $this->_entityGenerator->setUpdateEntityIfExists(false); + + return $this->_entityGenerator->generateEntityClass($metadata); + } + + protected function _generateOutputPath(ClassMetadataInfo $metadata) + { + return $this->_outputDir . '/' . str_replace('\\', '/', $metadata->name) . $this->_extension; + } + + public function setEntityGenerator(EntityGenerator $entityGenerator) + { + $this->_entityGenerator = $entityGenerator; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php new file mode 100644 index 0000000..24f7243 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php @@ -0,0 +1,165 @@ +. + */ + +namespace Doctrine\ORM\Tools\Export\Driver; + +use Doctrine\ORM\Mapping\ClassMetadataInfo; + +/** + * ClassMetadata exporter for PHP code + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Jonathan Wage + */ +class PhpExporter extends AbstractExporter +{ + protected $_extension = '.php'; + + /** + * Converts a single ClassMetadata instance to the exported format + * and returns it + * + * @param ClassMetadataInfo $metadata + * @return mixed $exported + */ + public function exportClassMetadata(ClassMetadataInfo $metadata) + { + $lines = array(); + $lines[] = 'isMappedSuperclass) { + $lines[] = '$metadata->isMappedSuperclass = true;'; + } + + if ($metadata->inheritanceType) { + $lines[] = '$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_' . $this->_getInheritanceTypeString($metadata->inheritanceType) . ');'; + } + + if ($metadata->customRepositoryClassName) { + $lines[] = "\$metadata->customRepositoryClassName = '" . $metadata->customRepositoryClassName . "';"; + } + + if ($metadata->table) { + $lines[] = '$metadata->setPrimaryTable(' . $this->_varExport($metadata->table) . ');'; + } + + if ($metadata->discriminatorColumn) { + $lines[] = '$metadata->setDiscriminatorColumn(' . $this->_varExport($metadata->discriminatorColumn) . ');'; + } + + if ($metadata->discriminatorMap) { + $lines[] = '$metadata->setDiscriminatorMap(' . $this->_varExport($metadata->discriminatorMap) . ');'; + } + + if ($metadata->changeTrackingPolicy) { + $lines[] = '$metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_' . $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy) . ');'; + } + + if ($metadata->lifecycleCallbacks) { + foreach ($metadata->lifecycleCallbacks as $event => $callbacks) { + foreach ($callbacks as $callback) { + $lines[] = "\$metadata->addLifecycleCallback('$callback', '$event');"; + } + } + } + + foreach ($metadata->fieldMappings as $fieldMapping) { + $lines[] = '$metadata->mapField(' . $this->_varExport($fieldMapping) . ');'; + } + + if ( ! $metadata->isIdentifierComposite && $generatorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) { + $lines[] = '$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_' . $generatorType . ');'; + } + + foreach ($metadata->associationMappings as $associationMapping) { + $cascade = array('remove', 'persist', 'refresh', 'merge', 'detach'); + foreach ($cascade as $key => $value) { + if ( ! $associationMapping['isCascade'.ucfirst($value)]) { + unset($cascade[$key]); + } + } + $associationMappingArray = array( + 'fieldName' => $associationMapping['fieldName'], + 'targetEntity' => $associationMapping['targetEntity'], + 'cascade' => $cascade, + ); + + if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) { + $method = 'mapOneToOne'; + $oneToOneMappingArray = array( + 'mappedBy' => $associationMapping['mappedBy'], + 'inversedBy' => $associationMapping['inversedBy'], + 'joinColumns' => $associationMapping['joinColumns'], + 'orphanRemoval' => $associationMapping['orphanRemoval'], + ); + + $associationMappingArray = array_merge($associationMappingArray, $oneToOneMappingArray); + } else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) { + $method = 'mapOneToMany'; + $potentialAssociationMappingIndexes = array( + 'mappedBy', + 'orphanRemoval', + 'orderBy', + ); + foreach ($potentialAssociationMappingIndexes as $index) { + if (isset($associationMapping[$index])) { + $oneToManyMappingArray[$index] = $associationMapping[$index]; + } + } + $associationMappingArray = array_merge($associationMappingArray, $oneToManyMappingArray); + } else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_MANY) { + $method = 'mapManyToMany'; + $potentialAssociationMappingIndexes = array( + 'mappedBy', + 'joinTable', + 'orderBy', + ); + foreach ($potentialAssociationMappingIndexes as $index) { + if (isset($associationMapping[$index])) { + $manyToManyMappingArray[$index] = $associationMapping[$index]; + } + } + $associationMappingArray = array_merge($associationMappingArray, $manyToManyMappingArray); + } + + $lines[] = '$metadata->' . $method . '(' . $this->_varExport($associationMappingArray) . ');'; + } + + return implode("\n", $lines); + } + + protected function _varExport($var) + { + $export = var_export($var, true); + $export = str_replace("\n", PHP_EOL . str_repeat(' ', 8), $export); + $export = str_replace(' ', ' ', $export); + $export = str_replace('array (', 'array(', $export); + $export = str_replace('array( ', 'array(', $export); + $export = str_replace(',)', ')', $export); + $export = str_replace(', )', ')', $export); + $export = str_replace(' ', ' ', $export); + + return $export; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php new file mode 100644 index 0000000..98f3d18 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php @@ -0,0 +1,335 @@ +. + */ + +namespace Doctrine\ORM\Tools\Export\Driver; + +use Doctrine\ORM\Mapping\ClassMetadataInfo; + +/** + * ClassMetadata exporter for Doctrine XML mapping files + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Jonathan Wage + */ +class XmlExporter extends AbstractExporter +{ + protected $_extension = '.dcm.xml'; + + /** + * Converts a single ClassMetadata instance to the exported format + * and returns it + * + * @param ClassMetadataInfo $metadata + * @return mixed $exported + */ + public function exportClassMetadata(ClassMetadataInfo $metadata) + { + $xml = new \SimpleXmlElement(""); + + /*$xml->addAttribute('xmlns', 'http://doctrine-project.org/schemas/orm/doctrine-mapping'); + $xml->addAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $xml->addAttribute('xsi:schemaLocation', 'http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd');*/ + + if ($metadata->isMappedSuperclass) { + $root = $xml->addChild('mapped-superclass'); + } else { + $root = $xml->addChild('entity'); + } + + if ($metadata->customRepositoryClassName) { + $root->addAttribute('repository-class', $metadata->customRepositoryClassName); + } + + $root->addAttribute('name', $metadata->name); + + if (isset($metadata->table['name'])) { + $root->addAttribute('table', $metadata->table['name']); + } + + if (isset($metadata->table['schema'])) { + $root->addAttribute('schema', $metadata->table['schema']); + } + + if (isset($metadata->table['inheritance-type'])) { + $root->addAttribute('inheritance-type', $metadata->table['inheritance-type']); + } + + if ($metadata->discriminatorColumn) { + $discriminatorColumnXml = $root->addChild('discriminiator-column'); + $discriminatorColumnXml->addAttribute('name', $metadata->discriminatorColumn['name']); + $discriminatorColumnXml->addAttribute('type', $metadata->discriminatorColumn['type']); + $discriminatorColumnXml->addAttribute('length', $metadata->discriminatorColumn['length']); + } + + if ($metadata->discriminatorMap) { + $discriminatorMapXml = $root->addChild('discriminator-map'); + foreach ($metadata->discriminatorMap as $value => $className) { + $discriminatorMappingXml = $discriminatorMapXml->addChild('discriminator-mapping'); + $discriminatorMappingXml->addAttribute('value', $value); + $discriminatorMappingXml->addAttribute('class', $className); + } + } + + $trackingPolicy = $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy); + if ( $trackingPolicy != 'DEFERRED_IMPLICIT') { + $root->addChild('change-tracking-policy', $trackingPolicy); + } + + if (isset($metadata->table['indexes'])) { + $indexesXml = $root->addChild('indexes'); + + foreach ($metadata->table['indexes'] as $name => $index) { + $indexXml = $indexesXml->addChild('index'); + $indexXml->addAttribute('name', $name); + $indexXml->addAttribute('columns', implode(',', $index['columns'])); + } + } + + if (isset($metadata->table['uniqueConstraints'])) { + $uniqueConstraintsXml = $root->addChild('unique-constraints'); + + foreach ($metadata->table['uniqueConstraints'] as $unique) { + $uniqueConstraintXml = $uniqueConstraintsXml->addChild('unique-constraint'); + $uniqueConstraintXml->addAttribute('name', $unique['name']); + $uniqueConstraintXml->addAttribute('columns', implode(',', $unique['columns'])); + } + } + + $fields = $metadata->fieldMappings; + + $id = array(); + foreach ($fields as $name => $field) { + if (isset($field['id']) && $field['id']) { + $id[$name] = $field; + unset($fields[$name]); + } + } + + if ( ! $metadata->isIdentifierComposite && $idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) { + $id[$metadata->getSingleIdentifierFieldName()]['generator']['strategy'] = $idGeneratorType; + } + + if ($id) { + foreach ($id as $field) { + $idXml = $root->addChild('id'); + $idXml->addAttribute('name', $field['fieldName']); + $idXml->addAttribute('type', $field['type']); + if (isset($field['columnName'])) { + $idXml->addAttribute('column', $field['columnName']); + } + if (isset($field['associationKey']) && $field['associationKey']) { + $idXml->addAttribute('association-key', 'true'); + } + if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) { + $generatorXml = $idXml->addChild('generator'); + $generatorXml->addAttribute('strategy', $idGeneratorType); + } + } + } + + if ($fields) { + foreach ($fields as $field) { + $fieldXml = $root->addChild('field'); + $fieldXml->addAttribute('name', $field['fieldName']); + $fieldXml->addAttribute('type', $field['type']); + if (isset($field['columnName'])) { + $fieldXml->addAttribute('column', $field['columnName']); + } + if (isset($field['length'])) { + $fieldXml->addAttribute('length', $field['length']); + } + if (isset($field['precision'])) { + $fieldXml->addAttribute('precision', $field['precision']); + } + if (isset($field['scale'])) { + $fieldXml->addAttribute('scale', $field['scale']); + } + if (isset($field['unique']) && $field['unique']) { + $fieldXml->addAttribute('unique', $field['unique']); + } + if (isset($field['options'])) { + $optionsXml = $fieldXml->addChild('options'); + foreach ($field['options'] as $key => $value) { + $optionsXml->addAttribute($key, $value); + } + } + if (isset($field['version'])) { + $fieldXml->addAttribute('version', $field['version']); + } + if (isset($field['columnDefinition'])) { + $fieldXml->addAttribute('column-definition', $field['columnDefinition']); + } + if (isset($field['nullable'])) { + $fieldXml->addAttribute('nullable', $field['nullable'] ? 'true' : 'false'); + } + } + } + $orderMap = array( + ClassMetadataInfo::ONE_TO_ONE, + ClassMetadataInfo::ONE_TO_MANY, + ClassMetadataInfo::MANY_TO_ONE, + ClassMetadataInfo::MANY_TO_MANY, + ); + uasort($metadata->associationMappings, function($m1, $m2)use(&$orderMap){ + $a1 = array_search($m1['type'],$orderMap); + $a2 = array_search($m2['type'],$orderMap); + return strcmp($a1, $a2); + }); + foreach ($metadata->associationMappings as $name => $associationMapping) { + if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_ONE) { + $associationMappingXml = $root->addChild('one-to-one'); + } else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_ONE) { + $associationMappingXml = $root->addChild('many-to-one'); + } else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) { + $associationMappingXml = $root->addChild('one-to-many'); + } else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_MANY) { + $associationMappingXml = $root->addChild('many-to-many'); + } + + $associationMappingXml->addAttribute('field', $associationMapping['fieldName']); + $associationMappingXml->addAttribute('target-entity', $associationMapping['targetEntity']); + + if (isset($associationMapping['mappedBy'])) { + $associationMappingXml->addAttribute('mapped-by', $associationMapping['mappedBy']); + } + if (isset($associationMapping['inversedBy'])) { + $associationMappingXml->addAttribute('inversed-by', $associationMapping['inversedBy']); + } + if (isset($associationMapping['indexBy'])) { + $associationMappingXml->addAttribute('index-by', $associationMapping['indexBy']); + } + if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']!==false) { + $associationMappingXml->addAttribute('orphan-removal', 'true'); + } + if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) { + $joinTableXml = $associationMappingXml->addChild('join-table'); + $joinTableXml->addAttribute('name', $associationMapping['joinTable']['name']); + $joinColumnsXml = $joinTableXml->addChild('join-columns'); + foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) { + $joinColumnXml = $joinColumnsXml->addChild('join-column'); + $joinColumnXml->addAttribute('name', $joinColumn['name']); + $joinColumnXml->addAttribute('referenced-column-name', $joinColumn['referencedColumnName']); + if (isset($joinColumn['onDelete'])) { + $joinColumnXml->addAttribute('on-delete', $joinColumn['onDelete']); + } + } + $inverseJoinColumnsXml = $joinTableXml->addChild('inverse-join-columns'); + foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) { + $inverseJoinColumnXml = $inverseJoinColumnsXml->addChild('join-column'); + $inverseJoinColumnXml->addAttribute('name', $inverseJoinColumn['name']); + $inverseJoinColumnXml->addAttribute('referenced-column-name', $inverseJoinColumn['referencedColumnName']); + if (isset($inverseJoinColumn['onDelete'])) { + $inverseJoinColumnXml->addAttribute('on-delete', $inverseJoinColumn['onDelete']); + } + if (isset($inverseJoinColumn['columnDefinition'])) { + $inverseJoinColumnXml->addAttribute('column-definition', $inverseJoinColumn['columnDefinition']); + } + if (isset($inverseJoinColumn['nullable'])) { + $inverseJoinColumnXml->addAttribute('nullable', $inverseJoinColumn['nullable']); + } + if (isset($inverseJoinColumn['orderBy'])) { + $inverseJoinColumnXml->addAttribute('order-by', $inverseJoinColumn['orderBy']); + } + } + } + if (isset($associationMapping['joinColumns'])) { + $joinColumnsXml = $associationMappingXml->addChild('join-columns'); + foreach ($associationMapping['joinColumns'] as $joinColumn) { + $joinColumnXml = $joinColumnsXml->addChild('join-column'); + $joinColumnXml->addAttribute('name', $joinColumn['name']); + $joinColumnXml->addAttribute('referenced-column-name', $joinColumn['referencedColumnName']); + if (isset($joinColumn['onDelete'])) { + $joinColumnXml->addAttribute('on-delete', $joinColumn['onDelete']); + } + if (isset($joinColumn['columnDefinition'])) { + $joinColumnXml->addAttribute('column-definition', $joinColumn['columnDefinition']); + } + if (isset($joinColumn['nullable'])) { + $joinColumnXml->addAttribute('nullable', $joinColumn['nullable']); + } + } + } + if (isset($associationMapping['orderBy'])) { + $orderByXml = $associationMappingXml->addChild('order-by'); + foreach ($associationMapping['orderBy'] as $name => $direction) { + $orderByFieldXml = $orderByXml->addChild('order-by-field'); + $orderByFieldXml->addAttribute('name', $name); + $orderByFieldXml->addAttribute('direction', $direction); + } + } + $cascade = array(); + if ($associationMapping['isCascadeRemove']) { + $cascade[] = 'cascade-remove'; + } + if ($associationMapping['isCascadePersist']) { + $cascade[] = 'cascade-persist'; + } + if ($associationMapping['isCascadeRefresh']) { + $cascade[] = 'cascade-refresh'; + } + if ($associationMapping['isCascadeMerge']) { + $cascade[] = 'cascade-merge'; + } + if ($associationMapping['isCascadeDetach']) { + $cascade[] = 'cascade-detach'; + } + if (count($cascade) === 5) { + $cascade = array('cascade-all'); + } + if ($cascade) { + $cascadeXml = $associationMappingXml->addChild('cascade'); + foreach ($cascade as $type) { + $cascadeXml->addChild($type); + } + } + } + + if (isset($metadata->lifecycleCallbacks) && count($metadata->lifecycleCallbacks)>0) { + $lifecycleCallbacksXml = $root->addChild('lifecycle-callbacks'); + foreach ($metadata->lifecycleCallbacks as $name => $methods) { + foreach ($methods as $method) { + $lifecycleCallbackXml = $lifecycleCallbacksXml->addChild('lifecycle-callback'); + $lifecycleCallbackXml->addAttribute('type', $name); + $lifecycleCallbackXml->addAttribute('method', $method); + } + } + } + + return $this->_asXml($xml); + } + + /** + * @param \SimpleXMLElement $simpleXml + * @return string $xml + */ + private function _asXml($simpleXml) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->loadXML($simpleXml->asXML()); + $dom->formatOutput = true; + + $result = $dom->saveXML(); + return $result; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php new file mode 100644 index 0000000..ceafa83 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php @@ -0,0 +1,205 @@ +. + */ + +namespace Doctrine\ORM\Tools\Export\Driver; + +use Doctrine\ORM\Mapping\ClassMetadataInfo; + +/** + * ClassMetadata exporter for Doctrine YAML mapping files + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Jonathan Wage + */ +class YamlExporter extends AbstractExporter +{ + protected $_extension = '.dcm.yml'; + + /** + * Converts a single ClassMetadata instance to the exported format + * and returns it + * + * TODO: Should this code be pulled out in to a toArray() method in ClassMetadata + * + * @param ClassMetadataInfo $metadata + * @return mixed $exported + */ + public function exportClassMetadata(ClassMetadataInfo $metadata) + { + $array = array(); + + if ($metadata->isMappedSuperclass) { + $array['type'] = 'mappedSuperclass'; + } else { + $array['type'] = 'entity'; + } + + $array['table'] = $metadata->table['name']; + + if (isset($metadata->table['schema'])) { + $array['schema'] = $metadata->table['schema']; + } + + $inheritanceType = $metadata->inheritanceType; + if ($inheritanceType !== ClassMetadataInfo::INHERITANCE_TYPE_NONE) { + $array['inheritanceType'] = $this->_getInheritanceTypeString($inheritanceType); + } + + if ($column = $metadata->discriminatorColumn) { + $array['discriminatorColumn'] = $column; + } + + if ($map = $metadata->discriminatorMap) { + $array['discriminatorMap'] = $map; + } + + if ($metadata->changeTrackingPolicy !== ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT) { + $array['changeTrackingPolicy'] = $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy); + } + + if (isset($metadata->table['indexes'])) { + $array['indexes'] = $metadata->table['indexes']; + } + + if ($metadata->customRepositoryClassName) { + $array['repositoryClass'] = $metadata->customRepositoryClassName; + } + + if (isset($metadata->table['uniqueConstraints'])) { + $array['uniqueConstraints'] = $metadata->table['uniqueConstraints']; + } + + $fieldMappings = $metadata->fieldMappings; + + $ids = array(); + foreach ($fieldMappings as $name => $fieldMapping) { + $fieldMapping['column'] = $fieldMapping['columnName']; + unset( + $fieldMapping['columnName'], + $fieldMapping['fieldName'] + ); + + if ($fieldMapping['column'] == $name) { + unset($fieldMapping['column']); + } + + if (isset($fieldMapping['id']) && $fieldMapping['id']) { + $ids[$name] = $fieldMapping; + unset($fieldMappings[$name]); + continue; + } + + $fieldMappings[$name] = $fieldMapping; + } + + if ( ! $metadata->isIdentifierComposite && $idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) { + $ids[$metadata->getSingleIdentifierFieldName()]['generator']['strategy'] = $idGeneratorType; + } + + if ($ids) { + $array['fields'] = $ids; + } + + if ($fieldMappings) { + if ( ! isset($array['fields'])) { + $array['fields'] = array(); + } + $array['fields'] = array_merge($array['fields'], $fieldMappings); + } + + foreach ($metadata->associationMappings as $name => $associationMapping) { + $cascade = array(); + if ($associationMapping['isCascadeRemove']) { + $cascade[] = 'remove'; + } + if ($associationMapping['isCascadePersist']) { + $cascade[] = 'persist'; + } + if ($associationMapping['isCascadeRefresh']) { + $cascade[] = 'refresh'; + } + if ($associationMapping['isCascadeMerge']) { + $cascade[] = 'merge'; + } + if ($associationMapping['isCascadeDetach']) { + $cascade[] = 'detach'; + } + if (count($cascade) === 5) { + $cascade = array('all'); + } + $associationMappingArray = array( + 'targetEntity' => $associationMapping['targetEntity'], + 'cascade' => $cascade, + ); + + if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) { + $joinColumns = $associationMapping['joinColumns']; + $newJoinColumns = array(); + foreach ($joinColumns as $joinColumn) { + $newJoinColumns[$joinColumn['name']]['referencedColumnName'] = $joinColumn['referencedColumnName']; + if (isset($joinColumn['onDelete'])) { + $newJoinColumns[$joinColumn['name']]['onDelete'] = $joinColumn['onDelete']; + } + } + $oneToOneMappingArray = array( + 'mappedBy' => $associationMapping['mappedBy'], + 'inversedBy' => $associationMapping['inversedBy'], + 'joinColumns' => $newJoinColumns, + 'orphanRemoval' => $associationMapping['orphanRemoval'], + ); + + $associationMappingArray = array_merge($associationMappingArray, $oneToOneMappingArray); + + if ($associationMapping['type'] & ClassMetadataInfo::ONE_TO_ONE) { + $array['oneToOne'][$name] = $associationMappingArray; + } else { + $array['manyToOne'][$name] = $associationMappingArray; + } + + } else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) { + $oneToManyMappingArray = array( + 'mappedBy' => $associationMapping['mappedBy'], + 'inversedBy' => $associationMapping['inversedBy'], + 'orphanRemoval' => $associationMapping['orphanRemoval'], + 'orderBy' => isset($associationMapping['orderBy']) ? $associationMapping['orderBy'] : null + ); + + $associationMappingArray = array_merge($associationMappingArray, $oneToManyMappingArray); + $array['oneToMany'][$name] = $associationMappingArray; + } else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_MANY) { + $manyToManyMappingArray = array( + 'mappedBy' => $associationMapping['mappedBy'], + 'inversedBy' => $associationMapping['inversedBy'], + 'joinTable' => isset($associationMapping['joinTable']) ? $associationMapping['joinTable'] : null, + 'orderBy' => isset($associationMapping['orderBy']) ? $associationMapping['orderBy'] : null + ); + + $associationMappingArray = array_merge($associationMappingArray, $manyToManyMappingArray); + $array['manyToMany'][$name] = $associationMappingArray; + } + } + if (isset($metadata->lifecycleCallbacks)) { + $array['lifecycleCallbacks'] = $metadata->lifecycleCallbacks; + } + + return \Symfony\Component\Yaml\Yaml::dump(array($metadata->name => $array), 10); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/ExportException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/ExportException.php new file mode 100644 index 0000000..5ba8bd2 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Export/ExportException.php @@ -0,0 +1,23 @@ + FROM ()) + * + * Works with composite keys but cannot deal with queries that have multiple + * root entities (e.g. `SELECT f, b from Foo, Bar`) + * + * @author Sander Marechal + */ +class CountOutputWalker extends SqlWalker +{ + /** + * @var Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $platform; + + /** + * @var Doctrine\ORM\Query\ResultSetMapping + */ + private $rsm; + + /** + * @var array + */ + private $queryComponents; + + /** + * Constructor. Stores various parameters that are otherwise unavailable + * because Doctrine\ORM\Query\SqlWalker keeps everything private without + * accessors. + * + * @param Doctrine\ORM\Query $query + * @param Doctrine\ORM\Query\ParserResult $parserResult + * @param array $queryComponents + */ + public function __construct($query, $parserResult, array $queryComponents) + { + $this->platform = $query->getEntityManager()->getConnection()->getDatabasePlatform(); + $this->rsm = $parserResult->getResultSetMapping(); + $this->queryComponents = $queryComponents; + + parent::__construct($query, $parserResult, $queryComponents); + } + + /** + * Walks down a SelectStatement AST node, wrapping it in a COUNT (SELECT DISTINCT) + * + * Note that the ORDER BY clause is not removed. Many SQL implementations (e.g. MySQL) + * are able to cache subqueries. By keeping the ORDER BY clause intact, the limitSubQuery + * that will most likely be executed next can be read from the native SQL cache. + * + * @param SelectStatement $AST + * @return string + */ + public function walkSelectStatement(SelectStatement $AST) + { + $sql = parent::walkSelectStatement($AST); + + // Find out the SQL alias of the identifier column of the root entity + // It may be possible to make this work with multiple root entities but that + // would probably require issuing multiple queries or doing a UNION SELECT + // so for now, It's not supported. + + // Get the root entity and alias from the AST fromClause + $from = $AST->fromClause->identificationVariableDeclarations; + if (count($from) > 1) { + throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction"); + } + + $rootAlias = $from[0]->rangeVariableDeclaration->aliasIdentificationVariable; + $rootClass = $this->queryComponents[$rootAlias]['metadata']; + $rootIdentifier = $rootClass->identifier; + + // For every identifier, find out the SQL alias by combing through the ResultSetMapping + $sqlIdentifier = array(); + foreach ($rootIdentifier as $property) { + if (isset($rootClass->fieldMappings[$property])) { + foreach (array_keys($this->rsm->fieldMappings, $property) as $alias) { + if ($this->rsm->columnOwnerMap[$alias] == $rootAlias) { + $sqlIdentifier[$property] = $alias; + } + } + } + + if (isset($rootClass->associationMappings[$property])) { + $joinColumn = $rootClass->associationMappings[$property]['joinColumns'][0]['name']; + + foreach (array_keys($this->rsm->metaMappings, $joinColumn) as $alias) { + if ($this->rsm->columnOwnerMap[$alias] == $rootAlias) { + $sqlIdentifier[$property] = $alias; + } + } + } + } + + if (count($rootIdentifier) != count($sqlIdentifier)) { + throw new \RuntimeException(sprintf( + 'Not all identifier properties can be found in the ResultSetMapping: %s', + implode(', ', array_diff($rootIdentifier, array_keys($sqlIdentifier))) + )); + } + + // Build the counter query + return sprintf('SELECT %s AS dctrn_count FROM (SELECT DISTINCT %s FROM (%s) dctrn_result) dctrn_table', + $this->platform->getCountExpression('*'), + implode(', ', $sqlIdentifier), + $sql + ); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/CountWalker.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/CountWalker.php new file mode 100644 index 0000000..0fc7e75 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/CountWalker.php @@ -0,0 +1,90 @@ + + * @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/) + * @license http://hobodave.com/license.txt New BSD License + */ +class CountWalker extends TreeWalkerAdapter +{ + /** + * Distinct mode hint name + */ + const HINT_DISTINCT = 'doctrine_paginator.distinct'; + + /** + * Walks down a SelectStatement AST node, modifying it to retrieve a COUNT + * + * @param SelectStatement $AST + * @return void + */ + public function walkSelectStatement(SelectStatement $AST) + { + if ($AST->havingClause) { + throw new \RuntimeException('Cannot count query that uses a HAVING clause. Use the output walkers for pagination'); + } + + $rootComponents = array(); + foreach ($this->_getQueryComponents() as $dqlAlias => $qComp) { + $isParent = array_key_exists('parent', $qComp) + && $qComp['parent'] === null + && $qComp['nestingLevel'] == 0 + ; + if ($isParent) { + $rootComponents[] = array($dqlAlias => $qComp); + } + } + if (count($rootComponents) > 1) { + throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction"); + } + $root = reset($rootComponents); + $parentName = key($root); + $parent = current($root); + $identifierFieldName = $parent['metadata']->getSingleIdentifierFieldName(); + + $pathType = PathExpression::TYPE_STATE_FIELD; + if (isset($parent['metadata']->associationMappings[$identifierFieldName])) { + $pathType = PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; + } + + $pathExpression = new PathExpression( + PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName, + $identifierFieldName + ); + $pathExpression->type = $pathType; + + $distinct = $this->_getQuery()->getHint(self::HINT_DISTINCT); + $AST->selectClause->selectExpressions = array( + new SelectExpression( + new AggregateExpression('count', $pathExpression, $distinct), null + ) + ); + + // ORDER BY is not needed, only increases query execution through unnecessary sorting. + $AST->orderByClause = null; + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php new file mode 100644 index 0000000..2c79a5a --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php @@ -0,0 +1,153 @@ + FROM () LIMIT x OFFSET y + * + * Works with composite keys but cannot deal with queries that have multiple + * root entities (e.g. `SELECT f, b from Foo, Bar`) + * + * @author Sander Marechal + */ +class LimitSubqueryOutputWalker extends SqlWalker +{ + /** + * @var Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $platform; + + /** + * @var Doctrine\ORM\Query\ResultSetMapping + */ + private $rsm; + + /** + * @var array + */ + private $queryComponents; + + /** + * @var int + */ + private $firstResult; + + /** + * @var int + */ + private $maxResults; + + /** + * Constructor. Stores various parameters that are otherwise unavailable + * because Doctrine\ORM\Query\SqlWalker keeps everything private without + * accessors. + * + * @param Doctrine\ORM\Query $query + * @param Doctrine\ORM\Query\ParserResult $parserResult + * @param array $queryComponents + */ + public function __construct($query, $parserResult, array $queryComponents) + { + $this->platform = $query->getEntityManager()->getConnection()->getDatabasePlatform(); + $this->rsm = $parserResult->getResultSetMapping(); + $this->queryComponents = $queryComponents; + + // Reset limit and offset + $this->firstResult = $query->getFirstResult(); + $this->maxResults = $query->getMaxResults(); + $query->setFirstResult(null)->setMaxResults(null); + + parent::__construct($query, $parserResult, $queryComponents); + } + + /** + * Walks down a SelectStatement AST node, wrapping it in a SELECT DISTINCT + * + * @param SelectStatement $AST + * @return string + */ + public function walkSelectStatement(SelectStatement $AST) + { + $sql = parent::walkSelectStatement($AST); + + // Find out the SQL alias of the identifier column of the root entity + // It may be possible to make this work with multiple root entities but that + // would probably require issuing multiple queries or doing a UNION SELECT + // so for now, It's not supported. + + // Get the root entity and alias from the AST fromClause + $from = $AST->fromClause->identificationVariableDeclarations; + if (count($from) !== 1) { + throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction"); + } + + $rootAlias = $from[0]->rangeVariableDeclaration->aliasIdentificationVariable; + $rootClass = $this->queryComponents[$rootAlias]['metadata']; + $rootIdentifier = $rootClass->identifier; + + // For every identifier, find out the SQL alias by combing through the ResultSetMapping + $sqlIdentifier = array(); + foreach ($rootIdentifier as $property) { + if (isset($rootClass->fieldMappings[$property])) { + foreach (array_keys($this->rsm->fieldMappings, $property) as $alias) { + if ($this->rsm->columnOwnerMap[$alias] == $rootAlias) { + $sqlIdentifier[$property] = $alias; + } + } + } + + if (isset($rootClass->associationMappings[$property])) { + $joinColumn = $rootClass->associationMappings[$property]['joinColumns'][0]['name']; + + foreach (array_keys($this->rsm->metaMappings, $joinColumn) as $alias) { + if ($this->rsm->columnOwnerMap[$alias] == $rootAlias) { + $sqlIdentifier[$property] = $alias; + } + } + } + } + + if (count($rootIdentifier) != count($sqlIdentifier)) { + throw new \RuntimeException(sprintf( + 'Not all identifier properties can be found in the ResultSetMapping: %s', + implode(', ', array_diff($rootIdentifier, array_keys($sqlIdentifier))) + )); + } + + // Build the counter query + $sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result', + implode(', ', $sqlIdentifier), $sql); + + // Apply the limit and offset + $sql = $this->platform->modifyLimitQuery( + $sql, $this->maxResults, $this->firstResult + ); + + // Add the columns to the ResultSetMapping. It's not really nice but + // it works. Preferably I'd clear the RSM or simply create a new one + // but that is not possible from inside the output walker, so we dirty + // up the one we have. + foreach ($sqlIdentifier as $property => $alias) { + $this->rsm->addScalarResult($alias, $property); + } + + return $sql; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php new file mode 100644 index 0000000..1ae74f4 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php @@ -0,0 +1,119 @@ + + * @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/) + * @license http://hobodave.com/license.txt New BSD License + */ + +namespace Doctrine\ORM\Tools\Pagination; + +use Doctrine\DBAL\Types\Type, + Doctrine\ORM\Query\TreeWalkerAdapter, + Doctrine\ORM\Query\AST\SelectStatement, + Doctrine\ORM\Query\AST\SelectExpression, + Doctrine\ORM\Query\AST\PathExpression, + Doctrine\ORM\Query\AST\AggregateExpression; + +/** + * Replaces the selectClause of the AST with a SELECT DISTINCT root.id equivalent + * + * @category DoctrineExtensions + * @package DoctrineExtensions\Paginate + * @author David Abdemoulaie + * @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/) + * @license http://hobodave.com/license.txt New BSD License + */ +class LimitSubqueryWalker extends TreeWalkerAdapter +{ + /** + * ID type hint + */ + const IDENTIFIER_TYPE = 'doctrine_paginator.id.type'; + + /** + * @var int Counter for generating unique order column aliases + */ + private $_aliasCounter = 0; + + /** + * Walks down a SelectStatement AST node, modifying it to retrieve DISTINCT ids + * of the root Entity + * + * @param SelectStatement $AST + * @return void + */ + public function walkSelectStatement(SelectStatement $AST) + { + $parent = null; + $parentName = null; + $selectExpressions = array(); + + foreach ($this->_getQueryComponents() as $dqlAlias => $qComp) { + // preserve mixed data in query for ordering + if (isset($qComp['resultVariable'])) { + $selectExpressions[] = new SelectExpression($qComp['resultVariable'], $dqlAlias); + continue; + } + + if ($qComp['parent'] === null && $qComp['nestingLevel'] == 0) { + $parent = $qComp; + $parentName = $dqlAlias; + continue; + } + } + + $identifier = $parent['metadata']->getSingleIdentifierFieldName(); + if (isset($parent['metadata']->associationMappings[$identifier])) { + throw new \RuntimeException("Paginating an entity with foreign key as identifier only works when using the Output Walkers. Call Paginator#setUseOutputWalkers(true) before iterating the paginator."); + } + + $this->_getQuery()->setHint( + self::IDENTIFIER_TYPE, + Type::getType($parent['metadata']->getTypeOfField($identifier)) + ); + + $pathExpression = new PathExpression( + PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, + $parentName, + $identifier + ); + $pathExpression->type = PathExpression::TYPE_STATE_FIELD; + + array_unshift($selectExpressions, new SelectExpression($pathExpression, '_dctrn_id')); + $AST->selectClause->selectExpressions = $selectExpressions; + + if (isset($AST->orderByClause)) { + foreach ($AST->orderByClause->orderByItems as $item) { + if ($item->expression instanceof PathExpression) { + $pathExpression = new PathExpression( + PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, + $item->expression->identificationVariable, + $item->expression->field + ); + $pathExpression->type = PathExpression::TYPE_STATE_FIELD; + $AST->selectClause->selectExpressions[] = new SelectExpression( + $pathExpression, + '_dctrn_ord' . $this->_aliasCounter++ + ); + } + } + } + + $AST->selectClause->isDistinct = true; + } + +} + + + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/Paginator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/Paginator.php new file mode 100644 index 0000000..16c9dcf --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/Paginator.php @@ -0,0 +1,239 @@ +. + */ + +namespace Doctrine\ORM\Tools\Pagination; + +use Doctrine\ORM\QueryBuilder, + Doctrine\ORM\Query, + Doctrine\ORM\Query\ResultSetMapping, + Doctrine\ORM\NoResultException; + +/** + * Paginator + * + * The paginator can handle various complex scenarios with DQL. + * + * @author Pablo Díez + * @author Benjamin Eberlei + * @license New BSD + */ +class Paginator implements \Countable, \IteratorAggregate +{ + /** + * @var Query + */ + private $query; + + /** + * @var bool + */ + private $fetchJoinCollection; + + /** + * @var bool|null + */ + private $useOutputWalkers; + + /** + * @var int + */ + private $count; + + /** + * Constructor. + * + * @param Query|QueryBuilder $query A Doctrine ORM query or query builder. + * @param Boolean $fetchJoinCollection Whether the query joins a collection (true by default). + */ + public function __construct($query, $fetchJoinCollection = true) + { + if ($query instanceof QueryBuilder) { + $query = $query->getQuery(); + } + + $this->query = $query; + $this->fetchJoinCollection = (Boolean) $fetchJoinCollection; + } + + /** + * Returns the query + * + * @return Query + */ + public function getQuery() + { + return $this->query; + } + + /** + * Returns whether the query joins a collection. + * + * @return Boolean Whether the query joins a collection. + */ + public function getFetchJoinCollection() + { + return $this->fetchJoinCollection; + } + + /** + * Returns whether the paginator will use an output walker + * + * @return bool|null + */ + public function getUseOutputWalkers() + { + return $this->useOutputWalkers; + } + + /** + * Set whether the paginator will use an output walker + * + * @param bool|null $useOutputWalkers + * @return $this + */ + public function setUseOutputWalkers($useOutputWalkers) + { + $this->useOutputWalkers = $useOutputWalkers; + return $this; + } + + /** + * {@inheritdoc} + */ + public function count() + { + if ($this->count === null) { + /* @var $countQuery Query */ + $countQuery = $this->cloneQuery($this->query); + + if ( ! $countQuery->getHint(CountWalker::HINT_DISTINCT)) { + $countQuery->setHint(CountWalker::HINT_DISTINCT, true); + } + + if ($this->useOutputWalker($countQuery)) { + $platform = $countQuery->getEntityManager()->getConnection()->getDatabasePlatform(); // law of demeter win + + $rsm = new ResultSetMapping(); + $rsm->addScalarResult($platform->getSQLResultCasing('dctrn_count'), 'count'); + + $countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker'); + $countQuery->setResultSetMapping($rsm); + } else { + $countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker')); + } + + $countQuery->setFirstResult(null)->setMaxResults(null); + + try { + $data = $countQuery->getScalarResult(); + $data = array_map('current', $data); + $this->count = array_sum($data); + } catch(NoResultException $e) { + $this->count = 0; + } + } + return $this->count; + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + $offset = $this->query->getFirstResult(); + $length = $this->query->getMaxResults(); + + if ($this->fetchJoinCollection) { + $subQuery = $this->cloneQuery($this->query); + + if ($this->useOutputWalker($subQuery)) { + $subQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker'); + } else { + $subQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker')); + } + + $subQuery->setFirstResult($offset)->setMaxResults($length); + + $ids = array_map('current', $subQuery->getScalarResult()); + + $whereInQuery = $this->cloneQuery($this->query); + // don't do this for an empty id array + if (count($ids) == 0) { + return new \ArrayIterator(array()); + } + + $namespace = WhereInWalker::PAGINATOR_ID_ALIAS; + + $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker')); + $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, count($ids)); + $whereInQuery->setFirstResult(null)->setMaxResults(null); + foreach ($ids as $i => $id) { + $i++; + $whereInQuery->setParameter("{$namespace}_{$i}", $id); + } + + $result = $whereInQuery->getResult($this->query->getHydrationMode()); + } else { + $result = $this->cloneQuery($this->query) + ->setMaxResults($length) + ->setFirstResult($offset) + ->getResult($this->query->getHydrationMode()) + ; + } + return new \ArrayIterator($result); + } + + /** + * Clones a query. + * + * @param Query $query The query. + * + * @return Query The cloned query. + */ + private function cloneQuery(Query $query) + { + /* @var $cloneQuery Query */ + $cloneQuery = clone $query; + + $cloneQuery->setParameters(clone $query->getParameters()); + + foreach ($query->getHints() as $name => $value) { + $cloneQuery->setHint($name, $value); + } + + return $cloneQuery; + } + + /** + * Determine whether to use an output walker for the query + * + * @param Query $query The query. + * + * @return bool + */ + private function useOutputWalker(Query $query) + { + if ($this->useOutputWalkers === null) { + return (Boolean) $query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER) == false; + } + + return $this->useOutputWalkers; + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php new file mode 100644 index 0000000..9b919e6 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php @@ -0,0 +1,148 @@ + + * @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/) + * @license http://hobodave.com/license.txt New BSD License + */ + +namespace Doctrine\ORM\Tools\Pagination; + +use Doctrine\ORM\Query\AST\ArithmeticExpression, + Doctrine\ORM\Query\AST\SimpleArithmeticExpression, + Doctrine\ORM\Query\TreeWalkerAdapter, + Doctrine\ORM\Query\AST\SelectStatement, + Doctrine\ORM\Query\AST\PathExpression, + Doctrine\ORM\Query\AST\InExpression, + Doctrine\ORM\Query\AST\NullComparisonExpression, + Doctrine\ORM\Query\AST\InputParameter, + Doctrine\ORM\Query\AST\ConditionalPrimary, + Doctrine\ORM\Query\AST\ConditionalTerm, + Doctrine\ORM\Query\AST\ConditionalExpression, + Doctrine\ORM\Query\AST\ConditionalFactor, + Doctrine\ORM\Query\AST\WhereClause; + +/** + * Replaces the whereClause of the AST with a WHERE id IN (:foo_1, :foo_2) equivalent + * + * @category DoctrineExtensions + * @package DoctrineExtensions\Paginate + * @author David Abdemoulaie + * @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/) + * @license http://hobodave.com/license.txt New BSD License + */ +class WhereInWalker extends TreeWalkerAdapter +{ + /** + * ID Count hint name + */ + const HINT_PAGINATOR_ID_COUNT = 'doctrine.id.count'; + + /** + * Primary key alias for query + */ + const PAGINATOR_ID_ALIAS = 'dpid'; + + /** + * Replaces the whereClause in the AST + * + * Generates a clause equivalent to WHERE IN (:dpid_1, :dpid_2, ...) + * + * The parameter namespace (dpid) is defined by + * the PAGINATOR_ID_ALIAS + * + * The total number of parameters is retrieved from + * the HINT_PAGINATOR_ID_COUNT query hint + * + * @param SelectStatement $AST + * @return void + */ + public function walkSelectStatement(SelectStatement $AST) + { + $rootComponents = array(); + foreach ($this->_getQueryComponents() as $dqlAlias => $qComp) { + $isParent = array_key_exists('parent', $qComp) + && $qComp['parent'] === null + && $qComp['nestingLevel'] == 0 + ; + if ($isParent) { + $rootComponents[] = array($dqlAlias => $qComp); + } + } + if (count($rootComponents) > 1) { + throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction"); + } + $root = reset($rootComponents); + $parentName = key($root); + $parent = current($root); + $identifierFieldName = $parent['metadata']->getSingleIdentifierFieldName(); + + $pathType = PathExpression::TYPE_STATE_FIELD; + if (isset($parent['metadata']->associationMappings[$identifierFieldName])) { + $pathType = PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; + } + + $pathExpression = new PathExpression(PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName, $identifierFieldName); + $pathExpression->type = $pathType; + + $count = $this->_getQuery()->getHint(self::HINT_PAGINATOR_ID_COUNT); + + if ($count > 0) { + $arithmeticExpression = new ArithmeticExpression(); + $arithmeticExpression->simpleArithmeticExpression = new SimpleArithmeticExpression( + array($pathExpression) + ); + $expression = new InExpression($arithmeticExpression); + $ns = self::PAGINATOR_ID_ALIAS; + + for ($i = 1; $i <= $count; $i++) { + $expression->literals[] = new InputParameter(":{$ns}_$i"); + } + } else { + $expression = new NullComparisonExpression($pathExpression); + $expression->not = false; + } + + $conditionalPrimary = new ConditionalPrimary; + $conditionalPrimary->simpleConditionalExpression = $expression; + if ($AST->whereClause) { + if ($AST->whereClause->conditionalExpression instanceof ConditionalTerm) { + $AST->whereClause->conditionalExpression->conditionalFactors[] = $conditionalPrimary; + } elseif ($AST->whereClause->conditionalExpression instanceof ConditionalPrimary) { + $AST->whereClause->conditionalExpression = new ConditionalExpression(array( + new ConditionalTerm(array( + $AST->whereClause->conditionalExpression, + $conditionalPrimary + )) + )); + } elseif ($AST->whereClause->conditionalExpression instanceof ConditionalExpression + || $AST->whereClause->conditionalExpression instanceof ConditionalFactor + ) { + $tmpPrimary = new ConditionalPrimary; + $tmpPrimary->conditionalExpression = $AST->whereClause->conditionalExpression; + $AST->whereClause->conditionalExpression = new ConditionalTerm(array( + $tmpPrimary, + $conditionalPrimary + )); + } + } else { + $AST->whereClause = new WhereClause( + new ConditionalExpression(array( + new ConditionalTerm(array( + $conditionalPrimary + )) + )) + ); + } + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php new file mode 100644 index 0000000..45eae26 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php @@ -0,0 +1,94 @@ +. + */ + +namespace Doctrine\ORM\Tools; + +use Doctrine\ORM\Event\LoadClassMetadataEventArgs; +use Doctrine\ORM\Mapping\ClassMetadata; + +/** + * ResolveTargetEntityListener + * + * Mechanism to overwrite interfaces or classes specified as association + * targets. + * + * @author Benjamin Eberlei + * @since 2.2 + */ +class ResolveTargetEntityListener +{ + /** + * @var array + */ + private $resolveTargetEntities = array(); + + /** + * Add a target-entity class name to resolve to a new class name. + * + * @param string $originalEntity + * @param string $newEntity + * @param array $mapping + * @return void + */ + public function addResolveTargetEntity($originalEntity, $newEntity, array $mapping) + { + $mapping['targetEntity'] = ltrim($newEntity, "\\"); + $this->resolveTargetEntities[ltrim($originalEntity, "\\")] = $mapping; + } + + /** + * Process event and resolve new target entity names. + * + * @param LoadClassMetadataEventArgs $args + * @return void + */ + public function loadClassMetadata(LoadClassMetadataEventArgs $args) + { + $cm = $args->getClassMetadata(); + foreach ($cm->associationMappings as $mapping) { + if (isset($this->resolveTargetEntities[$mapping['targetEntity']])) { + $this->remapAssociation($cm, $mapping); + } + } + } + + private function remapAssociation($classMetadata, $mapping) + { + $newMapping = $this->resolveTargetEntities[$mapping['targetEntity']]; + $newMapping = array_replace_recursive($mapping, $newMapping); + $newMapping['fieldName'] = $mapping['fieldName']; + unset($classMetadata->associationMappings[$mapping['fieldName']]); + + switch ($mapping['type']) { + case ClassMetadata::MANY_TO_MANY: + $classMetadata->mapManyToMany($newMapping); + break; + case ClassMetadata::MANY_TO_ONE: + $classMetadata->mapManyToOne($newMapping); + break; + case ClassMetadata::ONE_TO_MANY: + $classMetadata->mapOneToMany($newMapping); + break; + case ClassMetadata::ONE_TO_ONE: + $classMetadata->mapOneToOne($newMapping); + break; + } + } +} + diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/SchemaTool.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/SchemaTool.php new file mode 100644 index 0000000..23a361e --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/SchemaTool.php @@ -0,0 +1,722 @@ +. + */ + +namespace Doctrine\ORM\Tools; + +use Doctrine\ORM\ORMException, + Doctrine\DBAL\Types\Type, + Doctrine\DBAL\Schema\Schema, + Doctrine\DBAL\Schema\Visitor\RemoveNamespacedAssets, + Doctrine\ORM\EntityManager, + Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\Internal\CommitOrderCalculator, + Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs, + Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs; + +/** + * The SchemaTool is a tool to create/drop/update database schemas based on + * ClassMetadata class descriptors. + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Benjamin Eberlei + */ +class SchemaTool +{ + /** + * @var \Doctrine\ORM\EntityManager + */ + private $em; + + /** + * @var \Doctrine\DBAL\Platforms\AbstractPlatform + */ + private $platform; + + /** + * The quote strategy. + * + * @var \Doctrine\ORM\Mapping\QuoteStrategy + */ + private $quoteStrategy; + + /** + * Initializes a new SchemaTool instance that uses the connection of the + * provided EntityManager. + * + * @param \Doctrine\ORM\EntityManager $em + */ + public function __construct(EntityManager $em) + { + $this->em = $em; + $this->platform = $em->getConnection()->getDatabasePlatform(); + $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); + } + + /** + * Creates the database schema for the given array of ClassMetadata instances. + * + * @throws ToolsException + * @param array $classes + * @return void + */ + public function createSchema(array $classes) + { + $createSchemaSql = $this->getCreateSchemaSql($classes); + $conn = $this->em->getConnection(); + + foreach ($createSchemaSql as $sql) { + try { + $conn->executeQuery($sql); + } catch(\Exception $e) { + throw ToolsException::schemaToolFailure($sql, $e); + } + } + } + + /** + * Gets the list of DDL statements that are required to create the database schema for + * the given list of ClassMetadata instances. + * + * @param array $classes + * @return array $sql The SQL statements needed to create the schema for the classes. + */ + public function getCreateSchemaSql(array $classes) + { + $schema = $this->getSchemaFromMetadata($classes); + return $schema->toSql($this->platform); + } + + /** + * Some instances of ClassMetadata don't need to be processed in the SchemaTool context. This method detects them. + * + * @param ClassMetadata $class + * @param array $processedClasses + * @return bool + */ + private function processingNotRequired($class, array $processedClasses) + { + return ( + isset($processedClasses[$class->name]) || + $class->isMappedSuperclass || + ($class->isInheritanceTypeSingleTable() && $class->name != $class->rootEntityName) + ); + } + + /** + * From a given set of metadata classes this method creates a Schema instance. + * + * @param array $classes + * @return Schema + */ + public function getSchemaFromMetadata(array $classes) + { + // Reminder for processed classes, used for hierarchies + $processedClasses = array(); + $eventManager = $this->em->getEventManager(); + $schemaManager = $this->em->getConnection()->getSchemaManager(); + $metadataSchemaConfig = $schemaManager->createSchemaConfig(); + + $metadataSchemaConfig->setExplicitForeignKeyIndexes(false); + $schema = new Schema(array(), array(), $metadataSchemaConfig); + + foreach ($classes as $class) { + if ($this->processingNotRequired($class, $processedClasses)) { + continue; + } + + $table = $schema->createTable($this->quoteStrategy->getTableName($class, $this->platform)); + $columns = array(); // table columns + + if ($class->isInheritanceTypeSingleTable()) { + $columns = $this->_gatherColumns($class, $table); + $this->_gatherRelationsSql($class, $table, $schema); + + // Add the discriminator column + $this->addDiscriminatorColumnDefinition($class, $table); + + // Aggregate all the information from all classes in the hierarchy + foreach ($class->parentClasses as $parentClassName) { + // Parent class information is already contained in this class + $processedClasses[$parentClassName] = true; + } + + foreach ($class->subClasses as $subClassName) { + $subClass = $this->em->getClassMetadata($subClassName); + $this->_gatherColumns($subClass, $table); + $this->_gatherRelationsSql($subClass, $table, $schema); + $processedClasses[$subClassName] = true; + } + } else if ($class->isInheritanceTypeJoined()) { + // Add all non-inherited fields as columns + $pkColumns = array(); + foreach ($class->fieldMappings as $fieldName => $mapping) { + if ( ! isset($mapping['inherited'])) { + $columnName = $this->quoteStrategy->getColumnName($mapping['fieldName'], $class, $this->platform); + $this->_gatherColumn($class, $mapping, $table); + + if ($class->isIdentifier($fieldName)) { + $pkColumns[] = $columnName; + } + } + } + + $this->_gatherRelationsSql($class, $table, $schema); + + // Add the discriminator column only to the root table + if ($class->name == $class->rootEntityName) { + $this->addDiscriminatorColumnDefinition($class, $table); + } else { + // Add an ID FK column to child tables + /* @var \Doctrine\ORM\Mapping\ClassMetadata $class */ + $idMapping = $class->fieldMappings[$class->identifier[0]]; + $this->_gatherColumn($class, $idMapping, $table); + $columnName = $this->quoteStrategy->getColumnName($class->identifier[0], $class, $this->platform); + // TODO: This seems rather hackish, can we optimize it? + $table->getColumn($columnName)->setAutoincrement(false); + + $pkColumns[] = $columnName; + + // Add a FK constraint on the ID column + $table->addUnnamedForeignKeyConstraint( + $this->quoteStrategy->getTableName($this->em->getClassMetadata($class->rootEntityName), $this->platform), + array($columnName), array($columnName), array('onDelete' => 'CASCADE') + ); + } + + $table->setPrimaryKey($pkColumns); + + } else if ($class->isInheritanceTypeTablePerClass()) { + throw ORMException::notSupported(); + } else { + $this->_gatherColumns($class, $table); + $this->_gatherRelationsSql($class, $table, $schema); + } + + $pkColumns = array(); + foreach ($class->identifier as $identifierField) { + if (isset($class->fieldMappings[$identifierField])) { + $pkColumns[] = $this->quoteStrategy->getColumnName($identifierField, $class, $this->platform); + } else if (isset($class->associationMappings[$identifierField])) { + /* @var $assoc \Doctrine\ORM\Mapping\OneToOne */ + $assoc = $class->associationMappings[$identifierField]; + foreach ($assoc['joinColumns'] as $joinColumn) { + $pkColumns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + } + } + } + + if ( ! $table->hasIndex('primary')) { + $table->setPrimaryKey($pkColumns); + } + + if (isset($class->table['indexes'])) { + foreach ($class->table['indexes'] as $indexName => $indexData) { + $table->addIndex($indexData['columns'], is_numeric($indexName) ? null : $indexName); + } + } + + if (isset($class->table['uniqueConstraints'])) { + foreach ($class->table['uniqueConstraints'] as $indexName => $indexData) { + $table->addUniqueIndex($indexData['columns'], is_numeric($indexName) ? null : $indexName); + } + } + + if (isset($class->table['options'])) { + foreach ($class->table['options'] as $key => $val) { + $table->addOption($key, $val); + } + } + + $processedClasses[$class->name] = true; + + if ($class->isIdGeneratorSequence() && $class->name == $class->rootEntityName) { + $seqDef = $class->sequenceGeneratorDefinition; + $quotedName = $this->quoteStrategy->getSequenceName($seqDef, $class, $this->platform); + if ( ! $schema->hasSequence($quotedName)) { + $schema->createSequence( + $quotedName, + $seqDef['allocationSize'], + $seqDef['initialValue'] + ); + } + } + + if ($eventManager->hasListeners(ToolEvents::postGenerateSchemaTable)) { + $eventManager->dispatchEvent(ToolEvents::postGenerateSchemaTable, new GenerateSchemaTableEventArgs($class, $schema, $table)); + } + } + + if ( ! $this->platform->supportsSchemas() && ! $this->platform->canEmulateSchemas() ) { + $schema->visit(new RemoveNamespacedAssets()); + } + + if ($eventManager->hasListeners(ToolEvents::postGenerateSchema)) { + $eventManager->dispatchEvent(ToolEvents::postGenerateSchema, new GenerateSchemaEventArgs($this->em, $schema)); + } + + return $schema; + } + + /** + * Gets a portable column definition as required by the DBAL for the discriminator + * column of a class. + * + * @param ClassMetadata $class + * @return array The portable column definition of the discriminator column as required by + * the DBAL. + */ + private function addDiscriminatorColumnDefinition($class, $table) + { + $discrColumn = $class->discriminatorColumn; + + if ( ! isset($discrColumn['type']) || (strtolower($discrColumn['type']) == 'string' && $discrColumn['length'] === null)) { + $discrColumn['type'] = 'string'; + $discrColumn['length'] = 255; + } + + $options = array( + 'length' => isset($discrColumn['length']) ? $discrColumn['length'] : null, + 'notnull' => true + ); + + if (isset($discrColumn['columnDefinition'])) { + $options['columnDefinition'] = $discrColumn['columnDefinition']; + } + + $table->addColumn($discrColumn['name'], $discrColumn['type'], $options); + } + + /** + * Gathers the column definitions as required by the DBAL of all field mappings + * found in the given class. + * + * @param ClassMetadata $class + * @param Table $table + * @return array The list of portable column definitions as required by the DBAL. + */ + private function _gatherColumns($class, $table) + { + $columns = array(); + $pkColumns = array(); + + foreach ($class->fieldMappings as $fieldName => $mapping) { + if ($class->isInheritanceTypeSingleTable() && isset($mapping['inherited'])) { + continue; + } + + $column = $this->_gatherColumn($class, $mapping, $table); + + if ($class->isIdentifier($mapping['fieldName'])) { + $pkColumns[] = $this->quoteStrategy->getColumnName($mapping['fieldName'], $class, $this->platform); + } + } + + // For now, this is a hack required for single table inheritence, since this method is called + // twice by single table inheritence relations + if(!$table->hasIndex('primary')) { + //$table->setPrimaryKey($pkColumns); + } + + return $columns; + } + + /** + * Creates a column definition as required by the DBAL from an ORM field mapping definition. + * + * @param ClassMetadata $class The class that owns the field mapping. + * @param array $mapping The field mapping. + * @param Table $table + * @return array The portable column definition as required by the DBAL. + */ + private function _gatherColumn($class, array $mapping, $table) + { + $columnName = $this->quoteStrategy->getColumnName($mapping['fieldName'], $class, $this->platform); + $columnType = $mapping['type']; + + $options = array(); + $options['length'] = isset($mapping['length']) ? $mapping['length'] : null; + $options['notnull'] = isset($mapping['nullable']) ? ! $mapping['nullable'] : true; + if ($class->isInheritanceTypeSingleTable() && count($class->parentClasses) > 0) { + $options['notnull'] = false; + } + + $options['platformOptions'] = array(); + $options['platformOptions']['version'] = $class->isVersioned && $class->versionField == $mapping['fieldName'] ? true : false; + + if(strtolower($columnType) == 'string' && $options['length'] === null) { + $options['length'] = 255; + } + + if (isset($mapping['precision'])) { + $options['precision'] = $mapping['precision']; + } + + if (isset($mapping['scale'])) { + $options['scale'] = $mapping['scale']; + } + + if (isset($mapping['default'])) { + $options['default'] = $mapping['default']; + } + + if (isset($mapping['columnDefinition'])) { + $options['columnDefinition'] = $mapping['columnDefinition']; + } + + if (isset($mapping['options'])) { + $options['customSchemaOptions'] = $mapping['options']; + } + + if ($class->isIdGeneratorIdentity() && $class->getIdentifierFieldNames() == array($mapping['fieldName'])) { + $options['autoincrement'] = true; + } + if ($class->isInheritanceTypeJoined() && $class->name != $class->rootEntityName) { + $options['autoincrement'] = false; + } + + if ($table->hasColumn($columnName)) { + // required in some inheritance scenarios + $table->changeColumn($columnName, $options); + } else { + $table->addColumn($columnName, $columnType, $options); + } + + $isUnique = isset($mapping['unique']) ? $mapping['unique'] : false; + if ($isUnique) { + $table->addUniqueIndex(array($columnName)); + } + } + + /** + * Gathers the SQL for properly setting up the relations of the given class. + * This includes the SQL for foreign key constraints and join tables. + * + * @param ClassMetadata $class + * @param \Doctrine\DBAL\Schema\Table $table + * @param \Doctrine\DBAL\Schema\Schema $schema + * @return void + */ + private function _gatherRelationsSql($class, $table, $schema) + { + foreach ($class->associationMappings as $fieldName => $mapping) { + if (isset($mapping['inherited'])) { + continue; + } + + $foreignClass = $this->em->getClassMetadata($mapping['targetEntity']); + + if ($mapping['type'] & ClassMetadata::TO_ONE && $mapping['isOwningSide']) { + $primaryKeyColumns = $uniqueConstraints = array(); // PK is unnecessary for this relation-type + + $this->_gatherRelationJoinColumns($mapping['joinColumns'], $table, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints); + + foreach($uniqueConstraints as $indexName => $unique) { + $table->addUniqueIndex($unique['columns'], is_numeric($indexName) ? null : $indexName); + } + } else if ($mapping['type'] == ClassMetadata::ONE_TO_MANY && $mapping['isOwningSide']) { + //... create join table, one-many through join table supported later + throw ORMException::notSupported(); + } else if ($mapping['type'] == ClassMetadata::MANY_TO_MANY && $mapping['isOwningSide']) { + // create join table + $joinTable = $mapping['joinTable']; + + $theJoinTable = $schema->createTable($this->quoteStrategy->getJoinTableName($mapping, $foreignClass, $this->platform)); + + $primaryKeyColumns = $uniqueConstraints = array(); + + // Build first FK constraint (relation table => source table) + $this->_gatherRelationJoinColumns($joinTable['joinColumns'], $theJoinTable, $class, $mapping, $primaryKeyColumns, $uniqueConstraints); + + // Build second FK constraint (relation table => target table) + $this->_gatherRelationJoinColumns($joinTable['inverseJoinColumns'], $theJoinTable, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints); + + $theJoinTable->setPrimaryKey($primaryKeyColumns); + + foreach($uniqueConstraints as $indexName => $unique) { + $theJoinTable->addUniqueIndex($unique['columns'], is_numeric($indexName) ? null : $indexName); + } + } + } + } + + /** + * Get the class metadata that is responsible for the definition of the referenced column name. + * + * Previously this was a simple task, but with DDC-117 this problem is actually recursive. If its + * not a simple field, go through all identifier field names that are associations recursivly and + * find that referenced column name. + * + * TODO: Is there any way to make this code more pleasing? + * + * @param ClassMetadata $class + * @param string $referencedColumnName + * @return array(ClassMetadata, referencedFieldName) + */ + private function getDefiningClass($class, $referencedColumnName) + { + $referencedFieldName = $class->getFieldName($referencedColumnName); + + if ($class->hasField($referencedFieldName)) { + return array($class, $referencedFieldName); + } else if (in_array($referencedColumnName, $class->getIdentifierColumnNames())) { + // it seems to be an entity as foreign key + foreach ($class->getIdentifierFieldNames() as $fieldName) { + if ($class->hasAssociation($fieldName) && $class->getSingleAssociationJoinColumnName($fieldName) == $referencedColumnName) { + return $this->getDefiningClass( + $this->em->getClassMetadata($class->associationMappings[$fieldName]['targetEntity']), + $class->getSingleAssociationReferencedJoinColumnName($fieldName) + ); + } + } + } + + return null; + } + + /** + * Gather columns and fk constraints that are required for one part of relationship. + * + * @param array $joinColumns + * @param \Doctrine\DBAL\Schema\Table $theJoinTable + * @param ClassMetadata $class + * @param array $mapping + * @param array $primaryKeyColumns + * @param array $uniqueConstraints + */ + private function _gatherRelationJoinColumns($joinColumns, $theJoinTable, $class, $mapping, &$primaryKeyColumns, &$uniqueConstraints) + { + $localColumns = array(); + $foreignColumns = array(); + $fkOptions = array(); + $foreignTableName = $this->quoteStrategy->getTableName($class, $this->platform); + + foreach ($joinColumns as $joinColumn) { + + list($definingClass, $referencedFieldName) = $this->getDefiningClass($class, $joinColumn['referencedColumnName']); + + if ( ! $definingClass) { + throw new \Doctrine\ORM\ORMException( + "Column name `".$joinColumn['referencedColumnName']."` referenced for relation from ". + $mapping['sourceEntity'] . " towards ". $mapping['targetEntity'] . " does not exist." + ); + } + + $quotedColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + $quotedRefColumnName = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $class, $this->platform); + + $primaryKeyColumns[] = $quotedColumnName; + $localColumns[] = $quotedColumnName; + $foreignColumns[] = $quotedRefColumnName; + + if ( ! $theJoinTable->hasColumn($quotedColumnName)) { + // Only add the column to the table if it does not exist already. + // It might exist already if the foreign key is mapped into a regular + // property as well. + + $fieldMapping = $definingClass->getFieldMapping($referencedFieldName); + + $columnDef = null; + if (isset($joinColumn['columnDefinition'])) { + $columnDef = $joinColumn['columnDefinition']; + } else if (isset($fieldMapping['columnDefinition'])) { + $columnDef = $fieldMapping['columnDefinition']; + } + $columnOptions = array('notnull' => false, 'columnDefinition' => $columnDef); + if (isset($joinColumn['nullable'])) { + $columnOptions['notnull'] = !$joinColumn['nullable']; + } + if ($fieldMapping['type'] == "string" && isset($fieldMapping['length'])) { + $columnOptions['length'] = $fieldMapping['length']; + } else if ($fieldMapping['type'] == "decimal") { + $columnOptions['scale'] = $fieldMapping['scale']; + $columnOptions['precision'] = $fieldMapping['precision']; + } + + $theJoinTable->addColumn($quotedColumnName, $fieldMapping['type'], $columnOptions); + } + + if (isset($joinColumn['unique']) && $joinColumn['unique'] == true) { + $uniqueConstraints[] = array('columns' => array($quotedColumnName)); + } + + if (isset($joinColumn['onDelete'])) { + $fkOptions['onDelete'] = $joinColumn['onDelete']; + } + } + + $theJoinTable->addUnnamedForeignKeyConstraint( + $foreignTableName, $localColumns, $foreignColumns, $fkOptions + ); + } + + /** + * Drops the database schema for the given classes. + * + * In any way when an exception is thrown it is supressed since drop was + * issued for all classes of the schema and some probably just don't exist. + * + * @param array $classes + * @return void + */ + public function dropSchema(array $classes) + { + $dropSchemaSql = $this->getDropSchemaSQL($classes); + $conn = $this->em->getConnection(); + + foreach ($dropSchemaSql as $sql) { + try { + $conn->executeQuery($sql); + } catch(\Exception $e) { + + } + } + } + + /** + * Drops all elements in the database of the current connection. + * + * @return void + */ + public function dropDatabase() + { + $dropSchemaSql = $this->getDropDatabaseSQL(); + $conn = $this->em->getConnection(); + + foreach ($dropSchemaSql as $sql) { + $conn->executeQuery($sql); + } + } + + /** + * Gets the SQL needed to drop the database schema for the connections database. + * + * @return array + */ + public function getDropDatabaseSQL() + { + $sm = $this->em->getConnection()->getSchemaManager(); + $schema = $sm->createSchema(); + + $visitor = new \Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector($this->platform); + /* @var $schema \Doctrine\DBAL\Schema\Schema */ + $schema->visit($visitor); + return $visitor->getQueries(); + } + + /** + * Get SQL to drop the tables defined by the passed classes. + * + * @param array $classes + * @return array + */ + public function getDropSchemaSQL(array $classes) + { + $visitor = new \Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector($this->platform); + $schema = $this->getSchemaFromMetadata($classes); + + $sm = $this->em->getConnection()->getSchemaManager(); + $fullSchema = $sm->createSchema(); + foreach ($fullSchema->getTables() as $table) { + if ( ! $schema->hasTable($table->getName())) { + foreach ($table->getForeignKeys() as $foreignKey) { + /* @var $foreignKey \Doctrine\DBAL\Schema\ForeignKeyConstraint */ + if ($schema->hasTable($foreignKey->getForeignTableName())) { + $visitor->acceptForeignKey($table, $foreignKey); + } + } + } else { + $visitor->acceptTable($table); + foreach ($table->getForeignKeys() as $foreignKey) { + $visitor->acceptForeignKey($table, $foreignKey); + } + } + } + + if ($this->platform->supportsSequences()) { + foreach ($schema->getSequences() as $sequence) { + $visitor->acceptSequence($sequence); + } + foreach ($schema->getTables() as $table) { + /* @var $sequence Table */ + if ($table->hasPrimaryKey()) { + $columns = $table->getPrimaryKey()->getColumns(); + if (count($columns) == 1) { + $checkSequence = $table->getName() . "_" . $columns[0] . "_seq"; + if ($fullSchema->hasSequence($checkSequence)) { + $visitor->acceptSequence($fullSchema->getSequence($checkSequence)); + } + } + } + } + } + + return $visitor->getQueries(); + } + + /** + * Updates the database schema of the given classes by comparing the ClassMetadata + * instances to the current database schema that is inspected. If $saveMode is set + * to true the command is executed in the Database, else SQL is returned. + * + * @param array $classes + * @param boolean $saveMode + * @return void + */ + public function updateSchema(array $classes, $saveMode=false) + { + $updateSchemaSql = $this->getUpdateSchemaSql($classes, $saveMode); + $conn = $this->em->getConnection(); + + foreach ($updateSchemaSql as $sql) { + $conn->executeQuery($sql); + } + } + + /** + * Gets the sequence of SQL statements that need to be performed in order + * to bring the given class mappings in-synch with the relational schema. + * If $saveMode is set to true the command is executed in the Database, + * else SQL is returned. + * + * @param array $classes The classes to consider. + * @param boolean $saveMode True for writing to DB, false for SQL string + * @return array The sequence of SQL statements. + */ + public function getUpdateSchemaSql(array $classes, $saveMode=false) + { + $sm = $this->em->getConnection()->getSchemaManager(); + + $fromSchema = $sm->createSchema(); + $toSchema = $this->getSchemaFromMetadata($classes); + + $comparator = new \Doctrine\DBAL\Schema\Comparator(); + $schemaDiff = $comparator->compare($fromSchema, $toSchema); + + if ($saveMode) { + return $schemaDiff->toSaveSql($this->platform); + } else { + return $schemaDiff->toSql($this->platform); + } + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/SchemaValidator.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/SchemaValidator.php new file mode 100644 index 0000000..7a3f6f5 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/SchemaValidator.php @@ -0,0 +1,289 @@ +. +*/ + +namespace Doctrine\ORM\Tools; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\DBAL\Types\Type; + +/** + * Performs strict validation of the mapping schema + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class SchemaValidator +{ + /** + * @var EntityManager + */ + private $em; + + /** + * @param EntityManager $em + */ + public function __construct(EntityManager $em) + { + $this->em = $em; + } + + /** + * Checks the internal consistency of all mapping files. + * + * There are several checks that can't be done at runtime or are too expensive, which can be verified + * with this command. For example: + * + * 1. Check if a relation with "mappedBy" is actually connected to that specified field. + * 2. Check if "mappedBy" and "inversedBy" are consistent to each other. + * 3. Check if "referencedColumnName" attributes are really pointing to primary key columns. + * 4. Check if there are public properties that might cause problems with lazy loading. + * + * @return array + */ + public function validateMapping() + { + $errors = array(); + $cmf = $this->em->getMetadataFactory(); + $classes = $cmf->getAllMetadata(); + + foreach ($classes as $class) { + if ($ce = $this->validateClass($class)) { + $errors[$class->name] = $ce; + } + } + + return $errors; + } + + /** + * Validate a single class of the current + * + * @param ClassMetadataInfo $class + * @return array + */ + public function validateClass(ClassMetadataInfo $class) + { + $ce = array(); + $cmf = $this->em->getMetadataFactory(); + + foreach ($class->fieldMappings as $fieldName => $mapping) { + if (!Type::hasType($mapping['type'])) { + $ce[] = "The field '" . $class->name . "#" . $fieldName."' uses a non-existant type '" . $mapping['type'] . "'."; + } + } + + foreach ($class->associationMappings as $fieldName => $assoc) { + if (!class_exists($assoc['targetEntity']) || $cmf->isTransient($assoc['targetEntity'])) { + $ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown or not an entity.'; + return $ce; + } + + if ($assoc['mappedBy'] && $assoc['inversedBy']) { + $ce[] = "The association " . $class . "#" . $fieldName . " cannot be defined as both inverse and owning."; + } + + $targetMetadata = $cmf->getMetadataFor($assoc['targetEntity']); + + if (isset($assoc['id']) && $targetMetadata->containsForeignIdentifier) { + $ce[] = "Cannot map association '" . $class->name. "#". $fieldName ." as identifier, because " . + "the target entity '". $targetMetadata->name . "' also maps an association as identifier."; + } + + /* @var $assoc AssociationMapping */ + if ($assoc['mappedBy']) { + if ($targetMetadata->hasField($assoc['mappedBy'])) { + $ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ". + "field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which is not defined as association."; + } + if (!$targetMetadata->hasAssociation($assoc['mappedBy'])) { + $ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ". + "field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which does not exist."; + } else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] == null) { + $ce[] = "The field " . $class->name . "#" . $fieldName . " is on the inverse side of a ". + "bi-directional relationship, but the specified mappedBy association on the target-entity ". + $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ". + "'inversedBy=".$fieldName."' attribute."; + } else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] != $fieldName) { + $ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " . + $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " are ". + "incosistent with each other."; + } + } + + if ($assoc['inversedBy']) { + if ($targetMetadata->hasField($assoc['inversedBy'])) { + $ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ". + "field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which is not defined as association."; + } + if (!$targetMetadata->hasAssociation($assoc['inversedBy'])) { + $ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ". + "field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which does not exist."; + } else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] == null) { + $ce[] = "The field " . $class->name . "#" . $fieldName . " is on the owning side of a ". + "bi-directional relationship, but the specified mappedBy association on the target-entity ". + $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ". + "'inversedBy' attribute."; + } else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] != $fieldName) { + $ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " . + $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " are ". + "incosistent with each other."; + } + + // Verify inverse side/owning side match each other + if (array_key_exists($assoc['inversedBy'], $targetMetadata->associationMappings)) { + $targetAssoc = $targetMetadata->associationMappings[$assoc['inversedBy']]; + if ($assoc['type'] == ClassMetadataInfo::ONE_TO_ONE && $targetAssoc['type'] !== ClassMetadataInfo::ONE_TO_ONE){ + $ce[] = "If association " . $class->name . "#" . $fieldName . " is one-to-one, then the inversed " . + "side " . $targetMetadata->name . "#" . $assoc['inversedBy'] . " has to be one-to-one as well."; + } else if ($assoc['type'] == ClassMetadataInfo::MANY_TO_ONE && $targetAssoc['type'] !== ClassMetadataInfo::ONE_TO_MANY){ + $ce[] = "If association " . $class->name . "#" . $fieldName . " is many-to-one, then the inversed " . + "side " . $targetMetadata->name . "#" . $assoc['inversedBy'] . " has to be one-to-many."; + } else if ($assoc['type'] == ClassMetadataInfo::MANY_TO_MANY && $targetAssoc['type'] !== ClassMetadataInfo::MANY_TO_MANY){ + $ce[] = "If association " . $class->name . "#" . $fieldName . " is many-to-many, then the inversed " . + "side " . $targetMetadata->name . "#" . $assoc['inversedBy'] . " has to be many-to-many as well."; + } + } + } + + if ($assoc['isOwningSide']) { + if ($assoc['type'] == ClassMetadataInfo::MANY_TO_MANY) { + $identifierColumns = $class->getIdentifierColumnNames(); + foreach ($assoc['joinTable']['joinColumns'] as $joinColumn) { + if (!in_array($joinColumn['referencedColumnName'], $identifierColumns)) { + $ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " . + "has to be a primary key column on the target entity class '".$class->name."'."; + break; + } + } + + $identifierColumns = $targetMetadata->getIdentifierColumnNames(); + foreach ($assoc['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) { + if (!in_array($inverseJoinColumn['referencedColumnName'], $identifierColumns)) { + $ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " . + "has to be a primary key column on the target entity class '".$targetMetadata->name."'."; + break; + } + } + + if (count($targetMetadata->getIdentifierColumnNames()) != count($assoc['joinTable']['inverseJoinColumns'])) { + $ce[] = "The inverse join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " . + "have to contain to ALL identifier columns of the target entity '". $targetMetadata->name . "', " . + "however '" . implode(", ", array_diff($targetMetadata->getIdentifierColumnNames(), array_values($assoc['relationToTargetKeyColumns']))) . + "' are missing."; + } + + if (count($class->getIdentifierColumnNames()) != count($assoc['joinTable']['joinColumns'])) { + $ce[] = "The join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " . + "have to contain to ALL identifier columns of the source entity '". $class->name . "', " . + "however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), array_values($assoc['relationToSourceKeyColumns']))) . + "' are missing."; + } + + } else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) { + $identifierColumns = $targetMetadata->getIdentifierColumnNames(); + foreach ($assoc['joinColumns'] as $joinColumn) { + if (!in_array($joinColumn['referencedColumnName'], $identifierColumns)) { + $ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " . + "has to be a primary key column on the target entity class '".$targetMetadata->name."'."; + } + } + + if (count($identifierColumns) != count($assoc['joinColumns'])) { + $ids = array(); + foreach ($assoc['joinColumns'] as $joinColumn) { + $ids[] = $joinColumn['name']; + } + + $ce[] = "The join columns of the association '" . $assoc['fieldName'] . "' " . + "have to match to ALL identifier columns of the target entity '". $class->name . "', " . + "however '" . implode(", ", array_diff($targetMetadata->getIdentifierColumnNames(), $ids)) . + "' are missing."; + } + } + } + + if (isset($assoc['orderBy']) && $assoc['orderBy'] !== null) { + foreach ($assoc['orderBy'] as $orderField => $orientation) { + if (!$targetMetadata->hasField($orderField)) { + $ce[] = "The association " . $class->name."#".$fieldName." is ordered by a foreign field " . + $orderField . " that is not a field on the target entity " . $targetMetadata->name; + } + } + } + } + + foreach ($class->reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $publicAttr) { + if ($publicAttr->isStatic()) { + continue; + } + $ce[] = "Field '".$publicAttr->getName()."' in class '".$class->name."' must be private ". + "or protected. Public fields may break lazy-loading."; + } + + foreach ($class->subClasses as $subClass) { + if (!in_array($class->name, class_parents($subClass))) { + $ce[] = "According to the discriminator map class '" . $subClass . "' has to be a child ". + "of '" . $class->name . "' but these entities are not related through inheritance."; + } + } + + return $ce; + } + + /** + * @param string $columnName + * @param ClassMetadataInfo $class + * @return bool + */ + private function columnExistsOnEntity($columnName, $class) + { + if (isset($class->fieldNames[$columnName])) { + return true; + } + foreach ($class->associationMappings as $assoc) { + if ($assoc['isOwningSide']) { + foreach ($assoc['joinColumns'] as $columnMapping) { + if ($columnMapping['name'] == $columnName) { + return true; + } + } + } + } + return false; + } + + /** + * Check if the Database Schema is in sync with the current metadata state. + * + * @return bool + */ + public function schemaInSyncWithMetadata() + { + $schemaTool = new SchemaTool($this->em); + + $allMetadata = $this->em->getMetadataFactory()->getAllMetadata(); + return (count($schemaTool->getUpdateSchemaSql($allMetadata, true)) == 0); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Setup.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Setup.php new file mode 100644 index 0000000..f861073 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Setup.php @@ -0,0 +1,200 @@ +. +*/ + +namespace Doctrine\ORM\Tools; + +use Doctrine\Common\ClassLoader; +use Doctrine\Common\Cache\Cache; +use Doctrine\Common\Cache\ArrayCache; +use Doctrine\ORM\Configuration; +use Doctrine\ORM\Mapping\Driver\XmlDriver; +use Doctrine\ORM\Mapping\Driver\YamlDriver; + +/** + * Convenience class for setting up Doctrine from different installations and configurations. + * + * @author Benjamin Eberlei + */ +class Setup +{ + /** + * Use this method to register all autoloaders for a setup where Doctrine is checked out from + * its github repository at {@link http://github.com/doctrine/doctrine2} + * + * @param string $gitCheckoutRootPath + * @return void + */ + static public function registerAutoloadGit($gitCheckoutRootPath) + { + if (!class_exists('Doctrine\Common\ClassLoader', false)) { + require_once $gitCheckoutRootPath . "/lib/vendor/doctrine-common/lib/Doctrine/Common/ClassLoader.php"; + } + + $loader = new ClassLoader("Doctrine\Common", $gitCheckoutRootPath . "/lib/vendor/doctrine-common/lib"); + $loader->register(); + + $loader = new ClassLoader("Doctrine\DBAL", $gitCheckoutRootPath . "/lib/vendor/doctrine-dbal/lib"); + $loader->register(); + + $loader = new ClassLoader("Doctrine\ORM", $gitCheckoutRootPath . "/lib"); + $loader->register(); + + $loader = new ClassLoader("Symfony\Component", $gitCheckoutRootPath . "/lib/vendor"); + $loader->register(); + } + + /** + * Use this method to register all autoloaders for a setup where Doctrine is installed + * though {@link http://pear.doctrine-project.org}. + * + * @return void + */ + static public function registerAutoloadPEAR() + { + if (!class_exists('Doctrine\Common\ClassLoader', false)) { + require_once "Doctrine/Common/ClassLoader.php"; + } + + $loader = new ClassLoader("Doctrine"); + $loader->register(); + + $parts = explode(PATH_SEPARATOR, get_include_path()); + + foreach ($parts as $includePath) { + if ($includePath != "." && file_exists($includePath . "/Doctrine")) { + $loader = new ClassLoader("Symfony\Component", $includePath . "/Doctrine"); + $loader->register(); + return; + } + } + } + + /** + * Use this method to register all autoloads for a downloaded Doctrine library. + * Pick the directory the library was uncompressed into. + * + * @param string $directory + */ + static public function registerAutoloadDirectory($directory) + { + if (!class_exists('Doctrine\Common\ClassLoader', false)) { + require_once $directory . "/Doctrine/Common/ClassLoader.php"; + } + + $loader = new ClassLoader("Doctrine", $directory); + $loader->register(); + + $loader = new ClassLoader("Symfony\Component", $directory . "/Doctrine"); + $loader->register(); + } + + /** + * Create a configuration with an annotation metadata driver. + * + * @param array $paths + * @param boolean $isDevMode + * @param string $proxyDir + * @param Cache $cache + * @param bool $useSimpleAnnotationReader + * @return Configuration + */ + static public function createAnnotationMetadataConfiguration(array $paths, $isDevMode = false, $proxyDir = null, Cache $cache = null, $useSimpleAnnotationReader = true) + { + $config = self::createConfiguration($isDevMode, $proxyDir, $cache); + $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver($paths, $useSimpleAnnotationReader)); + return $config; + } + + /** + * Create a configuration with a xml metadata driver. + * + * @param array $paths + * @param boolean $isDevMode + * @param string $proxyDir + * @param Cache $cache + * @return Configuration + */ + static public function createXMLMetadataConfiguration(array $paths, $isDevMode = false, $proxyDir = null, Cache $cache = null) + { + $config = self::createConfiguration($isDevMode, $proxyDir, $cache); + $config->setMetadataDriverImpl(new XmlDriver($paths)); + return $config; + } + + /** + * Create a configuration with a yaml metadata driver. + * + * @param array $paths + * @param boolean $isDevMode + * @param string $proxyDir + * @param Cache $cache + * @return Configuration + */ + static public function createYAMLMetadataConfiguration(array $paths, $isDevMode = false, $proxyDir = null, Cache $cache = null) + { + $config = self::createConfiguration($isDevMode, $proxyDir, $cache); + $config->setMetadataDriverImpl(new YamlDriver($paths)); + return $config; + } + + /** + * Create a configuration without a metadata driver. + * + * @param bool $isDevMode + * @param string $proxyDir + * @param Cache $cache + * @return Configuration + */ + static public function createConfiguration($isDevMode = false, $proxyDir = null, Cache $cache = null) + { + $proxyDir = $proxyDir ?: sys_get_temp_dir(); + if ($isDevMode === false && $cache === null) { + if (extension_loaded('apc')) { + $cache = new \Doctrine\Common\Cache\ApcCache(); + } else if (extension_loaded('xcache')) { + $cache = new \Doctrine\Common\Cache\XcacheCache(); + } else if (extension_loaded('memcache')) { + $memcache = new \Memcache(); + $memcache->connect('127.0.0.1'); + $cache = new \Doctrine\Common\Cache\MemcacheCache(); + $cache->setMemcache($memcache); + } else if (extension_loaded('redis')) { + $redis = new \Redis(); + $redis->connect('127.0.0.1'); + $cache = new \Doctrine\Common\Cache\RedisCache(); + $cache->setRedis($redis); + } else { + $cache = new ArrayCache(); + } + } else if ($cache === null) { + $cache = new ArrayCache(); + } + $cache->setNamespace("dc2_" . md5($proxyDir) . "_"); // to avoid collisions + + $config = new Configuration(); + $config->setMetadataCacheImpl($cache); + $config->setQueryCacheImpl($cache); + $config->setResultCacheImpl($cache); + $config->setProxyDir($proxyDir); + $config->setProxyNamespace('DoctrineProxies'); + $config->setAutoGenerateProxyClasses($isDevMode); + + return $config; + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ToolEvents.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ToolEvents.php new file mode 100644 index 0000000..7aa98d9 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ToolEvents.php @@ -0,0 +1,42 @@ +. + */ + +namespace Doctrine\ORM\Tools; + +class ToolEvents +{ + /** + * The postGenerateSchemaTable event occurs in SchemaTool#getSchemaFromMetadata() + * whenever an entity class is transformed into its table representation. It recieves + * the current non-complete Schema instance, the Entity Metadata Class instance and + * the Schema Table instance of this entity. + * + * @var string + */ + const postGenerateSchemaTable = 'postGenerateSchemaTable'; + + /** + * The postGenerateSchema event is triggered in SchemaTool#getSchemaFromMetadata() + * after all entity classes have been transformed into the related Schema structure. + * The EventArgs contain the EntityManager and the created Schema instance. + * + * @var string + */ + const postGenerateSchema = 'postGenerateSchema'; +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ToolsException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ToolsException.php new file mode 100644 index 0000000..30f7ea1 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ToolsException.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\ORM\Tools; + +use Doctrine\ORM\ORMException; + +/** + * Tools related Exceptions + * + * @author Benjamin Eberlei + */ +class ToolsException extends ORMException +{ + public static function schemaToolFailure($sql, \Exception $e) + { + return new self("Schema-Tool failed with Error '" . $e->getMessage() . "' while executing DDL: " . $sql, "0", $e); + } + + public static function couldNotMapDoctrine1Type($type) + { + return new self("Could not map doctrine 1 type '$type'!"); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/TransactionRequiredException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/TransactionRequiredException.php new file mode 100644 index 0000000..3e04224 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/TransactionRequiredException.php @@ -0,0 +1,37 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Is thrown when a transaction is required for the current operation, but there is none open. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @author Benjamin Eberlei + * @author Roman Borschel + */ +class TransactionRequiredException extends ORMException +{ + static public function transactionRequired() + { + return new self('An open transaction is required for this operation.'); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/UnexpectedResultException.php b/vendor/doctrine/orm/lib/Doctrine/ORM/UnexpectedResultException.php new file mode 100644 index 0000000..5d6b6d1 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/UnexpectedResultException.php @@ -0,0 +1,31 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Exception for a unexpected query result. + * + * @author Fabio B. Silva + * @since 2.3 + */ +class UnexpectedResultException extends ORMException +{ + +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php b/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php new file mode 100644 index 0000000..19ba6cb --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php @@ -0,0 +1,3046 @@ +. + */ + +namespace Doctrine\ORM; + +use Exception, InvalidArgumentException, UnexpectedValueException, + Doctrine\Common\Collections\ArrayCollection, + Doctrine\Common\Collections\Collection, + Doctrine\Common\NotifyPropertyChanged, + Doctrine\Common\PropertyChangedListener, + Doctrine\Common\Persistence\ObjectManagerAware, + Doctrine\ORM\Event\LifecycleEventArgs, + Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\Proxy\Proxy; + +/** + * The UnitOfWork is responsible for tracking changes to objects during an + * "object-level" transaction and for writing out changes to the database + * in the correct order. + * + * @since 2.0 + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @internal This class contains highly performance-sensitive code. + */ +class UnitOfWork implements PropertyChangedListener +{ + /** + * An entity is in MANAGED state when its persistence is managed by an EntityManager. + */ + const STATE_MANAGED = 1; + + /** + * An entity is new if it has just been instantiated (i.e. using the "new" operator) + * and is not (yet) managed by an EntityManager. + */ + const STATE_NEW = 2; + + /** + * A detached entity is an instance with persistent state and identity that is not + * (or no longer) associated with an EntityManager (and a UnitOfWork). + */ + const STATE_DETACHED = 3; + + /** + * A removed entity instance is an instance with a persistent identity, + * associated with an EntityManager, whose persistent state will be deleted + * on commit. + */ + const STATE_REMOVED = 4; + + /** + * The identity map that holds references to all managed entities that have + * an identity. The entities are grouped by their class name. + * Since all classes in a hierarchy must share the same identifier set, + * we always take the root class name of the hierarchy. + * + * @var array + */ + private $identityMap = array(); + + /** + * Map of all identifiers of managed entities. + * Keys are object ids (spl_object_hash). + * + * @var array + */ + private $entityIdentifiers = array(); + + /** + * Map of the original entity data of managed entities. + * Keys are object ids (spl_object_hash). This is used for calculating changesets + * at commit time. + * + * @var array + * @internal Note that PHPs "copy-on-write" behavior helps a lot with memory usage. + * A value will only really be copied if the value in the entity is modified + * by the user. + */ + private $originalEntityData = array(); + + /** + * Map of entity changes. Keys are object ids (spl_object_hash). + * Filled at the beginning of a commit of the UnitOfWork and cleaned at the end. + * + * @var array + */ + private $entityChangeSets = array(); + + /** + * The (cached) states of any known entities. + * Keys are object ids (spl_object_hash). + * + * @var array + */ + private $entityStates = array(); + + /** + * Map of entities that are scheduled for dirty checking at commit time. + * This is only used for entities with a change tracking policy of DEFERRED_EXPLICIT. + * Keys are object ids (spl_object_hash). + * + * @var array + * @todo rename: scheduledForSynchronization + */ + private $scheduledForDirtyCheck = array(); + + /** + * A list of all pending entity insertions. + * + * @var array + */ + private $entityInsertions = array(); + + /** + * A list of all pending entity updates. + * + * @var array + */ + private $entityUpdates = array(); + + /** + * Any pending extra updates that have been scheduled by persisters. + * + * @var array + */ + private $extraUpdates = array(); + + /** + * A list of all pending entity deletions. + * + * @var array + */ + private $entityDeletions = array(); + + /** + * All pending collection deletions. + * + * @var array + */ + private $collectionDeletions = array(); + + /** + * All pending collection updates. + * + * @var array + */ + private $collectionUpdates = array(); + + /** + * List of collections visited during changeset calculation on a commit-phase of a UnitOfWork. + * At the end of the UnitOfWork all these collections will make new snapshots + * of their data. + * + * @var array + */ + private $visitedCollections = array(); + + /** + * The EntityManager that "owns" this UnitOfWork instance. + * + * @var \Doctrine\ORM\EntityManager + */ + private $em; + + /** + * The calculator used to calculate the order in which changes to + * entities need to be written to the database. + * + * @var \Doctrine\ORM\Internal\CommitOrderCalculator + */ + private $commitOrderCalculator; + + /** + * The entity persister instances used to persist entity instances. + * + * @var array + */ + private $persisters = array(); + + /** + * The collection persister instances used to persist collections. + * + * @var array + */ + private $collectionPersisters = array(); + + /** + * The EventManager used for dispatching events. + * + * @var \Doctrine\Common\EventManager + */ + private $evm; + + /** + * Orphaned entities that are scheduled for removal. + * + * @var array + */ + private $orphanRemovals = array(); + + /** + * Read-Only objects are never evaluated + * + * @var array + */ + private $readOnlyObjects = array(); + + /** + * Map of Entity Class-Names and corresponding IDs that should eager loaded when requested. + * + * @var array + */ + private $eagerLoadingEntities = array(); + + /** + * Initializes a new UnitOfWork instance, bound to the given EntityManager. + * + * @param \Doctrine\ORM\EntityManager $em + */ + public function __construct(EntityManager $em) + { + $this->em = $em; + $this->evm = $em->getEventManager(); + } + + /** + * Commits the UnitOfWork, executing all operations that have been postponed + * up to this point. The state of all managed entities will be synchronized with + * the database. + * + * The operations are executed in the following order: + * + * 1) All entity insertions + * 2) All entity updates + * 3) All collection deletions + * 4) All collection updates + * 5) All entity deletions + * + * @param null|object|array $entity + * + * @throws \Exception + * + * @return void + */ + public function commit($entity = null) + { + // Raise preFlush + if ($this->evm->hasListeners(Events::preFlush)) { + $this->evm->dispatchEvent(Events::preFlush, new Event\PreFlushEventArgs($this->em)); + } + + // Compute changes done since last commit. + if ($entity === null) { + $this->computeChangeSets(); + } elseif (is_object($entity)) { + $this->computeSingleEntityChangeSet($entity); + } elseif (is_array($entity)) { + foreach ($entity as $object) { + $this->computeSingleEntityChangeSet($object); + } + } + + if ( ! ($this->entityInsertions || + $this->entityDeletions || + $this->entityUpdates || + $this->collectionUpdates || + $this->collectionDeletions || + $this->orphanRemovals)) { + return; // Nothing to do. + } + + if ($this->orphanRemovals) { + foreach ($this->orphanRemovals as $orphan) { + $this->remove($orphan); + } + } + + // Raise onFlush + if ($this->evm->hasListeners(Events::onFlush)) { + $this->evm->dispatchEvent(Events::onFlush, new Event\OnFlushEventArgs($this->em)); + } + + // Now we need a commit order to maintain referential integrity + $commitOrder = $this->getCommitOrder(); + + $conn = $this->em->getConnection(); + $conn->beginTransaction(); + + try { + if ($this->entityInsertions) { + foreach ($commitOrder as $class) { + $this->executeInserts($class); + } + } + + if ($this->entityUpdates) { + foreach ($commitOrder as $class) { + $this->executeUpdates($class); + } + } + + // Extra updates that were requested by persisters. + if ($this->extraUpdates) { + $this->executeExtraUpdates(); + } + + // Collection deletions (deletions of complete collections) + foreach ($this->collectionDeletions as $collectionToDelete) { + $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete); + } + // Collection updates (deleteRows, updateRows, insertRows) + foreach ($this->collectionUpdates as $collectionToUpdate) { + $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate); + } + + // Entity deletions come last and need to be in reverse commit order + if ($this->entityDeletions) { + for ($count = count($commitOrder), $i = $count - 1; $i >= 0; --$i) { + $this->executeDeletions($commitOrder[$i]); + } + } + + $conn->commit(); + } catch (Exception $e) { + $this->em->close(); + $conn->rollback(); + + throw $e; + } + + // Take new snapshots from visited collections + foreach ($this->visitedCollections as $coll) { + $coll->takeSnapshot(); + } + + // Raise postFlush + if ($this->evm->hasListeners(Events::postFlush)) { + $this->evm->dispatchEvent(Events::postFlush, new Event\PostFlushEventArgs($this->em)); + } + + // Clear up + $this->entityInsertions = + $this->entityUpdates = + $this->entityDeletions = + $this->extraUpdates = + $this->entityChangeSets = + $this->collectionUpdates = + $this->collectionDeletions = + $this->visitedCollections = + $this->scheduledForDirtyCheck = + $this->orphanRemovals = array(); + } + + /** + * Compute the changesets of all entities scheduled for insertion + * + * @return void + */ + private function computeScheduleInsertsChangeSets() + { + foreach ($this->entityInsertions as $entity) { + $class = $this->em->getClassMetadata(get_class($entity)); + + $this->computeChangeSet($class, $entity); + } + } + + /** + * Only flush the given entity according to a ruleset that keeps the UoW consistent. + * + * 1. All entities scheduled for insertion, (orphan) removals and changes in collections are processed as well! + * 2. Read Only entities are skipped. + * 3. Proxies are skipped. + * 4. Only if entity is properly managed. + * + * @param object $entity + * + * @throws \InvalidArgumentException + * + * @return void + */ + private function computeSingleEntityChangeSet($entity) + { + if ( $this->getEntityState($entity) !== self::STATE_MANAGED) { + throw new \InvalidArgumentException("Entity has to be managed for single computation " . self::objToStr($entity)); + } + + $class = $this->em->getClassMetadata(get_class($entity)); + + if ($class->isChangeTrackingDeferredImplicit()) { + $this->persist($entity); + } + + // Compute changes for INSERTed entities first. This must always happen even in this case. + $this->computeScheduleInsertsChangeSets(); + + if ($class->isReadOnly) { + return; + } + + // Ignore uninitialized proxy objects + if ($entity instanceof Proxy && ! $entity->__isInitialized__) { + return; + } + + // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here. + $oid = spl_object_hash($entity); + + if ( ! isset($this->entityInsertions[$oid]) && isset($this->entityStates[$oid])) { + $this->computeChangeSet($class, $entity); + } + } + + /** + * Executes any extra updates that have been scheduled. + */ + private function executeExtraUpdates() + { + foreach ($this->extraUpdates as $oid => $update) { + list ($entity, $changeset) = $update; + + $this->entityChangeSets[$oid] = $changeset; + $this->getEntityPersister(get_class($entity))->update($entity); + } + } + + /** + * Gets the changeset for an entity. + * + * @param object $entity + * + * @return array + */ + public function getEntityChangeSet($entity) + { + $oid = spl_object_hash($entity); + + if (isset($this->entityChangeSets[$oid])) { + return $this->entityChangeSets[$oid]; + } + + return array(); + } + + /** + * Computes the changes that happened to a single entity. + * + * Modifies/populates the following properties: + * + * {@link _originalEntityData} + * If the entity is NEW or MANAGED but not yet fully persisted (only has an id) + * then it was not fetched from the database and therefore we have no original + * entity data yet. All of the current entity data is stored as the original entity data. + * + * {@link _entityChangeSets} + * The changes detected on all properties of the entity are stored there. + * A change is a tuple array where the first entry is the old value and the second + * entry is the new value of the property. Changesets are used by persisters + * to INSERT/UPDATE the persistent entity state. + * + * {@link _entityUpdates} + * If the entity is already fully MANAGED (has been fetched from the database before) + * and any changes to its properties are detected, then a reference to the entity is stored + * there to mark it for an update. + * + * {@link _collectionDeletions} + * If a PersistentCollection has been de-referenced in a fully MANAGED entity, + * then this collection is marked for deletion. + * + * @ignore + * @internal Don't call from the outside. + * @param ClassMetadata $class The class descriptor of the entity. + * @param object $entity The entity for which to compute the changes. + */ + public function computeChangeSet(ClassMetadata $class, $entity) + { + $oid = spl_object_hash($entity); + + if (isset($this->readOnlyObjects[$oid])) { + return; + } + + if ( ! $class->isInheritanceTypeNone()) { + $class = $this->em->getClassMetadata(get_class($entity)); + } + + // Fire PreFlush lifecycle callbacks + if (isset($class->lifecycleCallbacks[Events::preFlush])) { + $class->invokeLifecycleCallbacks(Events::preFlush, $entity); + } + + $actualData = array(); + + foreach ($class->reflFields as $name => $refProp) { + $value = $refProp->getValue($entity); + + if ($class->isCollectionValuedAssociation($name) && $value !== null && ! ($value instanceof PersistentCollection)) { + // If $value is not a Collection then use an ArrayCollection. + if ( ! $value instanceof Collection) { + $value = new ArrayCollection($value); + } + + $assoc = $class->associationMappings[$name]; + + // Inject PersistentCollection + $value = new PersistentCollection( + $this->em, $this->em->getClassMetadata($assoc['targetEntity']), $value + ); + $value->setOwner($entity, $assoc); + $value->setDirty( ! $value->isEmpty()); + + $class->reflFields[$name]->setValue($entity, $value); + + $actualData[$name] = $value; + + continue; + } + + if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) && ($name !== $class->versionField)) { + $actualData[$name] = $value; + } + } + + if ( ! isset($this->originalEntityData[$oid])) { + // Entity is either NEW or MANAGED but not yet fully persisted (only has an id). + // These result in an INSERT. + $this->originalEntityData[$oid] = $actualData; + $changeSet = array(); + + foreach ($actualData as $propName => $actualValue) { + if ( ! isset($class->associationMappings[$propName])) { + $changeSet[$propName] = array(null, $actualValue); + + continue; + } + + $assoc = $class->associationMappings[$propName]; + + if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) { + $changeSet[$propName] = array(null, $actualValue); + } + } + + $this->entityChangeSets[$oid] = $changeSet; + } else { + // Entity is "fully" MANAGED: it was already fully persisted before + // and we have a copy of the original data + $originalData = $this->originalEntityData[$oid]; + $isChangeTrackingNotify = $class->isChangeTrackingNotify(); + $changeSet = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid])) + ? $this->entityChangeSets[$oid] + : array(); + + foreach ($actualData as $propName => $actualValue) { + // skip field, its a partially omitted one! + if ( ! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) { + continue; + } + + $orgValue = $originalData[$propName]; + + // skip if value havent changed + if ($orgValue === $actualValue) { + continue; + } + + // if regular field + if ( ! isset($class->associationMappings[$propName])) { + if ($isChangeTrackingNotify) { + continue; + } + + $changeSet[$propName] = array($orgValue, $actualValue); + + continue; + } + + $assoc = $class->associationMappings[$propName]; + + // Persistent collection was exchanged with the "originally" + // created one. This can only mean it was cloned and replaced + // on another entity. + if ($actualValue instanceof PersistentCollection) { + $owner = $actualValue->getOwner(); + if ($owner === null) { // cloned + $actualValue->setOwner($entity, $assoc); + } else if ($owner !== $entity) { // no clone, we have to fix + if (!$actualValue->isInitialized()) { + $actualValue->initialize(); // we have to do this otherwise the cols share state + } + $newValue = clone $actualValue; + $newValue->setOwner($entity, $assoc); + $class->reflFields[$propName]->setValue($entity, $newValue); + } + } + + if ($orgValue instanceof PersistentCollection) { + // A PersistentCollection was de-referenced, so delete it. + $coid = spl_object_hash($orgValue); + + if (isset($this->collectionDeletions[$coid])) { + continue; + } + + $this->collectionDeletions[$coid] = $orgValue; + $changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored. + + continue; + } + + if ($assoc['type'] & ClassMetadata::TO_ONE) { + if ($assoc['isOwningSide']) { + $changeSet[$propName] = array($orgValue, $actualValue); + } + + if ($orgValue !== null && $assoc['orphanRemoval']) { + $this->scheduleOrphanRemoval($orgValue); + } + } + } + + if ($changeSet) { + $this->entityChangeSets[$oid] = $changeSet; + $this->originalEntityData[$oid] = $actualData; + $this->entityUpdates[$oid] = $entity; + } + } + + // Look for changes in associations of the entity + foreach ($class->associationMappings as $field => $assoc) { + if (($val = $class->reflFields[$field]->getValue($entity)) !== null) { + $this->computeAssociationChanges($assoc, $val); + if (!isset($this->entityChangeSets[$oid]) && + $assoc['isOwningSide'] && + $assoc['type'] == ClassMetadata::MANY_TO_MANY && + $val instanceof PersistentCollection && + $val->isDirty()) { + $this->entityChangeSets[$oid] = array(); + $this->originalEntityData[$oid] = $actualData; + $this->entityUpdates[$oid] = $entity; + } + } + } + } + + /** + * Computes all the changes that have been done to entities and collections + * since the last commit and stores these changes in the _entityChangeSet map + * temporarily for access by the persisters, until the UoW commit is finished. + */ + public function computeChangeSets() + { + // Compute changes for INSERTed entities first. This must always happen. + $this->computeScheduleInsertsChangeSets(); + + // Compute changes for other MANAGED entities. Change tracking policies take effect here. + foreach ($this->identityMap as $className => $entities) { + $class = $this->em->getClassMetadata($className); + + // Skip class if instances are read-only + if ($class->isReadOnly) { + continue; + } + + // If change tracking is explicit or happens through notification, then only compute + // changes on entities of that type that are explicitly marked for synchronization. + switch (true) { + case ($class->isChangeTrackingDeferredImplicit()): + $entitiesToProcess = $entities; + break; + + case (isset($this->scheduledForDirtyCheck[$className])): + $entitiesToProcess = $this->scheduledForDirtyCheck[$className]; + break; + + default: + $entitiesToProcess = array(); + + } + + foreach ($entitiesToProcess as $entity) { + // Ignore uninitialized proxy objects + if ($entity instanceof Proxy && ! $entity->__isInitialized__) { + continue; + } + + // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here. + $oid = spl_object_hash($entity); + + if ( ! isset($this->entityInsertions[$oid]) && isset($this->entityStates[$oid])) { + $this->computeChangeSet($class, $entity); + } + } + } + } + + /** + * Computes the changes of an association. + * + * @param array $assoc + * @param mixed $value The value of the association. + * + * @throws ORMInvalidArgumentException + * @throws ORMException + * + * @return void + */ + private function computeAssociationChanges($assoc, $value) + { + if ($value instanceof Proxy && ! $value->__isInitialized__) { + return; + } + + if ($value instanceof PersistentCollection && $value->isDirty()) { + $coid = spl_object_hash($value); + + if ($assoc['isOwningSide']) { + $this->collectionUpdates[$coid] = $value; + } + + $this->visitedCollections[$coid] = $value; + } + + // Look through the entities, and in any of their associations, + // for transient (new) entities, recursively. ("Persistence by reachability") + // Unwrap. Uninitialized collections will simply be empty. + $unwrappedValue = ($assoc['type'] & ClassMetadata::TO_ONE) ? array($value) : $value->unwrap(); + $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); + + foreach ($unwrappedValue as $key => $entry) { + $state = $this->getEntityState($entry, self::STATE_NEW); + + if ( ! ($entry instanceof $assoc['targetEntity'])) { + throw new ORMException( + sprintf( + 'Found entity of type %s on association %s#%s, but expecting %s', + get_class($entry), + $assoc['sourceEntity'], + $assoc['fieldName'], + $targetClass->name + ) + ); + } + + switch ($state) { + case self::STATE_NEW: + if ( ! $assoc['isCascadePersist']) { + throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry); + } + + $this->persistNew($targetClass, $entry); + $this->computeChangeSet($targetClass, $entry); + break; + + case self::STATE_REMOVED: + // Consume the $value as array (it's either an array or an ArrayAccess) + // and remove the element from Collection. + if ($assoc['type'] & ClassMetadata::TO_MANY) { + unset($value[$key]); + } + break; + + case self::STATE_DETACHED: + // Can actually not happen right now as we assume STATE_NEW, + // so the exception will be raised from the DBAL layer (constraint violation). + throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry); + break; + + default: + // MANAGED associated entities are already taken into account + // during changeset calculation anyway, since they are in the identity map. + } + } + } + + /** + * @param ClassMetadata $class + * @param object $entity + */ + private function persistNew($class, $entity) + { + $oid = spl_object_hash($entity); + + if (isset($class->lifecycleCallbacks[Events::prePersist])) { + $class->invokeLifecycleCallbacks(Events::prePersist, $entity); + } + + if ($this->evm->hasListeners(Events::prePersist)) { + $this->evm->dispatchEvent(Events::prePersist, new LifecycleEventArgs($entity, $this->em)); + } + + $idGen = $class->idGenerator; + + if ( ! $idGen->isPostInsertGenerator()) { + $idValue = $idGen->generate($this->em, $entity); + + if ( ! $idGen instanceof \Doctrine\ORM\Id\AssignedGenerator) { + $idValue = array($class->identifier[0] => $idValue); + + $class->setIdentifierValues($entity, $idValue); + } + + $this->entityIdentifiers[$oid] = $idValue; + } + + $this->entityStates[$oid] = self::STATE_MANAGED; + + $this->scheduleForInsert($entity); + } + + /** + * INTERNAL: + * Computes the changeset of an individual entity, independently of the + * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit(). + * + * The passed entity must be a managed entity. If the entity already has a change set + * because this method is invoked during a commit cycle then the change sets are added. + * whereby changes detected in this method prevail. + * + * @ignore + * @param ClassMetadata $class The class descriptor of the entity. + * @param object $entity The entity for which to (re)calculate the change set. + * + * @throws ORMInvalidArgumentException If the passed entity is not MANAGED. + */ + public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity) + { + $oid = spl_object_hash($entity); + + if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) { + throw ORMInvalidArgumentException::entityNotManaged($entity); + } + + // skip if change tracking is "NOTIFY" + if ($class->isChangeTrackingNotify()) { + return; + } + + if ( ! $class->isInheritanceTypeNone()) { + $class = $this->em->getClassMetadata(get_class($entity)); + } + + $actualData = array(); + + foreach ($class->reflFields as $name => $refProp) { + if ( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) { + $actualData[$name] = $refProp->getValue($entity); + } + } + + $originalData = $this->originalEntityData[$oid]; + $changeSet = array(); + + foreach ($actualData as $propName => $actualValue) { + $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null; + + if (is_object($orgValue) && $orgValue !== $actualValue) { + $changeSet[$propName] = array($orgValue, $actualValue); + } else if ($orgValue != $actualValue || ($orgValue === null ^ $actualValue === null)) { + $changeSet[$propName] = array($orgValue, $actualValue); + } + } + + if ($changeSet) { + if (isset($this->entityChangeSets[$oid])) { + $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet); + } + + $this->originalEntityData[$oid] = $actualData; + } + } + + /** + * Executes all entity insertions for entities of the specified type. + * + * @param \Doctrine\ORM\Mapping\ClassMetadata $class + */ + private function executeInserts($class) + { + $className = $class->name; + $persister = $this->getEntityPersister($className); + $entities = array(); + + $hasLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::postPersist]); + $hasListeners = $this->evm->hasListeners(Events::postPersist); + + foreach ($this->entityInsertions as $oid => $entity) { + if ($this->em->getClassMetadata(get_class($entity))->name !== $className) { + continue; + } + + $persister->addInsert($entity); + + unset($this->entityInsertions[$oid]); + + if ($hasLifecycleCallbacks || $hasListeners) { + $entities[] = $entity; + } + } + + $postInsertIds = $persister->executeInserts(); + + if ($postInsertIds) { + // Persister returned post-insert IDs + foreach ($postInsertIds as $id => $entity) { + $oid = spl_object_hash($entity); + $idField = $class->identifier[0]; + + $class->reflFields[$idField]->setValue($entity, $id); + + $this->entityIdentifiers[$oid] = array($idField => $id); + $this->entityStates[$oid] = self::STATE_MANAGED; + $this->originalEntityData[$oid][$idField] = $id; + + $this->addToIdentityMap($entity); + } + } + + foreach ($entities as $entity) { + if ($hasLifecycleCallbacks) { + $class->invokeLifecycleCallbacks(Events::postPersist, $entity); + } + + if ($hasListeners) { + $this->evm->dispatchEvent(Events::postPersist, new LifecycleEventArgs($entity, $this->em)); + } + } + } + + /** + * Executes all entity updates for entities of the specified type. + * + * @param \Doctrine\ORM\Mapping\ClassMetadata $class + */ + private function executeUpdates($class) + { + $className = $class->name; + $persister = $this->getEntityPersister($className); + + $hasPreUpdateLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::preUpdate]); + $hasPreUpdateListeners = $this->evm->hasListeners(Events::preUpdate); + + $hasPostUpdateLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::postUpdate]); + $hasPostUpdateListeners = $this->evm->hasListeners(Events::postUpdate); + + foreach ($this->entityUpdates as $oid => $entity) { + if ($this->em->getClassMetadata(get_class($entity))->name !== $className) { + continue; + } + + if ($hasPreUpdateLifecycleCallbacks) { + $class->invokeLifecycleCallbacks(Events::preUpdate, $entity); + + $this->recomputeSingleEntityChangeSet($class, $entity); + } + + if ($hasPreUpdateListeners) { + $this->evm->dispatchEvent( + Events::preUpdate, + new Event\PreUpdateEventArgs($entity, $this->em, $this->entityChangeSets[$oid]) + ); + } + + if ($this->entityChangeSets[$oid]) { + $persister->update($entity); + } + + unset($this->entityUpdates[$oid]); + + if ($hasPostUpdateLifecycleCallbacks) { + $class->invokeLifecycleCallbacks(Events::postUpdate, $entity); + } + + if ($hasPostUpdateListeners) { + $this->evm->dispatchEvent(Events::postUpdate, new LifecycleEventArgs($entity, $this->em)); + } + } + } + + /** + * Executes all entity deletions for entities of the specified type. + * + * @param \Doctrine\ORM\Mapping\ClassMetadata $class + */ + private function executeDeletions($class) + { + $className = $class->name; + $persister = $this->getEntityPersister($className); + + $hasLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::postRemove]); + $hasListeners = $this->evm->hasListeners(Events::postRemove); + + foreach ($this->entityDeletions as $oid => $entity) { + if ($this->em->getClassMetadata(get_class($entity))->name !== $className) { + continue; + } + + $persister->delete($entity); + + unset( + $this->entityDeletions[$oid], + $this->entityIdentifiers[$oid], + $this->originalEntityData[$oid], + $this->entityStates[$oid] + ); + + // Entity with this $oid after deletion treated as NEW, even if the $oid + // is obtained by a new entity because the old one went out of scope. + //$this->entityStates[$oid] = self::STATE_NEW; + if ( ! $class->isIdentifierNatural()) { + $class->reflFields[$class->identifier[0]]->setValue($entity, null); + } + + if ($hasLifecycleCallbacks) { + $class->invokeLifecycleCallbacks(Events::postRemove, $entity); + } + + if ($hasListeners) { + $this->evm->dispatchEvent(Events::postRemove, new LifecycleEventArgs($entity, $this->em)); + } + } + } + + /** + * Gets the commit order. + * + * @param array $entityChangeSet + * + * @return array + */ + private function getCommitOrder(array $entityChangeSet = null) + { + if ($entityChangeSet === null) { + $entityChangeSet = array_merge($this->entityInsertions, $this->entityUpdates, $this->entityDeletions); + } + + $calc = $this->getCommitOrderCalculator(); + + // See if there are any new classes in the changeset, that are not in the + // commit order graph yet (dont have a node). + // We have to inspect changeSet to be able to correctly build dependencies. + // It is not possible to use IdentityMap here because post inserted ids + // are not yet available. + $newNodes = array(); + + foreach ($entityChangeSet as $entity) { + $className = $this->em->getClassMetadata(get_class($entity))->name; + + if ($calc->hasClass($className)) { + continue; + } + + $class = $this->em->getClassMetadata($className); + $calc->addClass($class); + + $newNodes[] = $class; + } + + // Calculate dependencies for new nodes + while ($class = array_pop($newNodes)) { + foreach ($class->associationMappings as $assoc) { + if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) { + continue; + } + + $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); + + if ( ! $calc->hasClass($targetClass->name)) { + $calc->addClass($targetClass); + + $newNodes[] = $targetClass; + } + + $calc->addDependency($targetClass, $class); + + // If the target class has mapped subclasses, these share the same dependency. + if ( ! $targetClass->subClasses) { + continue; + } + + foreach ($targetClass->subClasses as $subClassName) { + $targetSubClass = $this->em->getClassMetadata($subClassName); + + if ( ! $calc->hasClass($subClassName)) { + $calc->addClass($targetSubClass); + + $newNodes[] = $targetSubClass; + } + + $calc->addDependency($targetSubClass, $class); + } + } + } + + return $calc->getCommitOrder(); + } + + /** + * Schedules an entity for insertion into the database. + * If the entity already has an identifier, it will be added to the identity map. + * + * @param object $entity The entity to schedule for insertion. + * + * @throws ORMInvalidArgumentException + * @throws \InvalidArgumentException + */ + public function scheduleForInsert($entity) + { + $oid = spl_object_hash($entity); + + if (isset($this->entityUpdates[$oid])) { + throw new InvalidArgumentException("Dirty entity can not be scheduled for insertion."); + } + + if (isset($this->entityDeletions[$oid])) { + throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity); + } + if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) { + throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity); + } + + if (isset($this->entityInsertions[$oid])) { + throw ORMInvalidArgumentException::scheduleInsertTwice($entity); + } + + $this->entityInsertions[$oid] = $entity; + + if (isset($this->entityIdentifiers[$oid])) { + $this->addToIdentityMap($entity); + } + + if ($entity instanceof NotifyPropertyChanged) { + $entity->addPropertyChangedListener($this); + } + } + + /** + * Checks whether an entity is scheduled for insertion. + * + * @param object $entity + * + * @return boolean + */ + public function isScheduledForInsert($entity) + { + return isset($this->entityInsertions[spl_object_hash($entity)]); + } + + /** + * Schedules an entity for being updated. + * + * @param object $entity The entity to schedule for being updated. + * + * @throws ORMInvalidArgumentException + */ + public function scheduleForUpdate($entity) + { + $oid = spl_object_hash($entity); + + if ( ! isset($this->entityIdentifiers[$oid])) { + throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "scheduling for update"); + } + + if (isset($this->entityDeletions[$oid])) { + throw ORMInvalidArgumentException::entityIsRemoved($entity, "schedule for update"); + } + + if ( ! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid])) { + $this->entityUpdates[$oid] = $entity; + } + } + + /** + * INTERNAL: + * Schedules an extra update that will be executed immediately after the + * regular entity updates within the currently running commit cycle. + * + * Extra updates for entities are stored as (entity, changeset) tuples. + * + * @ignore + * @param object $entity The entity for which to schedule an extra update. + * @param array $changeset The changeset of the entity (what to update). + */ + public function scheduleExtraUpdate($entity, array $changeset) + { + $oid = spl_object_hash($entity); + $extraUpdate = array($entity, $changeset); + + if (isset($this->extraUpdates[$oid])) { + list($ignored, $changeset2) = $this->extraUpdates[$oid]; + + $extraUpdate = array($entity, $changeset + $changeset2); + } + + $this->extraUpdates[$oid] = $extraUpdate; + } + + /** + * Checks whether an entity is registered as dirty in the unit of work. + * Note: Is not very useful currently as dirty entities are only registered + * at commit time. + * + * @param object $entity + * + * @return boolean + */ + public function isScheduledForUpdate($entity) + { + return isset($this->entityUpdates[spl_object_hash($entity)]); + } + + + /** + * Checks whether an entity is registered to be checked in the unit of work. + * + * @param object $entity + * + * @return boolean + */ + public function isScheduledForDirtyCheck($entity) + { + $rootEntityName = $this->em->getClassMetadata(get_class($entity))->rootEntityName; + + return isset($this->scheduledForDirtyCheck[$rootEntityName][spl_object_hash($entity)]); + } + + /** + * INTERNAL: + * Schedules an entity for deletion. + * + * @param object $entity + */ + public function scheduleForDelete($entity) + { + $oid = spl_object_hash($entity); + + if (isset($this->entityInsertions[$oid])) { + if ($this->isInIdentityMap($entity)) { + $this->removeFromIdentityMap($entity); + } + + unset($this->entityInsertions[$oid], $this->entityStates[$oid]); + + return; // entity has not been persisted yet, so nothing more to do. + } + + if ( ! $this->isInIdentityMap($entity)) { + return; + } + + $this->removeFromIdentityMap($entity); + + if (isset($this->entityUpdates[$oid])) { + unset($this->entityUpdates[$oid]); + } + + if ( ! isset($this->entityDeletions[$oid])) { + $this->entityDeletions[$oid] = $entity; + $this->entityStates[$oid] = self::STATE_REMOVED; + } + } + + /** + * Checks whether an entity is registered as removed/deleted with the unit + * of work. + * + * @param object $entity + * + * @return boolean + */ + public function isScheduledForDelete($entity) + { + return isset($this->entityDeletions[spl_object_hash($entity)]); + } + + /** + * Checks whether an entity is scheduled for insertion, update or deletion. + * + * @param $entity + * + * @return boolean + */ + public function isEntityScheduled($entity) + { + $oid = spl_object_hash($entity); + + return isset($this->entityInsertions[$oid]) + || isset($this->entityUpdates[$oid]) + || isset($this->entityDeletions[$oid]); + } + + /** + * INTERNAL: + * Registers an entity in the identity map. + * Note that entities in a hierarchy are registered with the class name of + * the root entity. + * + * @ignore + * @param object $entity The entity to register. + * + * @throws ORMInvalidArgumentException + * + * @return boolean TRUE if the registration was successful, FALSE if the identity of + * the entity in question is already managed. + */ + public function addToIdentityMap($entity) + { + $classMetadata = $this->em->getClassMetadata(get_class($entity)); + $idHash = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]); + + if ($idHash === '') { + throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity); + } + + $className = $classMetadata->rootEntityName; + + if (isset($this->identityMap[$className][$idHash])) { + return false; + } + + $this->identityMap[$className][$idHash] = $entity; + + return true; + } + + /** + * Gets the state of an entity with regard to the current unit of work. + * + * @param object $entity + * @param integer $assume The state to assume if the state is not yet known (not MANAGED or REMOVED). + * This parameter can be set to improve performance of entity state detection + * by potentially avoiding a database lookup if the distinction between NEW and DETACHED + * is either known or does not matter for the caller of the method. + * + * @return int The entity state. + */ + public function getEntityState($entity, $assume = null) + { + $oid = spl_object_hash($entity); + + if (isset($this->entityStates[$oid])) { + return $this->entityStates[$oid]; + } + + if ($assume !== null) { + return $assume; + } + + // State can only be NEW or DETACHED, because MANAGED/REMOVED states are known. + // Note that you can not remember the NEW or DETACHED state in _entityStates since + // the UoW does not hold references to such objects and the object hash can be reused. + // More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it. + $class = $this->em->getClassMetadata(get_class($entity)); + $id = $class->getIdentifierValues($entity); + + if ( ! $id) { + return self::STATE_NEW; + } + + switch (true) { + case ($class->isIdentifierNatural()); + // Check for a version field, if available, to avoid a db lookup. + if ($class->isVersioned) { + return ($class->getFieldValue($entity, $class->versionField)) + ? self::STATE_DETACHED + : self::STATE_NEW; + } + + // Last try before db lookup: check the identity map. + if ($this->tryGetById($id, $class->rootEntityName)) { + return self::STATE_DETACHED; + } + + // db lookup + if ($this->getEntityPersister($class->name)->exists($entity)) { + return self::STATE_DETACHED; + } + + return self::STATE_NEW; + + case ( ! $class->idGenerator->isPostInsertGenerator()): + // if we have a pre insert generator we can't be sure that having an id + // really means that the entity exists. We have to verify this through + // the last resort: a db lookup + + // Last try before db lookup: check the identity map. + if ($this->tryGetById($id, $class->rootEntityName)) { + return self::STATE_DETACHED; + } + + // db lookup + if ($this->getEntityPersister($class->name)->exists($entity)) { + return self::STATE_DETACHED; + } + + return self::STATE_NEW; + + default: + return self::STATE_DETACHED; + } + } + + /** + * INTERNAL: + * Removes an entity from the identity map. This effectively detaches the + * entity from the persistence management of Doctrine. + * + * @ignore + * @param object $entity + * + * @throws ORMInvalidArgumentException + * + * @return boolean + */ + public function removeFromIdentityMap($entity) + { + $oid = spl_object_hash($entity); + $classMetadata = $this->em->getClassMetadata(get_class($entity)); + $idHash = implode(' ', $this->entityIdentifiers[$oid]); + + if ($idHash === '') { + throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "remove from identity map"); + } + + $className = $classMetadata->rootEntityName; + + if (isset($this->identityMap[$className][$idHash])) { + unset($this->identityMap[$className][$idHash]); + unset($this->readOnlyObjects[$oid]); + + //$this->entityStates[$oid] = self::STATE_DETACHED; + + return true; + } + + return false; + } + + /** + * INTERNAL: + * Gets an entity in the identity map by its identifier hash. + * + * @ignore + * @param string $idHash + * @param string $rootClassName + * + * @return object + */ + public function getByIdHash($idHash, $rootClassName) + { + return $this->identityMap[$rootClassName][$idHash]; + } + + /** + * INTERNAL: + * Tries to get an entity by its identifier hash. If no entity is found for + * the given hash, FALSE is returned. + * + * @ignore + * @param string $idHash + * @param string $rootClassName + * + * @return mixed The found entity or FALSE. + */ + public function tryGetByIdHash($idHash, $rootClassName) + { + if (isset($this->identityMap[$rootClassName][$idHash])) { + return $this->identityMap[$rootClassName][$idHash]; + } + + return false; + } + + /** + * Checks whether an entity is registered in the identity map of this UnitOfWork. + * + * @param object $entity + * + * @return boolean + */ + public function isInIdentityMap($entity) + { + $oid = spl_object_hash($entity); + + if ( ! isset($this->entityIdentifiers[$oid])) { + return false; + } + + $classMetadata = $this->em->getClassMetadata(get_class($entity)); + $idHash = implode(' ', $this->entityIdentifiers[$oid]); + + if ($idHash === '') { + return false; + } + + return isset($this->identityMap[$classMetadata->rootEntityName][$idHash]); + } + + /** + * INTERNAL: + * Checks whether an identifier hash exists in the identity map. + * + * @ignore + * @param string $idHash + * @param string $rootClassName + * + * @return boolean + */ + public function containsIdHash($idHash, $rootClassName) + { + return isset($this->identityMap[$rootClassName][$idHash]); + } + + /** + * Persists an entity as part of the current unit of work. + * + * @param object $entity The entity to persist. + */ + public function persist($entity) + { + $visited = array(); + + $this->doPersist($entity, $visited); + } + + /** + * Persists an entity as part of the current unit of work. + * + * This method is internally called during persist() cascades as it tracks + * the already visited entities to prevent infinite recursions. + * + * @param object $entity The entity to persist. + * @param array $visited The already visited entities. + * + * @throws ORMInvalidArgumentException + * @throws UnexpectedValueException + */ + private function doPersist($entity, array &$visited) + { + $oid = spl_object_hash($entity); + + if (isset($visited[$oid])) { + return; // Prevent infinite recursion + } + + $visited[$oid] = $entity; // Mark visited + + $class = $this->em->getClassMetadata(get_class($entity)); + + // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation). + // If we would detect DETACHED here we would throw an exception anyway with the same + // consequences (not recoverable/programming error), so just assuming NEW here + // lets us avoid some database lookups for entities with natural identifiers. + $entityState = $this->getEntityState($entity, self::STATE_NEW); + + switch ($entityState) { + case self::STATE_MANAGED: + // Nothing to do, except if policy is "deferred explicit" + if ($class->isChangeTrackingDeferredExplicit()) { + $this->scheduleForDirtyCheck($entity); + } + break; + + case self::STATE_NEW: + $this->persistNew($class, $entity); + break; + + case self::STATE_REMOVED: + // Entity becomes managed again + unset($this->entityDeletions[$oid]); + + $this->entityStates[$oid] = self::STATE_MANAGED; + break; + + case self::STATE_DETACHED: + // Can actually not happen right now since we assume STATE_NEW. + throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted"); + + default: + throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity)); + } + + $this->cascadePersist($entity, $visited); + } + + /** + * Deletes an entity as part of the current unit of work. + * + * @param object $entity The entity to remove. + */ + public function remove($entity) + { + $visited = array(); + + $this->doRemove($entity, $visited); + } + + /** + * Deletes an entity as part of the current unit of work. + * + * This method is internally called during delete() cascades as it tracks + * the already visited entities to prevent infinite recursions. + * + * @param object $entity The entity to delete. + * @param array $visited The map of the already visited entities. + * + * @throws ORMInvalidArgumentException If the instance is a detached entity. + * @throws UnexpectedValueException + */ + private function doRemove($entity, array &$visited) + { + $oid = spl_object_hash($entity); + + if (isset($visited[$oid])) { + return; // Prevent infinite recursion + } + + $visited[$oid] = $entity; // mark visited + + // Cascade first, because scheduleForDelete() removes the entity from the identity map, which + // can cause problems when a lazy proxy has to be initialized for the cascade operation. + $this->cascadeRemove($entity, $visited); + + $class = $this->em->getClassMetadata(get_class($entity)); + $entityState = $this->getEntityState($entity); + + switch ($entityState) { + case self::STATE_NEW: + case self::STATE_REMOVED: + // nothing to do + break; + + case self::STATE_MANAGED: + if (isset($class->lifecycleCallbacks[Events::preRemove])) { + $class->invokeLifecycleCallbacks(Events::preRemove, $entity); + } + + if ($this->evm->hasListeners(Events::preRemove)) { + $this->evm->dispatchEvent(Events::preRemove, new LifecycleEventArgs($entity, $this->em)); + } + + $this->scheduleForDelete($entity); + break; + + case self::STATE_DETACHED: + throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed"); + default: + throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity)); + } + + } + + /** + * Merges the state of the given detached entity into this UnitOfWork. + * + * @param object $entity + * + * @throws OptimisticLockException If the entity uses optimistic locking through a version + * attribute and the version check against the managed copy fails. + * + * @return object The managed copy of the entity. + * + * @todo Require active transaction!? OptimisticLockException may result in undefined state!? + */ + public function merge($entity) + { + $visited = array(); + + return $this->doMerge($entity, $visited); + } + + /** + * Executes a merge operation on an entity. + * + * @param object $entity + * @param array $visited + * @param object $prevManagedCopy + * @param array $assoc + * + * @throws OptimisticLockException If the entity uses optimistic locking through a version + * attribute and the version check against the managed copy fails. + * @throws ORMInvalidArgumentException If the entity instance is NEW. + * @throws EntityNotFoundException + * + * @return object The managed copy of the entity. + */ + private function doMerge($entity, array &$visited, $prevManagedCopy = null, $assoc = null) + { + $oid = spl_object_hash($entity); + + if (isset($visited[$oid])) { + return $visited[$oid]; // Prevent infinite recursion + } + + $visited[$oid] = $entity; // mark visited + + $class = $this->em->getClassMetadata(get_class($entity)); + + // First we assume DETACHED, although it can still be NEW but we can avoid + // an extra db-roundtrip this way. If it is not MANAGED but has an identity, + // we need to fetch it from the db anyway in order to merge. + // MANAGED entities are ignored by the merge operation. + $managedCopy = $entity; + + if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) { + if ($entity instanceof Proxy && ! $entity->__isInitialized__) { + $entity->__load(); + } + + // Try to look the entity up in the identity map. + $id = $class->getIdentifierValues($entity); + + // If there is no ID, it is actually NEW. + if ( ! $id) { + $managedCopy = $this->newInstance($class); + + $this->persistNew($class, $managedCopy); + } else { + $flatId = $id; + if ($class->containsForeignIdentifier) { + // convert foreign identifiers into scalar foreign key + // values to avoid object to string conversion failures. + foreach ($id as $idField => $idValue) { + if (isset($class->associationMappings[$idField])) { + $targetClassMetadata = $this->em->getClassMetadata($class->associationMappings[$idField]['targetEntity']); + $associatedId = $this->getEntityIdentifier($idValue); + + $flatId[$idField] = $associatedId[$targetClassMetadata->identifier[0]]; + } + } + } + + $managedCopy = $this->tryGetById($flatId, $class->rootEntityName); + + if ($managedCopy) { + // We have the entity in-memory already, just make sure its not removed. + if ($this->getEntityState($managedCopy) == self::STATE_REMOVED) { + throw ORMInvalidArgumentException::entityIsRemoved($managedCopy, "merge"); + } + } else { + // We need to fetch the managed copy in order to merge. + $managedCopy = $this->em->find($class->name, $flatId); + } + + if ($managedCopy === null) { + // If the identifier is ASSIGNED, it is NEW, otherwise an error + // since the managed entity was not found. + if ( ! $class->isIdentifierNatural()) { + throw new EntityNotFoundException; + } + + $managedCopy = $this->newInstance($class); + $class->setIdentifierValues($managedCopy, $id); + + $this->persistNew($class, $managedCopy); + } else { + if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized__) { + $managedCopy->__load(); + } + } + } + + if ($class->isVersioned) { + $managedCopyVersion = $class->reflFields[$class->versionField]->getValue($managedCopy); + $entityVersion = $class->reflFields[$class->versionField]->getValue($entity); + + // Throw exception if versions dont match. + if ($managedCopyVersion != $entityVersion) { + throw OptimisticLockException::lockFailedVersionMissmatch($entity, $entityVersion, $managedCopyVersion); + } + } + + // Merge state of $entity into existing (managed) entity + foreach ($class->reflClass->getProperties() as $prop) { + $name = $prop->name; + $prop->setAccessible(true); + if ( ! isset($class->associationMappings[$name])) { + if ( ! $class->isIdentifier($name)) { + $prop->setValue($managedCopy, $prop->getValue($entity)); + } + } else { + $assoc2 = $class->associationMappings[$name]; + if ($assoc2['type'] & ClassMetadata::TO_ONE) { + $other = $prop->getValue($entity); + if ($other === null) { + $prop->setValue($managedCopy, null); + } else if ($other instanceof Proxy && !$other->__isInitialized__) { + // do not merge fields marked lazy that have not been fetched. + continue; + } else if ( ! $assoc2['isCascadeMerge']) { + if ($this->getEntityState($other, self::STATE_DETACHED) !== self::STATE_MANAGED) { + $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']); + $relatedId = $targetClass->getIdentifierValues($other); + + if ($targetClass->subClasses) { + $other = $this->em->find($targetClass->name, $relatedId); + } else { + $other = $this->em->getProxyFactory()->getProxy($assoc2['targetEntity'], $relatedId); + $this->registerManaged($other, $relatedId, array()); + } + } + $prop->setValue($managedCopy, $other); + } + } else { + $mergeCol = $prop->getValue($entity); + if ($mergeCol instanceof PersistentCollection && !$mergeCol->isInitialized()) { + // do not merge fields marked lazy that have not been fetched. + // keep the lazy persistent collection of the managed copy. + continue; + } + + $managedCol = $prop->getValue($managedCopy); + if (!$managedCol) { + $managedCol = new PersistentCollection($this->em, + $this->em->getClassMetadata($assoc2['targetEntity']), + new ArrayCollection + ); + $managedCol->setOwner($managedCopy, $assoc2); + $prop->setValue($managedCopy, $managedCol); + $this->originalEntityData[$oid][$name] = $managedCol; + } + if ($assoc2['isCascadeMerge']) { + $managedCol->initialize(); + + // clear and set dirty a managed collection if its not also the same collection to merge from. + if (!$managedCol->isEmpty() && $managedCol !== $mergeCol) { + $managedCol->unwrap()->clear(); + $managedCol->setDirty(true); + + if ($assoc2['isOwningSide'] && $assoc2['type'] == ClassMetadata::MANY_TO_MANY && $class->isChangeTrackingNotify()) { + $this->scheduleForDirtyCheck($managedCopy); + } + } + } + } + } + + if ($class->isChangeTrackingNotify()) { + // Just treat all properties as changed, there is no other choice. + $this->propertyChanged($managedCopy, $name, null, $prop->getValue($managedCopy)); + } + } + + if ($class->isChangeTrackingDeferredExplicit()) { + $this->scheduleForDirtyCheck($entity); + } + } + + if ($prevManagedCopy !== null) { + $assocField = $assoc['fieldName']; + $prevClass = $this->em->getClassMetadata(get_class($prevManagedCopy)); + + if ($assoc['type'] & ClassMetadata::TO_ONE) { + $prevClass->reflFields[$assocField]->setValue($prevManagedCopy, $managedCopy); + } else { + $prevClass->reflFields[$assocField]->getValue($prevManagedCopy)->add($managedCopy); + + if ($assoc['type'] == ClassMetadata::ONE_TO_MANY) { + $class->reflFields[$assoc['mappedBy']]->setValue($managedCopy, $prevManagedCopy); + } + } + } + + // Mark the managed copy visited as well + $visited[spl_object_hash($managedCopy)] = true; + + $this->cascadeMerge($entity, $managedCopy, $visited); + + return $managedCopy; + } + + /** + * Detaches an entity from the persistence management. It's persistence will + * no longer be managed by Doctrine. + * + * @param object $entity The entity to detach. + */ + public function detach($entity) + { + $visited = array(); + + $this->doDetach($entity, $visited); + } + + /** + * Executes a detach operation on the given entity. + * + * @param object $entity + * @param array $visited + * @param boolean $noCascade if true, don't cascade detach operation + */ + private function doDetach($entity, array &$visited, $noCascade = false) + { + $oid = spl_object_hash($entity); + + if (isset($visited[$oid])) { + return; // Prevent infinite recursion + } + + $visited[$oid] = $entity; // mark visited + + switch ($this->getEntityState($entity, self::STATE_DETACHED)) { + case self::STATE_MANAGED: + if ($this->isInIdentityMap($entity)) { + $this->removeFromIdentityMap($entity); + } + + unset( + $this->entityInsertions[$oid], + $this->entityUpdates[$oid], + $this->entityDeletions[$oid], + $this->entityIdentifiers[$oid], + $this->entityStates[$oid], + $this->originalEntityData[$oid] + ); + break; + case self::STATE_NEW: + case self::STATE_DETACHED: + return; + } + + if ( ! $noCascade) { + $this->cascadeDetach($entity, $visited); + } + } + + /** + * Refreshes the state of the given entity from the database, overwriting + * any local, unpersisted changes. + * + * @param object $entity The entity to refresh. + * + * @throws InvalidArgumentException If the entity is not MANAGED. + */ + public function refresh($entity) + { + $visited = array(); + + $this->doRefresh($entity, $visited); + } + + /** + * Executes a refresh operation on an entity. + * + * @param object $entity The entity to refresh. + * @param array $visited The already visited entities during cascades. + * + * @throws ORMInvalidArgumentException If the entity is not MANAGED. + */ + private function doRefresh($entity, array &$visited) + { + $oid = spl_object_hash($entity); + + if (isset($visited[$oid])) { + return; // Prevent infinite recursion + } + + $visited[$oid] = $entity; // mark visited + + $class = $this->em->getClassMetadata(get_class($entity)); + + if ($this->getEntityState($entity) !== self::STATE_MANAGED) { + throw ORMInvalidArgumentException::entityNotManaged($entity); + } + + $this->getEntityPersister($class->name)->refresh( + array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]), + $entity + ); + + $this->cascadeRefresh($entity, $visited); + } + + /** + * Cascades a refresh operation to associated entities. + * + * @param object $entity + * @param array $visited + */ + private function cascadeRefresh($entity, array &$visited) + { + $class = $this->em->getClassMetadata(get_class($entity)); + + $associationMappings = array_filter( + $class->associationMappings, + function ($assoc) { return $assoc['isCascadeRefresh']; } + ); + + foreach ($associationMappings as $assoc) { + $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); + + switch (true) { + case ($relatedEntities instanceof PersistentCollection): + // Unwrap so that foreach() does not initialize + $relatedEntities = $relatedEntities->unwrap(); + // break; is commented intentionally! + + case ($relatedEntities instanceof Collection): + case (is_array($relatedEntities)): + foreach ($relatedEntities as $relatedEntity) { + $this->doRefresh($relatedEntity, $visited); + } + break; + + case ($relatedEntities !== null): + $this->doRefresh($relatedEntities, $visited); + break; + + default: + // Do nothing + } + } + } + + /** + * Cascades a detach operation to associated entities. + * + * @param object $entity + * @param array $visited + */ + private function cascadeDetach($entity, array &$visited) + { + $class = $this->em->getClassMetadata(get_class($entity)); + + $associationMappings = array_filter( + $class->associationMappings, + function ($assoc) { return $assoc['isCascadeDetach']; } + ); + + foreach ($associationMappings as $assoc) { + $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); + + switch (true) { + case ($relatedEntities instanceof PersistentCollection): + // Unwrap so that foreach() does not initialize + $relatedEntities = $relatedEntities->unwrap(); + // break; is commented intentionally! + + case ($relatedEntities instanceof Collection): + case (is_array($relatedEntities)): + foreach ($relatedEntities as $relatedEntity) { + $this->doDetach($relatedEntity, $visited); + } + break; + + case ($relatedEntities !== null): + $this->doDetach($relatedEntities, $visited); + break; + + default: + // Do nothing + } + } + } + + /** + * Cascades a merge operation to associated entities. + * + * @param object $entity + * @param object $managedCopy + * @param array $visited + */ + private function cascadeMerge($entity, $managedCopy, array &$visited) + { + $class = $this->em->getClassMetadata(get_class($entity)); + + $associationMappings = array_filter( + $class->associationMappings, + function ($assoc) { return $assoc['isCascadeMerge']; } + ); + + foreach ($associationMappings as $assoc) { + $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); + + if ($relatedEntities instanceof Collection) { + if ($relatedEntities === $class->reflFields[$assoc['fieldName']]->getValue($managedCopy)) { + continue; + } + + if ($relatedEntities instanceof PersistentCollection) { + // Unwrap so that foreach() does not initialize + $relatedEntities = $relatedEntities->unwrap(); + } + + foreach ($relatedEntities as $relatedEntity) { + $this->doMerge($relatedEntity, $visited, $managedCopy, $assoc); + } + } else if ($relatedEntities !== null) { + $this->doMerge($relatedEntities, $visited, $managedCopy, $assoc); + } + } + } + + /** + * Cascades the save operation to associated entities. + * + * @param object $entity + * @param array $visited + * + * @return void + */ + private function cascadePersist($entity, array &$visited) + { + $class = $this->em->getClassMetadata(get_class($entity)); + + $associationMappings = array_filter( + $class->associationMappings, + function ($assoc) { return $assoc['isCascadePersist']; } + ); + + foreach ($associationMappings as $assoc) { + $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); + + switch (true) { + case ($relatedEntities instanceof PersistentCollection): + // Unwrap so that foreach() does not initialize + $relatedEntities = $relatedEntities->unwrap(); + // break; is commented intentionally! + + case ($relatedEntities instanceof Collection): + case (is_array($relatedEntities)): + foreach ($relatedEntities as $relatedEntity) { + $this->doPersist($relatedEntity, $visited); + } + break; + + case ($relatedEntities !== null): + $this->doPersist($relatedEntities, $visited); + break; + + default: + // Do nothing + } + } + } + + /** + * Cascades the delete operation to associated entities. + * + * @param object $entity + * @param array $visited + */ + private function cascadeRemove($entity, array &$visited) + { + $class = $this->em->getClassMetadata(get_class($entity)); + + $associationMappings = array_filter( + $class->associationMappings, + function ($assoc) { return $assoc['isCascadeRemove']; } + ); + + foreach ($associationMappings as $assoc) { + if ($entity instanceof Proxy && !$entity->__isInitialized__) { + $entity->__load(); + } + + $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); + + switch (true) { + case ($relatedEntities instanceof Collection): + case (is_array($relatedEntities)): + // If its a PersistentCollection initialization is intended! No unwrap! + foreach ($relatedEntities as $relatedEntity) { + $this->doRemove($relatedEntity, $visited); + } + break; + + case ($relatedEntities !== null): + $this->doRemove($relatedEntities, $visited); + break; + + default: + // Do nothing + } + } + } + + /** + * Acquire a lock on the given entity. + * + * @param object $entity + * @param int $lockMode + * @param int $lockVersion + * + * @throws ORMInvalidArgumentException + * @throws TransactionRequiredException + * @throws OptimisticLockException + * + * @return void + */ + public function lock($entity, $lockMode, $lockVersion = null) + { + if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) { + throw ORMInvalidArgumentException::entityNotManaged($entity); + } + + $class = $this->em->getClassMetadata(get_class($entity)); + + switch ($lockMode) { + case \Doctrine\DBAL\LockMode::OPTIMISTIC; + if ( ! $class->isVersioned) { + throw OptimisticLockException::notVersioned($class->name); + } + + if ($lockVersion === null) { + return; + } + + $entityVersion = $class->reflFields[$class->versionField]->getValue($entity); + + if ($entityVersion != $lockVersion) { + throw OptimisticLockException::lockFailedVersionMissmatch($entity, $lockVersion, $entityVersion); + } + + break; + + case \Doctrine\DBAL\LockMode::PESSIMISTIC_READ: + case \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE: + if (!$this->em->getConnection()->isTransactionActive()) { + throw TransactionRequiredException::transactionRequired(); + } + + $oid = spl_object_hash($entity); + + $this->getEntityPersister($class->name)->lock( + array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]), + $lockMode + ); + break; + + default: + // Do nothing + } + } + + /** + * Gets the CommitOrderCalculator used by the UnitOfWork to order commits. + * + * @return \Doctrine\ORM\Internal\CommitOrderCalculator + */ + public function getCommitOrderCalculator() + { + if ($this->commitOrderCalculator === null) { + $this->commitOrderCalculator = new Internal\CommitOrderCalculator; + } + + return $this->commitOrderCalculator; + } + + /** + * Clears the UnitOfWork. + * + * @param string $entityName if given, only entities of this type will get detached + */ + public function clear($entityName = null) + { + if ($entityName === null) { + $this->identityMap = + $this->entityIdentifiers = + $this->originalEntityData = + $this->entityChangeSets = + $this->entityStates = + $this->scheduledForDirtyCheck = + $this->entityInsertions = + $this->entityUpdates = + $this->entityDeletions = + $this->collectionDeletions = + $this->collectionUpdates = + $this->extraUpdates = + $this->readOnlyObjects = + $this->orphanRemovals = array(); + + if ($this->commitOrderCalculator !== null) { + $this->commitOrderCalculator->clear(); + } + } else { + $visited = array(); + foreach ($this->identityMap as $className => $entities) { + if ($className === $entityName) { + foreach ($entities as $entity) { + $this->doDetach($entity, $visited, true); + } + } + } + } + + if ($this->evm->hasListeners(Events::onClear)) { + $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName)); + } + } + + /** + * INTERNAL: + * Schedules an orphaned entity for removal. The remove() operation will be + * invoked on that entity at the beginning of the next commit of this + * UnitOfWork. + * + * @ignore + * @param object $entity + */ + public function scheduleOrphanRemoval($entity) + { + $this->orphanRemovals[spl_object_hash($entity)] = $entity; + } + + /** + * INTERNAL: + * Schedules a complete collection for removal when this UnitOfWork commits. + * + * @param PersistentCollection $coll + */ + public function scheduleCollectionDeletion(PersistentCollection $coll) + { + $coid = spl_object_hash($coll); + + //TODO: if $coll is already scheduled for recreation ... what to do? + // Just remove $coll from the scheduled recreations? + if (isset($this->collectionUpdates[$coid])) { + unset($this->collectionUpdates[$coid]); + } + + $this->collectionDeletions[$coid] = $coll; + } + + /** + * @param PersistentCollection $coll + * + * @return bool + */ + public function isCollectionScheduledForDeletion(PersistentCollection $coll) + { + return isset($this->collectionDeletions[spl_object_hash($coll)]); + } + + /** + * @param ClassMetadata $class + * + * @return \Doctrine\Common\Persistence\ObjectManagerAware|object + */ + private function newInstance($class) + { + $entity = $class->newInstance(); + + if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) { + $entity->injectObjectManager($this->em, $class); + } + + return $entity; + } + + /** + * INTERNAL: + * Creates an entity. Used for reconstitution of persistent entities. + * + * @ignore + * @param string $className The name of the entity class. + * @param array $data The data for the entity. + * @param array $hints Any hints to account for during reconstitution/lookup of the entity. + * + * @return object The managed entity instance. + * @internal Highly performance-sensitive method. + * + * @todo Rename: getOrCreateEntity + */ + public function createEntity($className, array $data, &$hints = array()) + { + $class = $this->em->getClassMetadata($className); + //$isReadOnly = isset($hints[Query::HINT_READ_ONLY]); + + if ($class->isIdentifierComposite) { + $id = array(); + + foreach ($class->identifier as $fieldName) { + $id[$fieldName] = isset($class->associationMappings[$fieldName]) + ? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']] + : $data[$fieldName]; + } + + $idHash = implode(' ', $id); + } else { + $idHash = isset($class->associationMappings[$class->identifier[0]]) + ? $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']] + : $data[$class->identifier[0]]; + + $id = array($class->identifier[0] => $idHash); + } + + if (isset($this->identityMap[$class->rootEntityName][$idHash])) { + $entity = $this->identityMap[$class->rootEntityName][$idHash]; + $oid = spl_object_hash($entity); + + if ($entity instanceof Proxy && ! $entity->__isInitialized__) { + $entity->__isInitialized__ = true; + $overrideLocalValues = true; + + if ($entity instanceof NotifyPropertyChanged) { + $entity->addPropertyChangedListener($this); + } + } else { + $overrideLocalValues = isset($hints[Query::HINT_REFRESH]); + + // If only a specific entity is set to refresh, check that it's the one + if(isset($hints[Query::HINT_REFRESH_ENTITY])) { + $overrideLocalValues = $hints[Query::HINT_REFRESH_ENTITY] === $entity; + + // inject ObjectManager into just loaded proxies. + if ($overrideLocalValues && $entity instanceof ObjectManagerAware) { + $entity->injectObjectManager($this->em, $class); + } + } + } + + if ($overrideLocalValues) { + $this->originalEntityData[$oid] = $data; + } + } else { + $entity = $this->newInstance($class); + $oid = spl_object_hash($entity); + + $this->entityIdentifiers[$oid] = $id; + $this->entityStates[$oid] = self::STATE_MANAGED; + $this->originalEntityData[$oid] = $data; + + $this->identityMap[$class->rootEntityName][$idHash] = $entity; + + if ($entity instanceof NotifyPropertyChanged) { + $entity->addPropertyChangedListener($this); + } + + $overrideLocalValues = true; + } + + if ( ! $overrideLocalValues) { + return $entity; + } + + foreach ($data as $field => $value) { + if (isset($class->fieldMappings[$field])) { + $class->reflFields[$field]->setValue($entity, $value); + } + } + + // Loading the entity right here, if its in the eager loading map get rid of it there. + unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]); + + if (isset($this->eagerLoadingEntities[$class->rootEntityName]) && ! $this->eagerLoadingEntities[$class->rootEntityName]) { + unset($this->eagerLoadingEntities[$class->rootEntityName]); + } + + // Properly initialize any unfetched associations, if partial objects are not allowed. + if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) { + return $entity; + } + + foreach ($class->associationMappings as $field => $assoc) { + // Check if the association is not among the fetch-joined associations already. + if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) { + continue; + } + + $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); + + switch (true) { + case ($assoc['type'] & ClassMetadata::TO_ONE): + if ( ! $assoc['isOwningSide']) { + // Inverse side of x-to-one can never be lazy + $class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity)); + + continue 2; + } + + $associatedId = array(); + + // TODO: Is this even computed right in all cases of composite keys? + foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) { + $joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null; + + if ($joinColumnValue !== null) { + if ($targetClass->containsForeignIdentifier) { + $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue; + } else { + $associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue; + } + } + } + + if ( ! $associatedId) { + // Foreign key is NULL + $class->reflFields[$field]->setValue($entity, null); + $this->originalEntityData[$oid][$field] = null; + + continue; + } + + if ( ! isset($hints['fetchMode'][$class->name][$field])) { + $hints['fetchMode'][$class->name][$field] = $assoc['fetch']; + } + + // Foreign key is set + // Check identity map first + // FIXME: Can break easily with composite keys if join column values are in + // wrong order. The correct order is the one in ClassMetadata#identifier. + $relatedIdHash = implode(' ', $associatedId); + + switch (true) { + case (isset($this->identityMap[$targetClass->rootEntityName][$relatedIdHash])): + $newValue = $this->identityMap[$targetClass->rootEntityName][$relatedIdHash]; + + // If this is an uninitialized proxy, we are deferring eager loads, + // this association is marked as eager fetch, and its an uninitialized proxy (wtf!) + // then we can append this entity for eager loading! + if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER && + isset($hints['deferEagerLoad']) && + !$targetClass->isIdentifierComposite && + $newValue instanceof Proxy && + $newValue->__isInitialized__ === false) { + + $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId); + } + + break; + + case ($targetClass->subClasses): + // If it might be a subtype, it can not be lazy. There isn't even + // a way to solve this with deferred eager loading, which means putting + // an entity with subclasses at a *-to-one location is really bad! (performance-wise) + $newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId); + break; + + default: + switch (true) { + // We are negating the condition here. Other cases will assume it is valid! + case ($hints['fetchMode'][$class->name][$field] !== ClassMetadata::FETCH_EAGER): + $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId); + break; + + // Deferred eager load only works for single identifier classes + case (isset($hints['deferEagerLoad']) && ! $targetClass->isIdentifierComposite): + // TODO: Is there a faster approach? + $this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId); + + $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId); + break; + + default: + // TODO: This is very imperformant, ignore it? + $newValue = $this->em->find($assoc['targetEntity'], $associatedId); + break; + } + + // PERF: Inlined & optimized code from UnitOfWork#registerManaged() + $newValueOid = spl_object_hash($newValue); + $this->entityIdentifiers[$newValueOid] = $associatedId; + $this->identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue; + $this->entityStates[$newValueOid] = self::STATE_MANAGED; + // make sure that when an proxy is then finally loaded, $this->originalEntityData is set also! + break; + } + + $this->originalEntityData[$oid][$field] = $newValue; + $class->reflFields[$field]->setValue($entity, $newValue); + + if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) { + $inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']]; + $targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($newValue, $entity); + } + + break; + + default: + // Inject collection + $pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection); + $pColl->setOwner($entity, $assoc); + $pColl->setInitialized(false); + + $reflField = $class->reflFields[$field]; + $reflField->setValue($entity, $pColl); + + if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) { + $this->loadCollection($pColl); + $pColl->takeSnapshot(); + } + + $this->originalEntityData[$oid][$field] = $pColl; + break; + } + } + + if ($overrideLocalValues) { + if (isset($class->lifecycleCallbacks[Events::postLoad])) { + $class->invokeLifecycleCallbacks(Events::postLoad, $entity); + } + + + if ($this->evm->hasListeners(Events::postLoad)) { + $this->evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->em)); + } + } + + return $entity; + } + + /** + * @return void + */ + public function triggerEagerLoads() + { + if ( ! $this->eagerLoadingEntities) { + return; + } + + // avoid infinite recursion + $eagerLoadingEntities = $this->eagerLoadingEntities; + $this->eagerLoadingEntities = array(); + + foreach ($eagerLoadingEntities as $entityName => $ids) { + if ( ! $ids) { + continue; + } + + $class = $this->em->getClassMetadata($entityName); + + $this->getEntityPersister($entityName)->loadAll( + array_combine($class->identifier, array(array_values($ids))) + ); + } + } + + /** + * Initializes (loads) an uninitialized persistent collection of an entity. + * + * @param \Doctrine\ORM\PersistentCollection $collection The collection to initialize. + * + * @return void + * @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733. + */ + public function loadCollection(PersistentCollection $collection) + { + $assoc = $collection->getMapping(); + $persister = $this->getEntityPersister($assoc['targetEntity']); + + switch ($assoc['type']) { + case ClassMetadata::ONE_TO_MANY: + $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection); + break; + + case ClassMetadata::MANY_TO_MANY: + $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection); + break; + } + } + + /** + * Gets the identity map of the UnitOfWork. + * + * @return array + */ + public function getIdentityMap() + { + return $this->identityMap; + } + + /** + * Gets the original data of an entity. The original data is the data that was + * present at the time the entity was reconstituted from the database. + * + * @param object $entity + * + * @return array + */ + public function getOriginalEntityData($entity) + { + $oid = spl_object_hash($entity); + + if (isset($this->originalEntityData[$oid])) { + return $this->originalEntityData[$oid]; + } + + return array(); + } + + /** + * @ignore + */ + public function setOriginalEntityData($entity, array $data) + { + $this->originalEntityData[spl_object_hash($entity)] = $data; + } + + /** + * INTERNAL: + * Sets a property value of the original data array of an entity. + * + * @ignore + * @param string $oid + * @param string $property + * @param mixed $value + */ + public function setOriginalEntityProperty($oid, $property, $value) + { + $this->originalEntityData[$oid][$property] = $value; + } + + /** + * Gets the identifier of an entity. + * The returned value is always an array of identifier values. If the entity + * has a composite identifier then the identifier values are in the same + * order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames(). + * + * @param object $entity + * + * @return array The identifier values. + */ + public function getEntityIdentifier($entity) + { + return $this->entityIdentifiers[spl_object_hash($entity)]; + } + + /** + * Tries to find an entity with the given identifier in the identity map of + * this UnitOfWork. + * + * @param mixed $id The entity identifier to look for. + * @param string $rootClassName The name of the root class of the mapped entity hierarchy. + * + * @return mixed Returns the entity with the specified identifier if it exists in + * this UnitOfWork, FALSE otherwise. + */ + public function tryGetById($id, $rootClassName) + { + $idHash = implode(' ', (array) $id); + + if (isset($this->identityMap[$rootClassName][$idHash])) { + return $this->identityMap[$rootClassName][$idHash]; + } + + return false; + } + + /** + * Schedules an entity for dirty-checking at commit-time. + * + * @param object $entity The entity to schedule for dirty-checking. + * @todo Rename: scheduleForSynchronization + */ + public function scheduleForDirtyCheck($entity) + { + $rootClassName = $this->em->getClassMetadata(get_class($entity))->rootEntityName; + + $this->scheduledForDirtyCheck[$rootClassName][spl_object_hash($entity)] = $entity; + } + + /** + * Checks whether the UnitOfWork has any pending insertions. + * + * @return boolean TRUE if this UnitOfWork has pending insertions, FALSE otherwise. + */ + public function hasPendingInsertions() + { + return ! empty($this->entityInsertions); + } + + /** + * Calculates the size of the UnitOfWork. The size of the UnitOfWork is the + * number of entities in the identity map. + * + * @return integer + */ + public function size() + { + $countArray = array_map(function ($item) { return count($item); }, $this->identityMap); + + return array_sum($countArray); + } + + /** + * Gets the EntityPersister for an Entity. + * + * @param string $entityName The name of the Entity. + * + * @return \Doctrine\ORM\Persisters\BasicEntityPersister + */ + public function getEntityPersister($entityName) + { + if (isset($this->persisters[$entityName])) { + return $this->persisters[$entityName]; + } + + $class = $this->em->getClassMetadata($entityName); + + switch (true) { + case ($class->isInheritanceTypeNone()): + $persister = new Persisters\BasicEntityPersister($this->em, $class); + break; + + case ($class->isInheritanceTypeSingleTable()): + $persister = new Persisters\SingleTablePersister($this->em, $class); + break; + + case ($class->isInheritanceTypeJoined()): + $persister = new Persisters\JoinedSubclassPersister($this->em, $class); + break; + + default: + $persister = new Persisters\UnionSubclassPersister($this->em, $class); + } + + $this->persisters[$entityName] = $persister; + + return $this->persisters[$entityName]; + } + + /** + * Gets a collection persister for a collection-valued association. + * + * @param array $association + * + * @return \Doctrine\ORM\Persisters\AbstractCollectionPersister + */ + public function getCollectionPersister(array $association) + { + $type = $association['type']; + + if (isset($this->collectionPersisters[$type])) { + return $this->collectionPersisters[$type]; + } + + switch ($type) { + case ClassMetadata::ONE_TO_MANY: + $persister = new Persisters\OneToManyPersister($this->em); + break; + + case ClassMetadata::MANY_TO_MANY: + $persister = new Persisters\ManyToManyPersister($this->em); + break; + } + + $this->collectionPersisters[$type] = $persister; + + return $this->collectionPersisters[$type]; + } + + /** + * INTERNAL: + * Registers an entity as managed. + * + * @param object $entity The entity. + * @param array $id The identifier values. + * @param array $data The original entity data. + */ + public function registerManaged($entity, array $id, array $data) + { + $oid = spl_object_hash($entity); + + $this->entityIdentifiers[$oid] = $id; + $this->entityStates[$oid] = self::STATE_MANAGED; + $this->originalEntityData[$oid] = $data; + + $this->addToIdentityMap($entity); + + if ($entity instanceof NotifyPropertyChanged) { + $entity->addPropertyChangedListener($this); + } + } + + /** + * INTERNAL: + * Clears the property changeset of the entity with the given OID. + * + * @param string $oid The entity's OID. + */ + public function clearEntityChangeSet($oid) + { + $this->entityChangeSets[$oid] = array(); + } + + /* PropertyChangedListener implementation */ + + /** + * Notifies this UnitOfWork of a property change in an entity. + * + * @param object $entity The entity that owns the property. + * @param string $propertyName The name of the property that changed. + * @param mixed $oldValue The old value of the property. + * @param mixed $newValue The new value of the property. + */ + public function propertyChanged($entity, $propertyName, $oldValue, $newValue) + { + $oid = spl_object_hash($entity); + $class = $this->em->getClassMetadata(get_class($entity)); + + $isAssocField = isset($class->associationMappings[$propertyName]); + + if ( ! $isAssocField && ! isset($class->fieldMappings[$propertyName])) { + return; // ignore non-persistent fields + } + + // Update changeset and mark entity for synchronization + $this->entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue); + + if ( ! isset($this->scheduledForDirtyCheck[$class->rootEntityName][$oid])) { + $this->scheduleForDirtyCheck($entity); + } + } + + /** + * Gets the currently scheduled entity insertions in this UnitOfWork. + * + * @return array + */ + public function getScheduledEntityInsertions() + { + return $this->entityInsertions; + } + + /** + * Gets the currently scheduled entity updates in this UnitOfWork. + * + * @return array + */ + public function getScheduledEntityUpdates() + { + return $this->entityUpdates; + } + + /** + * Gets the currently scheduled entity deletions in this UnitOfWork. + * + * @return array + */ + public function getScheduledEntityDeletions() + { + return $this->entityDeletions; + } + + /** + * Get the currently scheduled complete collection deletions + * + * @return array + */ + public function getScheduledCollectionDeletions() + { + return $this->collectionDeletions; + } + + /** + * Gets the currently scheduled collection inserts, updates and deletes. + * + * @return array + */ + public function getScheduledCollectionUpdates() + { + return $this->collectionUpdates; + } + + /** + * Helper method to initialize a lazy loading proxy or persistent collection. + * + * @param object + * + * @return void + */ + public function initializeObject($obj) + { + if ($obj instanceof Proxy) { + $obj->__load(); + + return; + } + + if ($obj instanceof PersistentCollection) { + $obj->initialize(); + } + } + + /** + * Helper method to show an object as string. + * + * @param object $obj + * + * @return string + */ + private static function objToStr($obj) + { + return method_exists($obj, '__toString') ? (string)$obj : get_class($obj).'@'.spl_object_hash($obj); + } + + /** + * Marks an entity as read-only so that it will not be considered for updates during UnitOfWork#commit(). + * + * This operation cannot be undone as some parts of the UnitOfWork now keep gathering information + * on this object that might be necessary to perform a correct update. + * + * + * @param object $object + * + * @throws ORMInvalidArgumentException + * + * @return void + */ + public function markReadOnly($object) + { + if ( ! is_object($object) || ! $this->isInIdentityMap($object)) { + throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object); + } + + $this->readOnlyObjects[spl_object_hash($object)] = true; + } + + /** + * Is this entity read only? + * + * @param object $object + * + * @throws ORMInvalidArgumentException + * + * @return bool + */ + public function isReadOnly($object) + { + if ( ! is_object($object)) { + throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object); + } + + return isset($this->readOnlyObjects[spl_object_hash($object)]); + } +} diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Version.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Version.php new file mode 100644 index 0000000..bca1835 --- /dev/null +++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Version.php @@ -0,0 +1,55 @@ +. + */ + +namespace Doctrine\ORM; + +/** + * Class to store and retrieve the version of Doctrine + * + * + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + * @author Benjamin Eberlei + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +class Version +{ + /** + * Current Doctrine Version + */ + const VERSION = '2.3.0'; + + /** + * Compares a Doctrine version with the current one. + * + * @param string $version Doctrine version to compare. + * @return int Returns -1 if older, 0 if it is the same, 1 if version + * passed as argument is newer. + */ + public static function compare($version) + { + $currentVersion = str_replace(' ', '', strtolower(self::VERSION)); + $version = str_replace(' ', '', $version); + + return version_compare($version, $currentVersion); + } +} diff --git a/vendor/doctrine/orm/phpunit.xml.dist b/vendor/doctrine/orm/phpunit.xml.dist new file mode 100644 index 0000000..3ab5edb --- /dev/null +++ b/vendor/doctrine/orm/phpunit.xml.dist @@ -0,0 +1,59 @@ + + + + + + + ./tests/Doctrine/Tests/ORM + + + + + + performance + locking_functional + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/run-all.sh b/vendor/doctrine/orm/run-all.sh new file mode 100644 index 0000000..80712ee --- /dev/null +++ b/vendor/doctrine/orm/run-all.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# This script is a small convenience wrapper for running the doctrine testsuite against a large bunch of databases. +# Just create the phpunit.xmls as described in the array below and configure the specific files section +# to connect to that database. Just omit a file if you dont have that database and the tests will be skipped. + +configs[1]="mysql.phpunit.xml" +configs[2]='postgres.phpunit.xml' +configs[3]='sqlite.phpunit.xml' +configs[4]='oracle.phpunit.xml' +configs[5]='db2.phpunit.xml' +configs[6]='pdo-ibm.phpunit.xml' +configs[7]='sqlsrv.phpunit.xml' + +for i in "${configs[@]}"; do + if [ -f "$i" ]; + then + echo "RUNNING TESTS WITH CONFIG $i" + phpunit -c "$i" "$@" + fi; +done diff --git a/vendor/doctrine/orm/tests/.gitignore b/vendor/doctrine/orm/tests/.gitignore new file mode 100644 index 0000000..7210405 --- /dev/null +++ b/vendor/doctrine/orm/tests/.gitignore @@ -0,0 +1,3 @@ +Doctrine/Tests/Proxies/ +Doctrine/Tests/ORM/Proxy/generated/ +Doctrine/Tests/ORM/Tools/Export/export diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/DbalFunctionalTestCase.php b/vendor/doctrine/orm/tests/Doctrine/Tests/DbalFunctionalTestCase.php new file mode 100644 index 0000000..c4705a2 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/DbalFunctionalTestCase.php @@ -0,0 +1,32 @@ +sharedFixture['conn'] = null; + self::$_sharedConn = null; + } + + protected function setUp() + { + if (isset($this->sharedFixture['conn'])) { + $this->_conn = $this->sharedFixture['conn']; + } else { + if ( ! isset(self::$_sharedConn)) { + self::$_sharedConn = TestUtil::getConnection(); + } + $this->_conn = self::$_sharedConn; + } + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/DbalTestCase.php b/vendor/doctrine/orm/tests/Doctrine/Tests/DbalTestCase.php new file mode 100644 index 0000000..2478e7b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/DbalTestCase.php @@ -0,0 +1,10 @@ +getIntegerTypeDeclarationSQL($fieldDeclaration); + } + + public function canRequireSQLConversion() + { + return true; + } + + public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) + { + return 'ABS(' . $sqlExpr . ')'; + } + + public function convertToPHPValueSQL($sqlExpr, $platform) + { + return '-(' . $sqlExpr . ')'; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php b/vendor/doctrine/orm/tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php new file mode 100644 index 0000000..47e8c79 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php @@ -0,0 +1,29 @@ +_generatorType = $type; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/ConnectionMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/ConnectionMock.php new file mode 100644 index 0000000..90ebfec --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/ConnectionMock.php @@ -0,0 +1,106 @@ +_platformMock = new DatabasePlatformMock(); + + parent::__construct($params, $driver, $config, $eventManager); + + // Override possible assignment of platform to database platform mock + $this->_platform = $this->_platformMock; + } + + /** + * @override + */ + public function getDatabasePlatform() + { + return $this->_platformMock; + } + + /** + * @override + */ + public function insert($tableName, array $data, array $types = array()) + { + $this->_inserts[$tableName][] = $data; + } + + /** + * @override + */ + public function executeUpdate($query, array $params = array(), array $types = array()) + { + $this->_executeUpdates[] = array('query' => $query, 'params' => $params, 'types' => $types); + } + + /** + * @override + */ + public function lastInsertId($seqName = null) + { + return $this->_lastInsertId; + } + + /** + * @override + */ + public function fetchColumn($statement, array $params = array(), $colnum = 0) + { + return $this->_fetchOneResult; + } + + /** + * @override + */ + public function quote($input, $type = null) + { + if (is_string($input)) { + return "'" . $input . "'"; + } + return $input; + } + + /* Mock API */ + + public function setFetchOneResult($fetchOneResult) + { + $this->_fetchOneResult = $fetchOneResult; + } + + public function setDatabasePlatform($platform) + { + $this->_platformMock = $platform; + } + + public function setLastInsertId($id) + { + $this->_lastInsertId = $id; + } + + public function getInserts() + { + return $this->_inserts; + } + + public function getExecuteUpdates() + { + return $this->_executeUpdates; + } + + public function reset() + { + $this->_inserts = array(); + $this->_lastInsertId = 0; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php new file mode 100644 index 0000000..b634408 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php @@ -0,0 +1,97 @@ +_prefersIdentityColumns; + } + + /** + * @override + */ + public function prefersSequences() + { + return $this->_prefersSequences; + } + + /** @override */ + public function getSequenceNextValSQL($sequenceName) + { + return $this->_sequenceNextValSql; + } + + /** @override */ + public function getBooleanTypeDeclarationSQL(array $field) {} + + /** @override */ + public function getIntegerTypeDeclarationSQL(array $field) {} + + /** @override */ + public function getBigIntTypeDeclarationSQL(array $field) {} + + /** @override */ + public function getSmallIntTypeDeclarationSQL(array $field) {} + + /** @override */ + protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) {} + + /** @override */ + public function getVarcharTypeDeclarationSQL(array $field) {} + + /** @override */ + public function getClobTypeDeclarationSQL(array $field) {} + + /* MOCK API */ + + public function setPrefersIdentityColumns($bool) + { + $this->_prefersIdentityColumns = $bool; + } + + public function setPrefersSequences($bool) + { + $this->_prefersSequences = $bool; + } + + public function setSequenceNextValSql($sql) + { + $this->_sequenceNextValSql = $sql; + } + + public function getName() + { + return 'mock'; + } + + protected function initializeDoctrineTypeMappings() + { + + } + /** + * Gets the SQL Snippet used to declare a BLOB column type. + */ + public function getBlobTypeDeclarationSQL(array $field) + { + throw DBALException::notSupported(__METHOD__); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php new file mode 100644 index 0000000..a18e24a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/DriverConnectionMock.php @@ -0,0 +1,17 @@ +_platformMock) { + $this->_platformMock = new DatabasePlatformMock; + } + return $this->_platformMock; + } + + /** + * @override + */ + public function getSchemaManager(\Doctrine\DBAL\Connection $conn) + { + if($this->_schemaManagerMock == null) { + return new SchemaManagerMock($conn); + } else { + return $this->_schemaManagerMock; + } + } + + /* MOCK API */ + + public function setDatabasePlatform(\Doctrine\DBAL\Platforms\AbstractPlatform $platform) + { + $this->_platformMock = $platform; + } + + public function setSchemaManager(\Doctrine\DBAL\Schema\AbstractSchemaManager $sm) + { + $this->_schemaManagerMock = $sm; + } + + public function getName() + { + return 'mock'; + } + + public function getDatabase(\Doctrine\DBAL\Connection $conn) + { + return; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/EntityManagerMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/EntityManagerMock.php new file mode 100644 index 0000000..ca49410 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/EntityManagerMock.php @@ -0,0 +1,106 @@ +. + */ + +namespace Doctrine\Tests\Mocks; + +use Doctrine\ORM\Proxy\ProxyFactory; + +/** + * Special EntityManager mock used for testing purposes. + */ +class EntityManagerMock extends \Doctrine\ORM\EntityManager +{ + private $_uowMock; + private $_proxyFactoryMock; + private $_idGenerators = array(); + + /** + * @override + */ + public function getUnitOfWork() + { + return isset($this->_uowMock) ? $this->_uowMock : parent::getUnitOfWork(); + } + + /* Mock API */ + + /** + * Sets a (mock) UnitOfWork that will be returned when getUnitOfWork() is called. + * + * @param $uow + */ + public function setUnitOfWork($uow) + { + $this->_uowMock = $uow; + } + + public function setProxyFactory($proxyFactory) + { + $this->_proxyFactoryMock = $proxyFactory; + } + + public function getProxyFactory() + { + return isset($this->_proxyFactoryMock) ? $this->_proxyFactoryMock : parent::getProxyFactory(); + } + + /** + * Mock factory method to create an EntityManager. + * + * @param unknown_type $conn + * @param unknown_type $name + * @param Doctrine_Configuration $config + * @param Doctrine_EventManager $eventManager + * @return Doctrine\ORM\EntityManager + */ + public static function create($conn, \Doctrine\ORM\Configuration $config = null, + \Doctrine\Common\EventManager $eventManager = null) + { + if (is_null($config)) { + $config = new \Doctrine\ORM\Configuration(); + $config->setProxyDir(__DIR__ . '/../Proxies'); + $config->setProxyNamespace('Doctrine\Tests\Proxies'); + $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver(array(), true)); + } + if (is_null($eventManager)) { + $eventManager = new \Doctrine\Common\EventManager(); + } + + return new EntityManagerMock($conn, $config, $eventManager); + } +/* + public function setIdGenerator($className, $generator) + { + $this->_idGenerators[$className] = $generator; + } +*/ + /** @override */ +/* public function getIdGenerator($className) + { + + if (isset($this->_idGenerators[$className])) { + return $this->_idGenerators[$className]; + } + + return parent::getIdGenerator($className); + } + */ +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/EntityPersisterMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/EntityPersisterMock.php new file mode 100644 index 0000000..768e357 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/EntityPersisterMock.php @@ -0,0 +1,100 @@ + $entity + * @return + * @override + */ + public function insert($entity) + { + $this->_inserts[] = $entity; + if ( ! is_null($this->_mockIdGeneratorType) && $this->_mockIdGeneratorType == \Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY + || $this->_class->isIdGeneratorIdentity()) { + $id = $this->_identityColumnValueCounter++; + $this->_postInsertIds[$id] = $entity; + return $id; + } + return null; + } + + public function addInsert($entity) + { + $this->_inserts[] = $entity; + if ( ! is_null($this->_mockIdGeneratorType) && $this->_mockIdGeneratorType == \Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY + || $this->_class->isIdGeneratorIdentity()) { + $id = $this->_identityColumnValueCounter++; + $this->_postInsertIds[$id] = $entity; + return $id; + } + return null; + } + + public function executeInserts() + { + return $this->_postInsertIds; + } + + public function setMockIdGeneratorType($genType) + { + $this->_mockIdGeneratorType = $genType; + } + + public function update($entity) + { + $this->_updates[] = $entity; + } + + public function exists($entity, array $extraConditions = array()) + { + $this->existsCalled = true; + } + + public function delete($entity) + { + $this->_deletes[] = $entity; + } + + public function getInserts() + { + return $this->_inserts; + } + + public function getUpdates() + { + return $this->_updates; + } + + public function getDeletes() + { + return $this->_deletes; + } + + public function reset() + { + $this->existsCalled = false; + $this->_identityColumnValueCounter = 0; + $this->_inserts = array(); + $this->_updates = array(); + $this->_deletes = array(); + } + + public function isExistsCalled() + { + return $this->existsCalled; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/HydratorMockStatement.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/HydratorMockStatement.php new file mode 100644 index 0000000..297d41e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/HydratorMockStatement.php @@ -0,0 +1,111 @@ + + */ +class HydratorMockStatement implements \IteratorAggregate, \Doctrine\DBAL\Driver\Statement +{ + private $_resultSet; + + /** + * Creates a new mock statement that will serve the provided fake result set to clients. + * + * @param array $resultSet The faked SQL result set. + */ + public function __construct(array $resultSet) + { + $this->_resultSet = $resultSet; + } + + /** + * Fetches all rows from the result set. + * + * @return array + */ + public function fetchAll($fetchStyle = null, $columnIndex = null, array $ctorArgs = null) + { + return $this->_resultSet; + } + + public function fetchColumn($columnNumber = 0) + { + $row = current($this->_resultSet); + if ( ! is_array($row)) return false; + $val = array_shift($row); + return $val !== null ? $val : false; + } + + /** + * Fetches the next row in the result set. + * + */ + public function fetch($fetchStyle = null) + { + $current = current($this->_resultSet); + next($this->_resultSet); + return $current; + } + + /** + * Closes the cursor, enabling the statement to be executed again. + * + * @return boolean + */ + public function closeCursor() + { + return true; + } + + public function setResultSet(array $resultSet) + { + reset($resultSet); + $this->_resultSet = $resultSet; + } + + public function bindColumn($column, &$param, $type = null) + { + } + + public function bindValue($param, $value, $type = null) + { + } + + public function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array()) + { + } + + public function columnCount() + { + } + + public function errorCode() + { + } + + public function errorInfo() + { + } + + public function execute($params = array()) + { + } + + public function rowCount() + { + } + + public function getIterator() + { + return $this->_resultSet; + } + + public function setFetchMode($fetchStyle, $arg2 = null, $arg3 = null) + { + + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/IdentityIdGeneratorMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/IdentityIdGeneratorMock.php new file mode 100644 index 0000000..0c5696b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/IdentityIdGeneratorMock.php @@ -0,0 +1,12 @@ +_mockPostInsertId = $id; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/MetadataDriverMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/MetadataDriverMock.php new file mode 100644 index 0000000..3dfb5e3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/MetadataDriverMock.php @@ -0,0 +1,21 @@ +_sequenceNumber++; + } + + /** + * @override + */ + public function nextId($seqName, $ondemand = true) + { + return $this->_sequenceNumber++; + } + + /** + * @override + */ + public function lastInsertId($table = null, $field = null) + { + return $this->_sequenceNumber - 1; + } + + /** + * @override + */ + public function currId($seqName) + { + return $this->_sequenceNumber; + } + + /* Mock API */ + + public function reset() + { + $this->_sequenceNumber = 0; + } + + public function autoinc() + { + $this->_sequenceNumber++; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/StatementMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/StatementMock.php new file mode 100644 index 0000000..9b6959f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/StatementMock.php @@ -0,0 +1,25 @@ + + */ +class StatementMock implements \IteratorAggregate, \Doctrine\DBAL\Driver\Statement +{ + public function bindValue($param, $value, $type = null){} + public function bindParam($column, &$variable, $type = null, $length = null){} + public function errorCode(){} + public function errorInfo(){} + public function execute($params = null){} + public function rowCount(){} + public function closeCursor(){} + public function columnCount(){} + public function setFetchMode($fetchStyle, $arg2 = null, $arg3 = null){} + public function fetch($fetchStyle = null){} + public function fetchAll($fetchStyle = null){} + public function fetchColumn($columnIndex = 0){} + public function getIterator(){} +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/TaskMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/TaskMock.php new file mode 100644 index 0000000..d4d5068 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/TaskMock.php @@ -0,0 +1,81 @@ +. + */ + +namespace Doctrine\Tests\Mocks; + +use Doctrine\Common\Cli\AbstractNamespace; + +/** + * TaskMock used for testing the CLI interface. + * @author Nils Adermann + */ +class TaskMock extends \Doctrine\Common\Cli\Tasks\AbstractTask +{ + /** + * Since instances of this class can be created elsewhere all instances + * register themselves in this array for later inspection. + * + * @var array(TaskMock) + */ + static public $instances = array(); + + private $runCounter = 0; + + /** + * Constructor of Task Mock Object. + * Makes sure the object can be inspected later. + * + * @param AbstractNamespace CLI Namespace, passed to parent constructor + */ + function __construct(AbstractNamespace $namespace) + { + self::$instances[] = $this; + + parent::__construct($namespace); + } + + /** + * Returns the number of times run() was called on this object. + * + * @return int + */ + public function getRunCounter() + { + return $this->runCounter; + } + + /* Mock API */ + + /** + * Method invoked by CLI to run task. + */ + public function run() + { + $this->runCounter++; + } + + /** + * Method supposed to generate the CLI Task Documentation + */ + public function buildDocumentation() + { + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/UnitOfWorkMock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/UnitOfWorkMock.php new file mode 100644 index 0000000..9535cdd --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Mocks/UnitOfWorkMock.php @@ -0,0 +1,58 @@ +_persisterMock[$entityName]) ? + $this->_persisterMock[$entityName] : parent::getEntityPersister($entityName); + } + + /** + * @param $entity + * @override + */ + public function getEntityChangeSet($entity) + { + $oid = spl_object_hash($entity); + return isset($this->_mockDataChangeSets[$oid]) ? + $this->_mockDataChangeSets[$oid] : parent::getEntityChangeSet($entity); + } + + /* MOCK API */ + + /** + * Sets a (mock) persister for an entity class that will be returned when + * getEntityPersister() is invoked for that class. + * + * @param $entityName + * @param $persister + */ + public function setEntityPersister($entityName, $persister) + { + $this->_persisterMock[$entityName] = $persister; + } + + public function setDataChangeSet($entity, array $mockChangeSet) + { + $this->_mockDataChangeSets[spl_object_hash($entity)] = $mockChangeSet; + } + + public function setEntityState($entity, $state) + { + $this->_entityStates[spl_object_hash($entity)] = $state; + } + + public function setOriginalEntityData($entity, array $originalData) + { + $this->_originalEntityData[spl_object_hash($entity)] = $originalData; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsAddress.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsAddress.php new file mode 100644 index 0000000..9833f3d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsAddress.php @@ -0,0 +1,191 @@ +id; + } + + public function getUser() { + return $this->user; + } + + public function getCountry() { + return $this->country; + } + + public function getZipCode() { + return $this->zip; + } + + public function getCity() { + return $this->city; + } + + public function setUser(CmsUser $user) { + if ($this->user !== $user) { + $this->user = $user; + $user->setAddress($this); + } + } + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + $metadata->setPrimaryTable(array( + 'name' => 'company_person', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'find-all', + 'query' => 'SELECT id, country, city FROM cms_addresses', + 'resultSetMapping' => 'mapping-find-all', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'find-by-id', + 'query' => 'SELECT * FROM cms_addresses WHERE id = ?', + 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsAddress', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'count', + 'query' => 'SELECT COUNT(*) AS count FROM cms_addresses', + 'resultSetMapping' => 'mapping-count', + )); + + + $metadata->addSqlResultSetMapping(array ( + 'name' => 'mapping-find-all', + 'columns' => array(), + 'entities' => array ( array ( + 'fields' => array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'city', + 'column' => 'city', + ), + array ( + 'name' => 'country', + 'column' => 'country', + ), + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsAddress', + ), + ), + )); + + $metadata->addSqlResultSetMapping(array ( + 'name' => 'mapping-without-fields', + 'columns' => array(), + 'entities' => array(array ( + 'entityClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsAddress', + 'fields' => array() + ) + ) + )); + + $metadata->addSqlResultSetMapping(array ( + 'name' => 'mapping-count', + 'columns' =>array ( + array ( + 'name' => 'count', + ), + ) + )); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsArticle.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsArticle.php new file mode 100644 index 0000000..266cbc6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsArticle.php @@ -0,0 +1,48 @@ +user = $author; + } + + public function addComment(CmsComment $comment) { + $this->comments[] = $comment; + $comment->setArticle($this); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsComment.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsComment.php new file mode 100644 index 0000000..3e23821 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsComment.php @@ -0,0 +1,38 @@ +article = $article; + } + + public function __toString() { + return __CLASS__."[id=".$this->id."]"; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsEmail.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsEmail.php new file mode 100644 index 0000000..c79c300 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsEmail.php @@ -0,0 +1,48 @@ +id; + } + + public function getEmail() { + return $this->email; + } + + public function setEmail($email) { + $this->email = $email; + } + + public function getUser() { + return $this->user; + } + + public function setUser(CmsUser $user) { + $this->user = $user; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsEmployee.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsEmployee.php new file mode 100644 index 0000000..c169715 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsEmployee.php @@ -0,0 +1,44 @@ +id; + } + + public function getName() { + return $this->name; + } + + public function getSpouse() { + return $this->spouse; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsGroup.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsGroup.php new file mode 100644 index 0000000..b65ae85 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsGroup.php @@ -0,0 +1,49 @@ +name = $name; + } + + public function getName() { + return $this->name; + } + + public function addUser(CmsUser $user) { + $this->users[] = $user; + } + + public function getUsers() { + return $this->users; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsPhonenumber.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsPhonenumber.php new file mode 100644 index 0000000..ff28dfd --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsPhonenumber.php @@ -0,0 +1,28 @@ +user = $user; + } + + public function getUser() { + return $this->user; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsUser.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsUser.php new file mode 100644 index 0000000..2bae6ed --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CMS/CmsUser.php @@ -0,0 +1,437 @@ +phonenumbers = new ArrayCollection; + $this->articles = new ArrayCollection; + $this->groups = new ArrayCollection; + } + + public function getId() { + return $this->id; + } + + public function getStatus() { + return $this->status; + } + + public function getUsername() { + return $this->username; + } + + public function getName() { + return $this->name; + } + + /** + * Adds a phonenumber to the user. + * + * @param CmsPhonenumber $phone + */ + public function addPhonenumber(CmsPhonenumber $phone) { + $this->phonenumbers[] = $phone; + $phone->setUser($this); + } + + public function getPhonenumbers() { + return $this->phonenumbers; + } + + public function addArticle(CmsArticle $article) { + $this->articles[] = $article; + $article->setAuthor($this); + } + + public function addGroup(CmsGroup $group) { + $this->groups[] = $group; + $group->addUser($this); + } + + public function getGroups() { + return $this->groups; + } + + public function removePhonenumber($index) { + if (isset($this->phonenumbers[$index])) { + $ph = $this->phonenumbers[$index]; + unset($this->phonenumbers[$index]); + $ph->user = null; + return true; + } + return false; + } + + public function getAddress() { return $this->address; } + + public function setAddress(CmsAddress $address) { + if ($this->address !== $address) { + $this->address = $address; + $address->setUser($this); + } + } + + public function getEmail() { return $this->email; } + + public function setEmail(CmsEmail $email = null) { + if ($this->email !== $email) { + $this->email = $email; + + if ($email) { + $email->setUser($this); + } + } + } + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + $metadata->setPrimaryTable(array( + 'name' => 'cms_users', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'fetchIdAndUsernameWithResultClass', + 'query' => 'SELECT id, username FROM cms_users WHERE username = ?', + 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'fetchAllColumns', + 'query' => 'SELECT * FROM cms_users WHERE username = ?', + 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'fetchJoinedAddress', + 'query' => 'SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', + 'resultSetMapping' => 'mappingJoinedAddress', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'fetchJoinedPhonenumber', + 'query' => 'SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?', + 'resultSetMapping' => 'mappingJoinedPhonenumber', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'fetchUserPhonenumberCount', + 'query' => 'SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username', + 'resultSetMapping' => 'mappingUserPhonenumberCount', + )); + + $metadata->addNamedNativeQuery(array ( + "name" => "fetchMultipleJoinsEntityResults", + "resultSetMapping" => "mappingMultipleJoinsEntityResults", + "query" => "SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username" + )); + + $metadata->addSqlResultSetMapping(array ( + 'name' => 'mappingJoinedAddress', + 'columns' => array(), + 'entities' => array(array ( + 'fields'=> array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'name', + 'column' => 'name', + ), + array ( + 'name' => 'status', + 'column' => 'status', + ), + array ( + 'name' => 'address.zip', + 'column' => 'zip', + ), + array ( + 'name' => 'address.city', + 'column' => 'city', + ), + array ( + 'name' => 'address.country', + 'column' => 'country', + ), + array ( + 'name' => 'address.id', + 'column' => 'a_id', + ), + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'discriminatorColumn' => null + ), + ), + )); + + $metadata->addSqlResultSetMapping(array ( + 'name' => 'mappingJoinedPhonenumber', + 'columns' => array(), + 'entities' => array(array( + 'fields'=> array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'name', + 'column' => 'name', + ), + array ( + 'name' => 'status', + 'column' => 'status', + ), + array ( + 'name' => 'phonenumbers.phonenumber', + 'column' => 'number', + ), + ), + 'entityClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', + 'discriminatorColumn' => null + ), + ), + )); + + $metadata->addSqlResultSetMapping(array ( + 'name' => 'mappingUserPhonenumberCount', + 'columns' => array(), + 'entities' => array ( + array( + 'fields' => array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'name', + 'column' => 'name', + ), + array ( + 'name' => 'status', + 'column' => 'status', + ) + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'discriminatorColumn' => null + ) + ), + 'columns' => array ( + array ( + 'name' => 'numphones', + ) + ) + )); + + $metadata->addSqlResultSetMapping(array( + 'name' => 'mappingMultipleJoinsEntityResults', + 'entities' => array(array( + 'fields' => array( + array( + 'name' => 'id', + 'column' => 'u_id', + ), + array( + 'name' => 'name', + 'column' => 'u_name', + ), + array( + 'name' => 'status', + 'column' => 'u_status', + ) + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'discriminatorColumn' => null, + ), + array( + 'fields' => array( + array( + 'name' => 'id', + 'column' => 'a_id', + ), + array( + 'name' => 'zip', + 'column' => 'a_zip', + ), + array( + 'name' => 'country', + 'column' => 'a_country', + ), + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsAddress', + 'discriminatorColumn' => null, + ), + ), + 'columns' => array(array( + 'name' => 'numphones', + ) + ) + )); + + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyAuction.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyAuction.php new file mode 100644 index 0000000..5743122 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyAuction.php @@ -0,0 +1,17 @@ +data = $data; + } + + public function getData() { + return $this->data; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyCar.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyCar.php new file mode 100644 index 0000000..5af89b2 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyCar.php @@ -0,0 +1,33 @@ +brand = $brand; + } + + public function getId() { + return $this->id; + } + + public function getBrand() { + return $this->title; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyContract.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyContract.php new file mode 100644 index 0000000..bc8503d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyContract.php @@ -0,0 +1,131 @@ +engineers = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function getId() + { + return $this->id; + } + + public function markCompleted() + { + $this->completed = true; + } + + public function isCompleted() + { + return $this->completed; + } + + public function getSalesPerson() + { + return $this->salesPerson; + } + + public function setSalesPerson(CompanyEmployee $salesPerson) + { + $this->salesPerson = $salesPerson; + } + + public function getEngineers() + { + return $this->engineers; + } + + public function addEngineer(CompanyEmployee $engineer) + { + $this->engineers[] = $engineer; + } + + public function removeEngineer(CompanyEmployee $engineer) + { + $this->engineers->removeElement($engineer); + } + + abstract public function calculatePrice(); +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyEmployee.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyEmployee.php new file mode 100644 index 0000000..9d15377 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyEmployee.php @@ -0,0 +1,59 @@ +salary; + } + + public function setSalary($salary) { + $this->salary = $salary; + } + + public function getDepartment() { + return $this->department; + } + + public function setDepartment($dep) { + $this->department = $dep; + } + + public function getStartDate() { + return $this->startDate; + } + + public function setStartDate($date) { + $this->startDate = $date; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyEvent.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyEvent.php new file mode 100644 index 0000000..bb320aa --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyEvent.php @@ -0,0 +1,36 @@ +id; + } + + public function getOrganization() { + return $this->organization; + } + + public function setOrganization(CompanyOrganization $org) { + $this->organization = $org; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFixContract.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFixContract.php new file mode 100644 index 0000000..9186fc3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFixContract.php @@ -0,0 +1,30 @@ +fixPrice; + } + + public function getFixPrice() + { + return $this->fixPrice; + } + + public function setFixPrice($fixPrice) + { + $this->fixPrice = $fixPrice; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php new file mode 100644 index 0000000..121d8ec --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFlexContract.php @@ -0,0 +1,110 @@ +hoursWorked * $this->pricePerHour; + } + + public function getHoursWorked() + { + return $this->hoursWorked; + } + + public function setHoursWorked($hoursWorked) + { + $this->hoursWorked = $hoursWorked; + } + + public function getPricePerHour() + { + return $this->pricePerHour; + } + + public function setPricePerHour($pricePerHour) + { + $this->pricePerHour = $pricePerHour; + } + public function getManagers() + { + return $this->managers; + } + + public function addManager(CompanyManager $manager) + { + $this->managers[] = $manager; + } + + public function removeManager(CompanyManager $manager) + { + $this->managers->removeElement($manager); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContract.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContract.php new file mode 100644 index 0000000..b9ad3d4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyFlexUltraContract.php @@ -0,0 +1,30 @@ +maxPrice, parent::calculatePrice()); + } + + public function getMaxPrice() + { + return $this->maxPrice; + } + + public function setMaxPrice($maxPrice) + { + $this->maxPrice = $maxPrice; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyManager.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyManager.php new file mode 100644 index 0000000..aec9a77 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyManager.php @@ -0,0 +1,42 @@ +title; + } + + public function setTitle($title) { + $this->title = $title; + } + + public function getCar() { + return $this->car; + } + + public function setCar(CompanyCar $car) { + $this->car = $car; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyOrganization.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyOrganization.php new file mode 100644 index 0000000..ca99410 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyOrganization.php @@ -0,0 +1,44 @@ +id; + } + + public function getEvents() { + return $this->events; + } + + public function addEvent(CompanyEvent $event) { + $this->events[] = $event; + $event->setOrganization($this); + } + + /** + * @OneToOne(targetEntity="CompanyEvent", cascade={"persist"}) + * @JoinColumn(name="main_event_id", referencedColumnName="id", nullable=true) + */ + private $mainevent; + + public function getMainEvent() { + return $this->mainevent; + } + + public function setMainEvent($event) { + $this->mainevent = $event; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyPerson.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyPerson.php new file mode 100644 index 0000000..4636fa4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyPerson.php @@ -0,0 +1,160 @@ +friends = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function getId() { + return $this->id; + } + + public function getName() { + return $this->name; + } + + public function setName($name) { + $this->name = $name; + } + + public function getSpouse() { + return $this->spouse; + } + + public function getFriends() { + return $this->friends; + } + + public function addFriend(CompanyPerson $friend) { + if ( ! $this->friends->contains($friend)) { + $this->friends->add($friend); + $friend->addFriend($this); + } + } + + public function setSpouse(CompanyPerson $spouse) { + if ($spouse !== $this->spouse) { + $this->spouse = $spouse; + $this->spouse->setSpouse($this); + } + } + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + + $metadata->setPrimaryTable(array( + 'name' => 'company_person', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'fetchAllWithResultClass', + 'query' => 'SELECT id, name, discr FROM company_persons ORDER BY name', + 'resultClass' => 'Doctrine\\Tests\\Models\\Company\\CompanyPerson', + )); + + $metadata->addNamedNativeQuery(array ( + 'name' => 'fetchAllWithSqlResultSetMapping', + 'query' => 'SELECT id, name, discr AS discriminator FROM company_persons ORDER BY name', + 'resultSetMapping' => 'mappingFetchAll', + )); + + $metadata->addSqlResultSetMapping(array ( + 'name' => 'mappingFetchAll', + 'columns' => array(), + 'entities' => array ( array ( + 'fields' => array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'name', + 'column' => 'name', + ), + ), + 'entityClass' => 'Doctrine\Tests\Models\Company\CompanyPerson', + 'discriminatorColumn' => 'discriminator', + ), + ), + )); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyRaffle.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyRaffle.php new file mode 100644 index 0000000..733190d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Company/CompanyRaffle.php @@ -0,0 +1,17 @@ +data = $data; + } + + public function getData() { + return $this->data; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php new file mode 100644 index 0000000..e178ab5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php @@ -0,0 +1,21 @@ +friendsWithMe = new \Doctrine\Common\Collections\ArrayCollection(); + $this->myFriends = new \Doctrine\Common\Collections\ArrayCollection(); + } + + public function addMyFriend(CustomTypeParent $friend) + { + $this->getMyFriends()->add($friend); + $friend->addFriendWithMe($this); + } + + public function getMyFriends() + { + return $this->myFriends; + } + + public function addFriendWithMe(CustomTypeParent $friend) + { + $this->getFriendsWithMe()->add($friend); + } + + public function getFriendsWithMe() + { + return $this->friendsWithMe; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CustomType/CustomTypeUpperCase.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CustomType/CustomTypeUpperCase.php new file mode 100644 index 0000000..e4b46e8 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/CustomType/CustomTypeUpperCase.php @@ -0,0 +1,26 @@ +articleDetails = $details; + $this->reference = $reference; + $this->translation = $translation; + } + + public function getId() + { + return $this->id; + } + + public function getArticleDetails() + { + return $this->articleDetails; + } + + public function getReference() + { + return $this->reference; + } + + public function getTranslation() + { + return $this->translation; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Article.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Article.php new file mode 100644 index 0000000..d77bb94 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Article.php @@ -0,0 +1,87 @@ +title = $title; + $this->references = new \Doctrine\Common\Collections\ArrayCollection(); + $this->translations = new \Doctrine\Common\Collections\ArrayCollection(); + } + + public function setDetails($details) + { + $this->details = $details; + } + + public function id() + { + return $this->id; + } + + public function addReference($reference) + { + $this->references[] = $reference; + } + + public function references() + { + return $this->references; + } + + public function addTranslation($language, $title) + { + $this->translations[] = new DDC117Translation($this, $language, $title); + } + + public function getText() + { + return $this->details->getText(); + } + + public function getDetails() + { + return $this->details; + } + + public function resetText() + { + $this->details = null; + } + + public function getTranslations() + { + return $this->translations; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117ArticleDetails.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117ArticleDetails.php new file mode 100644 index 0000000..ae13df0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117ArticleDetails.php @@ -0,0 +1,39 @@ +article = $article; + $article->setDetails($this); + + $this->update($text); + } + + public function update($text) + { + $this->text = $text; + } + + public function getText() + { + return $this->text; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Editor.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Editor.php new file mode 100644 index 0000000..a323bb3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Editor.php @@ -0,0 +1,54 @@ +name = $name; + $this->reviewingTranslations = new \Doctrine\Common\Collections\ArrayCollection(); + } + + public function addLastTranslation(DDC117Translation $t) + { + $this->lastTranslation = $t; + $t->lastTranslatedBy[] = $this; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Link.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Link.php new file mode 100644 index 0000000..7e0084a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Link.php @@ -0,0 +1,31 @@ +source = $source; + $this->target = $target; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Reference.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Reference.php new file mode 100644 index 0000000..3c9017d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Reference.php @@ -0,0 +1,64 @@ +addReference($this); + $target->addReference($this); + + $this->source = $source; + $this->target = $target; + $this->description = $description; + $this->created = new \DateTime("now"); + } + + public function source() + { + return $this->source; + } + + public function target() + { + return $this->target; + } + + public function setDescription($desc) + { + $this->description = $desc; + } + + public function getDescription() + { + return $this->description; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Translation.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Translation.php new file mode 100644 index 0000000..b0fb437 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC117/DDC117Translation.php @@ -0,0 +1,65 @@ +article = $article; + $this->language = $language; + $this->title = $title; + $this->reviewedByEditors = new \Doctrine\Common\Collections\ArrayCollection(); + $this->lastTranslatedBy = new \Doctrine\Common\Collections\ArrayCollection(); + } + + public function getArticleId() + { + return $this->article->id(); + } + + public function getLanguage() + { + return $this->language; + } + + public function getLastTranslatedBy() + { + return $this->lastTranslatedBy; + } + + public function getReviewedByEditors() + { + return $this->reviewedByEditors; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC1476/DDC1476EntityWithDefaultFieldType.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC1476/DDC1476EntityWithDefaultFieldType.php new file mode 100644 index 0000000..cc09c13 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC1476/DDC1476EntityWithDefaultFieldType.php @@ -0,0 +1,76 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC1476; + +/** + * @Entity() + */ +class DDC1476EntityWithDefaultFieldType +{ + + /** + * @Id + * @Column() + * @GeneratedValue("NONE") + */ + protected $id; + + /** @column() */ + protected $name; + + /** + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + $metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + )); + $metadata->mapField(array( + 'fieldName' => 'name', + )); + + $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadataInfo::GENERATOR_TYPE_NONE); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753CustomRepository.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753CustomRepository.php new file mode 100644 index 0000000..eaf9006 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753CustomRepository.php @@ -0,0 +1,36 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC753; + +use Doctrine\ORM\EntityRepository; + +class DDC753CustomRepository extends EntityRepository +{ + + /** + * @return bool + */ + public function isCustomRepository() + { + return true; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753DefaultRepository.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753DefaultRepository.php new file mode 100644 index 0000000..5be9aa5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753DefaultRepository.php @@ -0,0 +1,35 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC753; + +use Doctrine\ORM\EntityRepository; + +class DDC753DefaultRepository extends EntityRepository +{ + /** + * @return bool + */ + public function isDefaultRepository() + { + return true; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithCustomRepository.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithCustomRepository.php new file mode 100644 index 0000000..7b92e66 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithCustomRepository.php @@ -0,0 +1,39 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC753; + +/** + * @Entity(repositoryClass = "Doctrine\Tests\Models\DDC753\DDC753CustomRepository") + */ +class DDC753EntityWithCustomRepository +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + protected $id; + + /** @column(type="string") */ + protected $name; + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithDefaultCustomRepository.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithDefaultCustomRepository.php new file mode 100644 index 0000000..8ca2a2c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithDefaultCustomRepository.php @@ -0,0 +1,39 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC753; + +/** + * @Entity() + */ +class DDC753EntityWithDefaultCustomRepository +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + protected $id; + + /** @column(type="string") */ + protected $name; + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithInvalidRepository.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithInvalidRepository.php new file mode 100644 index 0000000..d12660c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753EntityWithInvalidRepository.php @@ -0,0 +1,39 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC753; + +/** + * @Entity(repositoryClass = "\stdClass") + */ +class DDC753EntityWithInvalidRepository +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + protected $id; + + /** @column(type="string") */ + protected $name; + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753InvalidRepository.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753InvalidRepository.php new file mode 100644 index 0000000..9f0937a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC753/DDC753InvalidRepository.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC753; + +use Doctrine\ORM\EntityRepository; + +class DDC753InvalidRepository +{ + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php new file mode 100644 index 0000000..594f79f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869ChequePayment.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC869; + +/** + * @Entity + */ +class DDC869ChequePayment extends DDC869Payment +{ + + /** @column(type="string") */ + protected $serialNumber; + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + $metadata->mapField(array( + 'fieldName' => 'serialNumber', + 'type' => 'string', + )); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869CreditCardPayment.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869CreditCardPayment.php new file mode 100644 index 0000000..9e978d4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869CreditCardPayment.php @@ -0,0 +1,40 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC869; + +/** + * @Entity + */ +class DDC869CreditCardPayment extends DDC869Payment +{ + + /** @column(type="string") */ + protected $creditCardNumber; + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + $metadata->mapField(array( + 'fieldName' => 'creditCardNumber', + 'type' => 'string', + )); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php new file mode 100644 index 0000000..b9b8feb --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869Payment.php @@ -0,0 +1,57 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC869; + +/** + * @MappedSuperclass(repositoryClass = "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository") + */ +class DDC869Payment +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + protected $id; + + /** @column(type="float") */ + protected $value; + + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + $metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'id', + )); + $metadata->mapField(array( + 'fieldName' => 'value', + 'type' => 'float', + )); + $metadata->isMappedSuperclass = true; + $metadata->setCustomRepositoryClass("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository"); + $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadataInfo::GENERATOR_TYPE_AUTO); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869PaymentRepository.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869PaymentRepository.php new file mode 100644 index 0000000..f950df0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC869/DDC869PaymentRepository.php @@ -0,0 +1,37 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC869; + +use Doctrine\ORM\EntityRepository; + +class DDC869PaymentRepository extends EntityRepository +{ + + /** + * Very complex method + * + * @return bool + */ + public function isTrue() + { + return true; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889Class.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889Class.php new file mode 100644 index 0000000..7520568 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889Class.php @@ -0,0 +1,46 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC889; + +class DDC889Class extends DDC889SuperClass +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + protected $id; + + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + $metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'id', + )); + + $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadataInfo::GENERATOR_TYPE_AUTO); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889Entity.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889Entity.php new file mode 100644 index 0000000..59cd21a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889Entity.php @@ -0,0 +1,33 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC889; + +/** + * @Entity + */ +class DDC889Entity extends DDC889SuperClass +{ + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889SuperClass.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889SuperClass.php new file mode 100644 index 0000000..7cffe48 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC889/DDC889SuperClass.php @@ -0,0 +1,41 @@ +. + */ + +namespace Doctrine\Tests\Models\DDC889; + +/** + * @MappedSuperclass + */ +class DDC889SuperClass +{ + + /** @Column() */ + protected $name; + + public static function loadMetadata(\Doctrine\ORM\Mapping\ClassMetadataInfo $metadata) + { + $metadata->mapField(array( + 'fieldName' => 'name', + )); + + $metadata->isMappedSuperclass = true; + $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadataInfo::GENERATOR_TYPE_NONE); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Address.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Address.php new file mode 100644 index 0000000..f5edaf8 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Address.php @@ -0,0 +1,123 @@ +zip = $zip; + $this->country = $country; + $this->city = $city; + $this->street = $street; + } + + /** + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getCountry() + { + return $this->country; + } + + /** + * @param string $country + */ + public function setCountry($country) + { + $this->country = $country; + } + + /** + * @return string + */ + public function getZip() + { + return $this->zip; + } + + /** + * @param string $zip + */ + public function setZip($zip) + { + $this->zip = $zip; + } + + /** + * @return string + */ + public function getCity() + { + return $this->city; + } + + /** + * @param string $city + */ + public function setCity($city) + { + $this->city = $city; + } + + /** + * @return string + */ + public function getStreet() + { + return $this->street; + } + + /** + * @param string $street + */ + public function setStreet($street) + { + $this->street = $street; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Admin.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Admin.php new file mode 100644 index 0000000..e22b973 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Admin.php @@ -0,0 +1,47 @@ +setAssociationOverride('address',array( + 'joinColumns'=>array(array( + 'name' => 'adminaddress_id', + 'referencedColumnName' => 'id', + )) + )); + + $metadata->setAssociationOverride('groups',array( + 'joinTable' => array( + 'name' => 'ddc964_users_admingroups', + 'joinColumns' => array(array( + 'name' => 'adminuser_id', + )), + 'inverseJoinColumns' =>array (array ( + 'name' => 'admingroup_id', + )) + ) + )); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Group.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Group.php new file mode 100644 index 0000000..5260409 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Group.php @@ -0,0 +1,70 @@ +name = $name; + $this->users = new ArrayCollection(); + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param DDC964User $user + */ + public function addUser(DDC964User $user) + { + $this->users[] = $user; + } + + /** + * @return ArrayCollection + */ + public function getUsers() + { + return $this->users; + } + +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Guest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Guest.php new file mode 100644 index 0000000..9050118 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964Guest.php @@ -0,0 +1,44 @@ +setAttributeOverride('id', array( + 'columnName' => 'guest_id', + 'type' => 'integer', + 'length' => 140, + )); + + $metadata->setAttributeOverride('name',array( + 'columnName' => 'guest_name', + 'nullable' => false, + 'unique' => true, + 'length' => 240, + )); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964User.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964User.php new file mode 100644 index 0000000..608f42d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DDC964/DDC964User.php @@ -0,0 +1,155 @@ +name = $name; + $this->groups = new ArrayCollection; + } + + /** + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @param DDC964Group $group + */ + public function addGroup(DDC964Group $group) + { + $this->groups->add($group); + $group->addUser($this); + } + + /** + * @return ArrayCollection + */ + public function getGroups() + { + return $this->groups; + } + + /** + * @return DDC964Address + */ + public function getAddress() + { + return $this->address; + } + + /** + * @param DDC964Address $address + */ + public function setAddress(DDC964Address $address) + { + $this->address = $address; + } + + public static function loadMetadata($metadata) + { + $metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'user_id', + 'length' => 150, + )); + $metadata->mapField(array( + 'fieldName' => 'name', + 'type' => 'string', + 'columnName'=> 'user_name', + 'nullable' => true, + 'unique' => false, + 'length' => 250, + )); + + $metadata->mapManyToOne(array( + 'fieldName' => 'address', + 'targetEntity' => 'DDC964Address', + 'cascade' => array('persist','merge'), + 'joinColumn' => array('name'=>'address_id', 'referencedColumnMame'=>'id'), + )); + + $metadata->mapManyToMany(array( + 'fieldName' => 'groups', + 'targetEntity' => 'DDC964Group', + 'inversedBy' => 'users', + 'cascade' => array('persist','merge','detach'), + 'joinTable' => array( + 'name' => 'ddc964_users_groups', + 'joinColumns' => array(array( + 'name'=>'user_id', + 'referencedColumnName'=>'id', + )), + 'inverseJoinColumns'=>array(array( + 'name'=>'group_id', + 'referencedColumnName'=>'id', + )) + ) + )); + + $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadataInfo::GENERATOR_TYPE_AUTO); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/AbstractContentItem.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/AbstractContentItem.php new file mode 100644 index 0000000..12b27ee --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/AbstractContentItem.php @@ -0,0 +1,64 @@ +. + */ + +namespace Doctrine\Tests\Models\DirectoryTree; + +/** + * @MappedSuperclass + */ +abstract class AbstractContentItem +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + private $id; + + /** + * @ManyToOne(targetEntity="Directory") + */ + protected $parentDirectory; + + /** @column(type="string") */ + protected $name; + + public function __construct(Directory $parentDir = null) + { + $this->parentDirectory = $parentDir; + } + + public function getId() + { + return $this->id; + } + + public function setName($name) + { + $this->name = $name; + } + + public function getName() + { + return $this->name; + } + + public function getParent() + { + return $this->parentDirectory; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/Directory.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/Directory.php new file mode 100644 index 0000000..f0db778 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/Directory.php @@ -0,0 +1,41 @@ +. + */ + +namespace Doctrine\Tests\Models\DirectoryTree; + +/** + * @Entity + */ +class Directory extends AbstractContentItem +{ + /** + * @Column(type="string") + */ + protected $path; + + public function setPath($path) + { + $this->path = $path; + } + + public function getPath() + { + return $this->path; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/File.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/File.php new file mode 100644 index 0000000..3513268 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/DirectoryTree/File.php @@ -0,0 +1,46 @@ +. + */ + + +namespace Doctrine\Tests\Models\DirectoryTree; + +/** + * @Entity + * @Table(name="`file`") + */ +class File extends AbstractContentItem +{ + /** @Column(type="string") */ + protected $extension = "html"; + + public function __construct(Directory $parent = null) + { + parent::__construct($parent); + } + + public function getExtension() + { + return $this->extension; + } + + public function setExtension($ext) + { + $this->extension = $ext; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCart.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCart.php new file mode 100644 index 0000000..3d9f679 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCart.php @@ -0,0 +1,91 @@ +products = new ArrayCollection; + } + + public function getId() { + return $this->id; + } + + public function getPayment() { + return $this->payment; + } + + public function setPayment($payment) { + $this->payment = $payment; + } + + public function setCustomer(ECommerceCustomer $customer) { + if ($this->customer !== $customer) { + $this->customer = $customer; + $customer->setCart($this); + } + } + + public function removeCustomer() { + if ($this->customer !== null) { + $customer = $this->customer; + $this->customer = null; + $customer->removeCart(); + } + } + + public function getCustomer() { + return $this->customer; + } + + public function getProducts() + { + return $this->products; + } + + public function addProduct(ECommerceProduct $product) { + $this->products[] = $product; + } + + public function removeProduct(ECommerceProduct $product) { + return $this->products->removeElement($product); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCategory.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCategory.php new file mode 100644 index 0000000..a8d8dc6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCategory.php @@ -0,0 +1,126 @@ +products = new ArrayCollection(); + $this->children = new ArrayCollection(); + } + + public function getId() + { + return $this->id; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + } + + public function addProduct(ECommerceProduct $product) + { + if (!$this->products->contains($product)) { + $this->products[] = $product; + $product->addCategory($this); + } + } + + public function removeProduct(ECommerceProduct $product) + { + $removed = $this->products->removeElement($product); + if ($removed) { + $product->removeCategory($this); + } + } + + public function getProducts() + { + return $this->products; + } + + private function setParent(ECommerceCategory $parent) + { + $this->parent = $parent; + } + + public function getChildren() + { + return $this->children; + } + + public function getParent() + { + return $this->parent; + } + + public function addChild(ECommerceCategory $child) + { + $this->children[] = $child; + $child->setParent($this); + } + + /** does not set the owning side. */ + public function brokenAddChild(ECommerceCategory $child) + { + $this->children[] = $child; + } + + + public function removeChild(ECommerceCategory $child) + { + $removed = $this->children->removeElement($child); + if ($removed) { + $child->removeParent(); + } + } + + private function removeParent() + { + $this->parent = null; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCustomer.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCustomer.php new file mode 100644 index 0000000..a5de9e1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceCustomer.php @@ -0,0 +1,94 @@ +id; + } + + public function getName() { + return $this->name; + } + + public function setName($name) { + $this->name = $name; + } + + public function setCart(ECommerceCart $cart) + { + if ($this->cart !== $cart) { + $this->cart = $cart; + $cart->setCustomer($this); + } + } + + /* Does not properly maintain the bidirectional association! */ + public function brokenSetCart(ECommerceCart $cart) { + $this->cart = $cart; + } + + public function getCart() { + return $this->cart; + } + + public function removeCart() + { + if ($this->cart !== null) { + $cart = $this->cart; + $this->cart = null; + $cart->removeCustomer(); + } + } + + public function setMentor(ECommerceCustomer $mentor) + { + $this->mentor = $mentor; + } + + public function removeMentor() + { + $this->mentor = null; + } + + public function getMentor() + { + return $this->mentor; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceFeature.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceFeature.php new file mode 100644 index 0000000..04fc2be --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceFeature.php @@ -0,0 +1,59 @@ +id; + } + + public function getDescription() { + return $this->description; + } + + public function setDescription($description) { + $this->description = $description; + } + + public function setProduct(ECommerceProduct $product) { + $this->product = $product; + } + + public function removeProduct() { + if ($this->product !== null) { + $product = $this->product; + $this->product = null; + $product->removeFeature($this); + } + } + + public function getProduct() { + return $this->product; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceProduct.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceProduct.php new file mode 100644 index 0000000..f053fd2 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceProduct.php @@ -0,0 +1,178 @@ +features = new ArrayCollection; + $this->categories = new ArrayCollection; + $this->related = new ArrayCollection; + } + + public function getId() + { + return $this->id; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + } + + public function getShipping() + { + return $this->shipping; + } + + public function setShipping(ECommerceShipping $shipping) + { + $this->shipping = $shipping; + } + + public function removeShipping() + { + $this->shipping = null; + } + + public function getFeatures() + { + return $this->features; + } + + public function addFeature(ECommerceFeature $feature) + { + $this->features[] = $feature; + $feature->setProduct($this); + } + + /** does not set the owning side */ + public function brokenAddFeature(ECommerceFeature $feature) + { + $this->features[] = $feature; + } + + public function removeFeature(ECommerceFeature $feature) + { + $removed = $this->features->removeElement($feature); + if ($removed) { + $feature->removeProduct(); + } + return $removed; + } + + public function addCategory(ECommerceCategory $category) + { + if (!$this->categories->contains($category)) { + $this->categories[] = $category; + $category->addProduct($this); + } + } + + public function removeCategory(ECommerceCategory $category) + { + $removed = $this->categories->removeElement($category); + if ($removed) { + $category->removeProduct($this); + } + } + + public function getCategories() + { + return $this->categories; + } + + public function getRelated() + { + return $this->related; + } + + public function addRelated(ECommerceProduct $related) + { + if (!$this->related->contains($related)) { + $this->related[] = $related; + $related->addRelated($this); + } + } + + public function removeRelated(ECommerceProduct $related) + { + $removed = $this->related->removeElement($related); + if ($removed) { + $related->removeRelated($this); + } + } + + public function __clone() + { + $this->isCloned = true; + } + + /** + * Testing docblock contents here + */ + public function __wakeup() + { + $this->wakeUp = true; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceShipping.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceShipping.php new file mode 100644 index 0000000..a0f302c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/ECommerce/ECommerceShipping.php @@ -0,0 +1,40 @@ +id; + } + + public function getDays() + { + return $this->days; + } + + public function setDays($days) + { + $this->days = $days; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumAdministrator.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumAdministrator.php new file mode 100644 index 0000000..13d78ab --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumAdministrator.php @@ -0,0 +1,14 @@ +id; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumEntry.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumEntry.php new file mode 100644 index 0000000..efa359b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumEntry.php @@ -0,0 +1,26 @@ +topic; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumUser.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumUser.php new file mode 100644 index 0000000..3f3b5d9 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Forum/ForumUser.php @@ -0,0 +1,41 @@ +id; + } + + public function getUsername() { + return $this->username; + } + + public function getAvatar() { + return $this->avatar; + } + + public function setAvatar(ForumAvatar $avatar) { + $this->avatar = $avatar; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Generic/BooleanModel.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Generic/BooleanModel.php new file mode 100644 index 0000000..2c93156 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Generic/BooleanModel.php @@ -0,0 +1,20 @@ +_user = $author; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyCar.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyCar.php new file mode 100644 index 0000000..ac38341 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyCar.php @@ -0,0 +1,41 @@ +_description; + } + + public function addUser(LegacyUser $user) { + $this->_users[] = $user; + } + + public function getUsers() { + return $this->_users; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyUser.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyUser.php new file mode 100644 index 0000000..3e3deed --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyUser.php @@ -0,0 +1,80 @@ +_articles = new ArrayCollection; + $this->_references = new ArrayCollection; + $this->_cars = new ArrayCollection; + } + + public function getId() { + return $this->_id; + } + + public function getUsername() { + return $this->_username; + } + + public function addArticle(LegacyArticle $article) { + $this->_articles[] = $article; + $article->setAuthor($this); + } + + public function addReference($reference) + { + $this->_references[] = $reference; + } + + public function references() + { + return $this->_references; + } + + public function addCar(LegacyCar $car) { + $this->_cars[] = $car; + $car->addUser($this); + } + + public function getCars() { + return $this->_cars; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyUserReference.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyUserReference.php new file mode 100644 index 0000000..8dc20db --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Legacy/LegacyUserReference.php @@ -0,0 +1,65 @@ +addReference($this); + $target->addReference($this); + + $this->_source = $source; + $this->_target = $target; + $this->_description = $description; + $this->_created = new \DateTime("now"); + } + + public function source() + { + return $this->_source; + } + + public function target() + { + return $this->_target; + } + + public function setDescription($desc) + { + $this->_description = $desc; + } + + public function getDescription() + { + return $this->_description; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavCountry.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavCountry.php new file mode 100644 index 0000000..fd37552 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavCountry.php @@ -0,0 +1,39 @@ +name = $name; + } + + public function getId() { + return $this->id; + } + + public function getName() { + return $this->name; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavPhotos.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavPhotos.php new file mode 100644 index 0000000..25858d0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavPhotos.php @@ -0,0 +1,48 @@ +poi = $poi; + $this->file = $file; + } + + public function getId() { + return $this->id; + } + + public function getPointOfInterest() { + return $this->poi; + } + + public function getFile() { + return $this->file; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavPointOfInterest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavPointOfInterest.php new file mode 100644 index 0000000..33d0f70 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavPointOfInterest.php @@ -0,0 +1,79 @@ +lat = $lat; + $this->long = $long; + $this->name = $name; + $this->country = $country; + $this->visitors = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function getLong() { + return $this->long; + } + + public function getLat() { + return $this->lat; + } + + public function getName() { + return $this->name; + } + + public function getCountry() { + return $this->country; + } + + public function addVisitor(NavUser $user) + { + $this->visitors[] = $user; + } + + public function getVisitors() + { + return $this->visitors; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavTour.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavTour.php new file mode 100644 index 0000000..5a58017 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavTour.php @@ -0,0 +1,61 @@ +name = $name; + $this->pois = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function addPointOfInterest(NavPointOfInterest $poi) + { + $this->pois[] = $poi; + } + + public function getPointOfInterests() + { + return $this->pois; + } + + public function getName() + { + return $this->name; + } + + public function getId() + { + return $this->id; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavUser.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavUser.php new file mode 100644 index 0000000..42117e4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Navigation/NavUser.php @@ -0,0 +1,28 @@ +name = $name; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Address.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Address.php new file mode 100644 index 0000000..58e303f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Address.php @@ -0,0 +1,54 @@ +user !== $user) { + $this->user = $user; + $user->setAddress($this); + } + } + + + public function getId() + { + return $this->id; + } + + public function getZip() + { + return $this->zip; + } + + public function getUser() + { + return $this->user; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Group.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Group.php new file mode 100644 index 0000000..c653b69 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Group.php @@ -0,0 +1,42 @@ +name = $name; + $this->parent = $parent; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Phone.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Phone.php new file mode 100644 index 0000000..3d44753 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/Phone.php @@ -0,0 +1,24 @@ +value = $value; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/User.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/User.php new file mode 100644 index 0000000..d034f59 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Quote/User.php @@ -0,0 +1,102 @@ +phones = new ArrayCollection; + $this->groups = new ArrayCollection; + } + + + public function getPhones() + { + return $this->phones; + } + + public function getAddress() + { + return $this->address; + } + + public function getGroups() + { + return $this->groups; + } + + public function setAddress(Address $address) { + if ($this->address !== $address) { + $this->address = $address; + $address->setUser($this); + } + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingLeg.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingLeg.php new file mode 100644 index 0000000..a130e7b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingLeg.php @@ -0,0 +1,37 @@ +name; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingRoute.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingRoute.php new file mode 100644 index 0000000..9e5d5d0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingRoute.php @@ -0,0 +1,39 @@ +legs = new ArrayCollection(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingRouteBooking.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingRouteBooking.php new file mode 100644 index 0000000..9b862fc --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/Routing/RoutingRouteBooking.php @@ -0,0 +1,32 @@ +passengerName; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Bond.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Bond.php new file mode 100644 index 0000000..c8d6617 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Bond.php @@ -0,0 +1,48 @@ +name = $name; + } + + public function getId() + { + return $this->id; + } + + public function addStock(Stock $stock) + { + $this->stocks[$stock->getSymbol()] = $stock; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Market.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Market.php new file mode 100644 index 0000000..87e12ca --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Market.php @@ -0,0 +1,56 @@ +name = $name; + $this->stocks = new ArrayCollection(); + } + + public function getId() + { + return $this->id; + } + + public function getName() + { + return $this->name; + } + + public function addStock(Stock $stock) + { + $this->stocks[$stock->getSymbol()] = $stock; + } + + public function getStock($symbol) + { + return $this->stocks[$symbol]; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Stock.php b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Stock.php new file mode 100644 index 0000000..d65675b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/Models/StockExchange/Stock.php @@ -0,0 +1,49 @@ +symbol = $symbol; + $this->price = $initialOfferingPrice; + $this->market = $market; + $market->addStock($this); + } + + public function getSymbol() + { + return $this->symbol; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php new file mode 100644 index 0000000..ff82059 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php @@ -0,0 +1,56 @@ +_calc = new \Doctrine\ORM\Internal\CommitOrderCalculator(); + } + + public function testCommitOrdering1() + { + $class1 = new ClassMetadata(__NAMESPACE__ . '\NodeClass1'); + $class2 = new ClassMetadata(__NAMESPACE__ . '\NodeClass2'); + $class3 = new ClassMetadata(__NAMESPACE__ . '\NodeClass3'); + $class4 = new ClassMetadata(__NAMESPACE__ . '\NodeClass4'); + $class5 = new ClassMetadata(__NAMESPACE__ . '\NodeClass5'); + + $this->_calc->addClass($class1); + $this->_calc->addClass($class2); + $this->_calc->addClass($class3); + $this->_calc->addClass($class4); + $this->_calc->addClass($class5); + + $this->_calc->addDependency($class1, $class2); + $this->_calc->addDependency($class2, $class3); + $this->_calc->addDependency($class3, $class4); + $this->_calc->addDependency($class5, $class1); + + $sorted = $this->_calc->getCommitOrder(); + + // There is only 1 valid ordering for this constellation + $correctOrder = array($class5, $class1, $class2, $class3, $class4); + $this->assertSame($correctOrder, $sorted); + } +} + +class NodeClass1 {} +class NodeClass2 {} +class NodeClass3 {} +class NodeClass4 {} +class NodeClass5 {} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/ConfigurationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/ConfigurationTest.php new file mode 100644 index 0000000..76832c1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/ConfigurationTest.php @@ -0,0 +1,276 @@ + + */ +class ConfigurationTest extends PHPUnit_Framework_TestCase +{ + /** + * @var Configuration + */ + private $configuration; + + protected function setUp() + { + parent::setUp(); + $this->configuration = new Configuration(); + } + + public function testSetGetProxyDir() + { + $this->assertSame(null, $this->configuration->getProxyDir()); // defaults + + $this->configuration->setProxyDir(__DIR__); + $this->assertSame(__DIR__, $this->configuration->getProxyDir()); + } + + public function testSetGetAutoGenerateProxyClasses() + { + $this->assertSame(true, $this->configuration->getAutoGenerateProxyClasses()); // defaults + + $this->configuration->setAutoGenerateProxyClasses(false); + $this->assertSame(false, $this->configuration->getAutoGenerateProxyClasses()); + } + + public function testSetGetProxyNamespace() + { + $this->assertSame(null, $this->configuration->getProxyNamespace()); // defaults + + $this->configuration->setProxyNamespace(__NAMESPACE__); + $this->assertSame(__NAMESPACE__, $this->configuration->getProxyNamespace()); + } + + public function testSetGetMetadataDriverImpl() + { + $this->assertSame(null, $this->configuration->getMetadataDriverImpl()); // defaults + + $metadataDriver = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $this->configuration->setMetadataDriverImpl($metadataDriver); + $this->assertSame($metadataDriver, $this->configuration->getMetadataDriverImpl()); + } + + public function testNewDefaultAnnotationDriver() + { + $paths = array(__DIR__); + $reflectionClass = new ReflectionClass(__NAMESPACE__ . '\ConfigurationTestAnnotationReaderChecker'); + + $annotationDriver = $this->configuration->newDefaultAnnotationDriver($paths, false); + $reader = $annotationDriver->getReader(); + $annotation = $reader->getMethodAnnotation( + $reflectionClass->getMethod('namespacedAnnotationMethod'), + 'Doctrine\ORM\Mapping\PrePersist' + ); + $this->assertInstanceOf('Doctrine\ORM\Mapping\PrePersist', $annotation); + + $annotationDriver = $this->configuration->newDefaultAnnotationDriver($paths); + $reader = $annotationDriver->getReader(); + $annotation = $reader->getMethodAnnotation( + $reflectionClass->getMethod('simpleAnnotationMethod'), + 'Doctrine\ORM\Mapping\PrePersist' + ); + $this->assertInstanceOf('Doctrine\ORM\Mapping\PrePersist', $annotation); + } + + public function testSetGetEntityNamespace() + { + $this->configuration->addEntityNamespace('TestNamespace', __NAMESPACE__); + $this->assertSame(__NAMESPACE__, $this->configuration->getEntityNamespace('TestNamespace')); + $namespaces = array('OtherNamespace' => __NAMESPACE__); + $this->configuration->setEntityNamespaces($namespaces); + $this->assertSame($namespaces, $this->configuration->getEntityNamespaces()); + $this->setExpectedException('Doctrine\ORM\ORMException'); + $this->configuration->getEntityNamespace('NonExistingNamespace'); + } + + public function testSetGetQueryCacheImpl() + { + $this->assertSame(null, $this->configuration->getQueryCacheImpl()); // defaults + $queryCacheImpl = $this->getMock('Doctrine\Common\Cache\Cache'); + $this->configuration->setQueryCacheImpl($queryCacheImpl); + $this->assertSame($queryCacheImpl, $this->configuration->getQueryCacheImpl()); + } + + public function testSetGetHydrationCacheImpl() + { + $this->assertSame(null, $this->configuration->getHydrationCacheImpl()); // defaults + $queryCacheImpl = $this->getMock('Doctrine\Common\Cache\Cache'); + $this->configuration->setHydrationCacheImpl($queryCacheImpl); + $this->assertSame($queryCacheImpl, $this->configuration->getHydrationCacheImpl()); + } + + public function testSetGetMetadataCacheImpl() + { + $this->assertSame(null, $this->configuration->getMetadataCacheImpl()); // defaults + $queryCacheImpl = $this->getMock('Doctrine\Common\Cache\Cache'); + $this->configuration->setMetadataCacheImpl($queryCacheImpl); + $this->assertSame($queryCacheImpl, $this->configuration->getMetadataCacheImpl()); + } + + public function testAddGetNamedQuery() + { + $dql = 'SELECT u FROM User u'; + $this->configuration->addNamedQuery('QueryName', $dql); + $this->assertSame($dql, $this->configuration->getNamedQuery('QueryName')); + $this->setExpectedException('Doctrine\ORM\ORMException'); + $this->configuration->getNamedQuery('NonExistingQuery'); + } + + public function testAddGetNamedNativeQuery() + { + $sql = 'SELECT * FROM user'; + $rsm = $this->getMock('Doctrine\ORM\Query\ResultSetMapping'); + $this->configuration->addNamedNativeQuery('QueryName', $sql, $rsm); + $fetched = $this->configuration->getNamedNativeQuery('QueryName'); + $this->assertSame($sql, $fetched[0]); + $this->assertSame($rsm, $fetched[1]); + $this->setExpectedException('Doctrine\ORM\ORMException'); + $this->configuration->getNamedQuery('NonExistingQuery'); + } + + public function ensureProductionSettings() + { + $cache = $this->getMock('Doctrine\Common\Cache\Cache'); + $this->configuration->setAutoGenerateProxyClasses(true); + + try { + $this->configuration->ensureProductionSettings(); + $this->fail('Didn\'t check all production settings'); + } catch (ORMException $e) {} + + $this->configuration->setQueryCacheImpl($cache); + + try { + $this->configuration->ensureProductionSettings(); + $this->fail('Didn\'t check all production settings'); + } catch (ORMException $e) {} + + $this->configuration->setMetadataCacheImpl($cache); + + try { + $this->configuration->ensureProductionSettings(); + $this->fail('Didn\'t check all production settings'); + } catch (ORMException $e) {} + + $this->configuration->setAutoGenerateProxyClasses(false); + $this->configuration->ensureProductionSettings(); + } + + public function testAddGetCustomStringFunction() + { + $this->configuration->addCustomStringFunction('FunctionName', __CLASS__); + $this->assertSame(__CLASS__, $this->configuration->getCustomStringFunction('FunctionName')); + $this->assertSame(null, $this->configuration->getCustomStringFunction('NonExistingFunction')); + $this->configuration->setCustomStringFunctions(array('OtherFunctionName' => __CLASS__)); + $this->assertSame(__CLASS__, $this->configuration->getCustomStringFunction('OtherFunctionName')); + $this->setExpectedException('Doctrine\ORM\ORMException'); + $this->configuration->addCustomStringFunction('concat', __CLASS__); + } + + public function testAddGetCustomNumericFunction() + { + $this->configuration->addCustomNumericFunction('FunctionName', __CLASS__); + $this->assertSame(__CLASS__, $this->configuration->getCustomNumericFunction('FunctionName')); + $this->assertSame(null, $this->configuration->getCustomNumericFunction('NonExistingFunction')); + $this->configuration->setCustomNumericFunctions(array('OtherFunctionName' => __CLASS__)); + $this->assertSame(__CLASS__, $this->configuration->getCustomNumericFunction('OtherFunctionName')); + $this->setExpectedException('Doctrine\ORM\ORMException'); + $this->configuration->addCustomNumericFunction('abs', __CLASS__); + } + + public function testAddGetCustomDatetimeFunction() + { + $this->configuration->addCustomDatetimeFunction('FunctionName', __CLASS__); + $this->assertSame(__CLASS__, $this->configuration->getCustomDatetimeFunction('FunctionName')); + $this->assertSame(null, $this->configuration->getCustomDatetimeFunction('NonExistingFunction')); + $this->configuration->setCustomDatetimeFunctions(array('OtherFunctionName' => __CLASS__)); + $this->assertSame(__CLASS__, $this->configuration->getCustomDatetimeFunction('OtherFunctionName')); + $this->setExpectedException('Doctrine\ORM\ORMException'); + $this->configuration->addCustomDatetimeFunction('date_add', __CLASS__); + } + + public function testAddGetCustomHydrationMode() + { + $this->assertSame(null, $this->configuration->getCustomHydrationMode('NonExisting')); + $this->configuration->addCustomHydrationMode('HydrationModeName', __CLASS__); + $this->assertSame(__CLASS__, $this->configuration->getCustomHydrationMode('HydrationModeName')); + } + + public function testSetCustomHydrationModes() + { + $this->configuration->addCustomHydrationMode('HydrationModeName', __CLASS__); + $this->assertSame(__CLASS__, $this->configuration->getCustomHydrationMode('HydrationModeName')); + + $this->configuration->setCustomHydrationModes( + array( + 'AnotherHydrationModeName' => __CLASS__ + ) + ); + + $this->assertNull($this->configuration->getCustomHydrationMode('HydrationModeName')); + $this->assertSame(__CLASS__, $this->configuration->getCustomHydrationMode('AnotherHydrationModeName')); + } + + public function testSetGetClassMetadataFactoryName() + { + $this->assertSame('Doctrine\ORM\Mapping\ClassMetadataFactory', $this->configuration->getClassMetadataFactoryName()); + $this->configuration->setClassMetadataFactoryName(__CLASS__); + $this->assertSame(__CLASS__, $this->configuration->getClassMetadataFactoryName()); + } + + public function testAddGetFilters() + { + $this->assertSame(null, $this->configuration->getFilterClassName('NonExistingFilter')); + $this->configuration->addFilter('FilterName', __CLASS__); + $this->assertSame(__CLASS__, $this->configuration->getFilterClassName('FilterName')); + } + + public function setDefaultRepositoryClassName() + { + $this->assertSame('Doctrine\ORM\EntityRepository', $this->configuration->getDefaultRepositoryClassName()); + $repositoryClass = 'Doctrine\Tests\Models\DDC753\DDC753CustomRepository'; + $this->configuration->setDefaultRepositoryClassName($repositoryClass); + $this->assertSame($repositoryClass, $this->configuration->getDefaultRepositoryClassName()); + $this->setExpectedException('Doctrine\ORM\ORMException'); + $this->configuration->setDefaultRepositoryClassName(__CLASS__); + } + + public function testSetGetNamingStrategy() + { + $this->assertInstanceOf('Doctrine\ORM\Mapping\NamingStrategy', $this->configuration->getNamingStrategy()); + $namingStrategy = $this->getMock('Doctrine\ORM\Mapping\NamingStrategy'); + $this->configuration->setNamingStrategy($namingStrategy); + $this->assertSame($namingStrategy, $this->configuration->getNamingStrategy()); + } + + public function testSetGetQuoteStrategy() + { + $this->assertInstanceOf('Doctrine\ORM\Mapping\QuoteStrategy', $this->configuration->getQuoteStrategy()); + $quoteStrategy = $this->getMock('Doctrine\ORM\Mapping\QuoteStrategy'); + $this->configuration->setQuoteStrategy($quoteStrategy); + $this->assertSame($quoteStrategy, $this->configuration->getQuoteStrategy()); + } +} + +class ConfigurationTestAnnotationReaderChecker +{ + /** @PrePersist */ + public function simpleAnnotationMethod() + { + } + + /** @AnnotationNamespace\PrePersist */ + public function namespacedAnnotationMethod() + { + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Criteria/DqlGenerationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Criteria/DqlGenerationTest.php new file mode 100644 index 0000000..b3aa607 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Criteria/DqlGenerationTest.php @@ -0,0 +1,252 @@ +. + */ + +namespace Doctrine\Tests\ORM\Query; + +require_once __DIR__ . '/../../TestInit.php'; + +/** + * Test case for testing the saving and referencing of query identifiers. + * + * @author Guilherme Blanco + * @author Janne Vanhala + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class DqlGenerationTest extends \Doctrine\Tests\OrmTestCase +{ + protected function setUp() { + $this->markTestSkipped('Not yet implemented.'); + } + + protected function createQuery() + { + return $this->_em->createQuery(); + } + + public function testSelect() + { + $query = $this->createQuery(); + + // select and from + $query->setDql('FROM User u'); + $this->assertEquals('FROM User u', $query->getDql()); // Internally we use SELECT * FROM User u to process the DQL + $query->free(); + + $query->select()->from('User u'); + $this->assertEquals('SELECT * FROM User u', $query->getDql()); + $query->free(); + + $query->select('u.*')->from('User u'); + $this->assertEquals('SELECT u.* FROM User u', $query->getDql()); + $query->free(); + + $query->select('u.id')->from('User u'); + $this->assertEquals('SELECT u.id FROM User u', $query->getDql()); + $query->free(); + + $query->select('u.id, u.name')->from('User u'); + $this->assertEquals('SELECT u.id, u.name FROM User u', $query->getDql()); + $query->free(); + + $query->select('u.name AS myCustomName')->from('User u'); + $this->assertEquals('SELECT u.name AS myCustomName FROM User u', $query->getDql()); + $query->free(); + + $query->select('u.id')->select('u.name')->from('User u'); + $this->assertEquals('SELECT u.id, u.name FROM User u', $query->getDql()); + $query->free(); + } + + + public function testSelectDistinct() + { + $query = $this->createQuery(); + + $query->select()->distinct()->from('User u'); + $this->assertEquals('SELECT DISTINCT * FROM User u', $query->getDql()); + $query->free(); + + $query->select('u.name')->distinct(false)->from('User u'); + $this->assertEquals('SELECT u.name FROM User u', $query->getDql()); + $query->free(); + + $query->select()->distinct(false)->from('User u'); + $this->assertEquals('SELECT * FROM User u', $query->getDql()); + $query->free(); + + $query->select('u.name')->distinct()->from('User u'); + $this->assertEquals('SELECT DISTINCT u.name FROM User u', $query->getDql()); + $query->free(); + + $query->select('u.name, u.email')->distinct()->from('User u'); + $this->assertEquals('SELECT DISTINCT u.name, u.email FROM User u', $query->getDql()); + $query->free(); + + $query->select('u.name')->select('u.email')->distinct()->from('User u'); + $this->assertEquals('SELECT DISTINCT u.name, u.email FROM User u', $query->getDql()); + $query->free(); + + $query->select('DISTINCT u.name')->from('User u'); + $this->assertEquals('SELECT DISTINCT u.name FROM User u', $query->getDql()); + $query->free(); + + $query->select('DISTINCT u.name, u.email')->from('User u'); + $this->assertEquals('SELECT DISTINCT u.name, u.email FROM User u', $query->getDql()); + $query->free(); + + $query->select('DISTINCT u.name')->select('u.email')->from('User u'); + $this->assertEquals('SELECT DISTINCT u.name, u.email FROM User u', $query->getDql()); + $query->free(); + } + + + public function testSelectJoin() + { + $query = $this->createQuery(); + + $query->select('u.*')->from('User u')->join('u.Group g')->where('g.id = ?', 1); + $this->assertEquals('SELECT u.* FROM User u INNER JOIN u.Group g WHERE g.id = ?', $query->getDql()); + $this->assertEquals(array(1), $query->getParams()); + $query->free(); + + $query->select('u.*')->from('User u')->innerJoin('u.Group g')->where('g.id = ?', 1); + $this->assertEquals('SELECT u.* FROM User u INNER JOIN u.Group g WHERE g.id = ?', $query->getDql()); + $this->assertEquals(array(1), $query->getParams()); + $query->free(); + + $query->select('u.*')->from('User u')->leftJoin('u.Group g')->where('g.id IS NULL'); + $this->assertEquals('SELECT u.* FROM User u LEFT JOIN u.Group g WHERE g.id IS NULL', $query->getDql()); + $query->free(); + + $query->select('u.*')->from('User u')->leftJoin('u.UserGroup ug')->leftJoin('ug.Group g')->where('g.name = ?', 'admin'); + $this->assertEquals('SELECT u.* FROM User u LEFT JOIN u.UserGroup ug LEFT JOIN ug.Group g WHERE g.name = ?', $query->getDql()); + $query->free(); + } + + + public function testSelectWhere() + { + $query = $this->createQuery(); + + $query->select('u.name')->from('User u')->where('u.id = ?', 1); + $this->assertEquals('SELECT u.name FROM User u WHERE u.id = ?', $query->getDql()); + $this->assertEquals(array(1), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->where('u.id = ? AND u.type != ?', array(1, 'admin')); + $this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? AND u.type != ?', $query->getDql()); + $this->assertEquals(array(1, 'admin'), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->where('u.id = ?', 1)->andWhere('u.type != ?', 'admin'); + $this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? AND u.type != ?', $query->getDql()); + $this->assertEquals(array(1, 'admin'), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->where('( u.id = ?', 1)->andWhere('u.type != ? )', 'admin'); + $this->assertEquals('SELECT u.name FROM User u WHERE ( u.id = ? AND u.type != ? )', $query->getDql()); + $this->assertEquals(array(1, 'admin'), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->where('u.id = ? OR u.type != ?', array(1, 'admin')); + $this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? OR u.type != ?', $query->getDql()); + $this->assertEquals(array(1, 'admin'), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->where('u.id = ?', 1)->orWhere('u.type != ?', 'admin'); + $this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? OR u.type != ?', $query->getDql()); + $this->assertEquals(array(1, 'admin'), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->andwhere('u.id = ?', 1)->andWhere('u.type != ?', 'admin')->orWhere('u.email = ?', 'admin@localhost'); + $this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? AND u.type != ? OR u.email = ?', $query->getDql()); + $this->assertEquals(array(1, 'admin', 'admin@localhost'), $query->getParams()); + $query->free(); + } + + + public function testSelectWhereIn() + { + $query = $this->createQuery(); + + $query->select('u.name')->from('User u')->whereIn('u.id', array(1, 2, 3, 4, 5)); + $this->assertEquals('SELECT u.name FROM User u WHERE u.id IN (?, ?, ?, ?, ?)', $query->getDql()); + $this->assertEquals(array(1, 2, 3, 4, 5), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->whereNotIn('u.id', array(1, 2, 3)); + $this->assertEquals('SELECT u.name FROM User u WHERE u.id NOT IN (?, ?, ?)', $query->getDql()); + $this->assertEquals(array(1, 2, 3), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->where('u.type = ?', 'admin')->andWhereIn('u.id', array(1, 2)); + $this->assertEquals('SELECT u.name FROM User u WHERE u.type = ? AND u.id IN (?, ?)', $query->getDql()); + $this->assertEquals(array('admin', 1, 2), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->where('u.type = ?', 'admin')->andWhereNotIn('u.id', array(1, 2)); + $this->assertEquals('SELECT u.name FROM User u WHERE u.type = ? AND u.id NOT IN (?, ?)', $query->getDql()); + $this->assertEquals(array('admin', 1, 2), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->whereIn('u.type', array('admin', 'moderator'))->andWhereNotIn('u.id', array(1, 2, 3, 4)); + $this->assertEquals('SELECT u.name FROM User u WHERE u.type IN (?, ?) AND u.id NOT IN (?, ?, ?, ?)', $query->getDql()); + $this->assertEquals(array('admin', 'moderator', 1, 2, 3, 4), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->whereIn('u.type', array('admin', 'moderator'))->orWhereIn('u.id', array(1, 2, 3, 4)); + $this->assertEquals('SELECT u.name FROM User u WHERE u.type IN (?, ?) OR u.id IN (?, ?, ?, ?)', $query->getDql()); + $this->assertEquals(array('admin', 'moderator', 1, 2, 3, 4), $query->getParams()); + $query->free(); + + $query->select('u.name')->from('User u')->whereIn('u.type', array('admin', 'moderator'))->andWhereNotIn('u.id', array(1, 2))->orWhereNotIn('u.type', array('admin', 'moderator'))->andWhereNotIn('u.email', array('user@localhost', 'guest@localhost')); + $this->assertEquals('SELECT u.name FROM User u WHERE u.type IN (?, ?) AND u.id NOT IN (?, ?) OR u.type NOT IN (?, ?) AND u.email NOT IN (?, ?)', $query->getDql()); + $this->assertEquals(array('admin', 'moderator', 1, 2, 'admin', 'moderator', 'user@localhost', 'guest@localhost'), $query->getParams()); + $query->free(); + } + + + public function testDelete() + { + $query = $this->createQuery(); + + $query->setDql('DELETE CmsUser u'); + $this->assertEquals('DELETE CmsUser u', $query->getDql()); + $query->free(); + + $query->delete()->from('CmsUser u'); + $this->assertEquals('DELETE FROM CmsUser u', $query->getDql()); + $query->free(); + + $query->delete()->from('CmsUser u')->where('u.id = ?', 1); + $this->assertEquals('DELETE FROM CmsUser u WHERE u.id = ?', $query->getDql()); + $query->free(); + + $query->delete()->from('CmsUser u')->where('u.username = ?', 'gblanco')->orWhere('u.name = ?', 'Guilherme'); + $this->assertEquals('DELETE FROM CmsUser u WHERE u.username = ? OR u.name = ?', $query->getDql()); + $query->free(); + } + +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Entity/ConstructorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Entity/ConstructorTest.php new file mode 100644 index 0000000..014a7b4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Entity/ConstructorTest.php @@ -0,0 +1,28 @@ +assertEquals("romanb", $entity->username); + } +} + +class ConstructorTestEntity1 +{ + private $id; + public $username; + + public function __construct($username = null) + { + if ($username !== null) { + $this->username = $username; + } + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/EntityManagerTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/EntityManagerTest.php new file mode 100644 index 0000000..7de9213 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/EntityManagerTest.php @@ -0,0 +1,175 @@ +_em = $this->_getTestEntityManager(); + } + + /** + * @group DDC-899 + */ + public function testIsOpen() + { + $this->assertTrue($this->_em->isOpen()); + $this->_em->close(); + $this->assertFalse($this->_em->isOpen()); + } + + public function testGetConnection() + { + $this->assertInstanceOf('Doctrine\DBAL\Connection', $this->_em->getConnection()); + } + + public function testGetMetadataFactory() + { + $this->assertInstanceOf('Doctrine\ORM\Mapping\ClassMetadataFactory', $this->_em->getMetadataFactory()); + } + + public function testGetConfiguration() + { + $this->assertInstanceOf('Doctrine\ORM\Configuration', $this->_em->getConfiguration()); + } + + public function testGetUnitOfWork() + { + $this->assertInstanceOf('Doctrine\ORM\UnitOfWork', $this->_em->getUnitOfWork()); + } + + public function testGetProxyFactory() + { + $this->assertInstanceOf('Doctrine\ORM\Proxy\ProxyFactory', $this->_em->getProxyFactory()); + } + + public function testGetEventManager() + { + $this->assertInstanceOf('Doctrine\Common\EventManager', $this->_em->getEventManager()); + } + + public function testCreateNativeQuery() + { + $rsm = new \Doctrine\ORM\Query\ResultSetMapping(); + $query = $this->_em->createNativeQuery('SELECT foo', $rsm); + + $this->assertSame('SELECT foo', $query->getSql()); + } + + public function testCreateQueryBuilder() + { + $this->assertInstanceOf('Doctrine\ORM\QueryBuilder', $this->_em->createQueryBuilder()); + } + + public function testCreateQueryBuilderAliasValid() + { + $q = $this->_em->createQueryBuilder() + ->select('u')->from('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $q2 = clone $q; + + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', $q->getQuery()->getDql()); + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', $q2->getQuery()->getDql()); + + $q3 = clone $q; + + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', $q3->getQuery()->getDql()); + } + + public function testCreateQuery_DqlIsOptional() + { + $this->assertInstanceOf('Doctrine\ORM\Query', $this->_em->createQuery()); + } + + public function testGetPartialReference() + { + $user = $this->_em->getPartialReference('Doctrine\Tests\Models\CMS\CmsUser', 42); + $this->assertTrue($this->_em->contains($user)); + $this->assertEquals(42, $user->id); + $this->assertNull($user->getName()); + } + + public function testCreateQuery() + { + $q = $this->_em->createQuery('SELECT 1'); + $this->assertInstanceOf('Doctrine\ORM\Query', $q); + $this->assertEquals('SELECT 1', $q->getDql()); + } + + static public function dataMethodsAffectedByNoObjectArguments() + { + return array( + array('persist'), + array('remove'), + array('merge'), + array('refresh'), + array('detach') + ); + } + + /** + * @dataProvider dataMethodsAffectedByNoObjectArguments + */ + public function testThrowsExceptionOnNonObjectValues($methodName) { + $this->setExpectedException('Doctrine\ORM\ORMInvalidArgumentException', + 'EntityManager#'.$methodName.'() expects parameter 1 to be an entity object, NULL given.'); + $this->_em->$methodName(null); + } + + static public function dataAffectedByErrorIfClosedException() + { + return array( + array('flush'), + array('persist'), + array('remove'), + array('merge'), + array('refresh'), + ); + } + + /** + * @dataProvider dataAffectedByErrorIfClosedException + * @param string $methodName + */ + public function testAffectedByErrorIfClosedException($methodName) + { + $this->setExpectedException('Doctrine\ORM\ORMException', 'closed'); + + $this->_em->close(); + $this->_em->$methodName(new \stdClass()); + } + + /** + * @group DDC-1125 + */ + public function testTransactionalAcceptsReturn() + { + $return = $this->_em->transactional(function ($em) { + return 'foo'; + }); + + $this->assertEquals('foo', $return); + } + + public function testTransactionalAcceptsVariousCallables() + { + $this->assertSame('callback', $this->_em->transactional(array($this, 'transactionalCallback'))); + } + + public function testTransactionalThrowsInvalidArgumentExceptionIfNonCallablePassed() + { + $this->setExpectedException('InvalidArgumentException', 'Expected argument of type "callable", got "object"'); + $this->_em->transactional($this); + } + + public function transactionalCallback($em) + { + $this->assertSame($this->_em, $em); + return 'callback'; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AbstractManyToManyAssociationTestCase.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AbstractManyToManyAssociationTestCase.php new file mode 100644 index 0000000..f11ad26 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AbstractManyToManyAssociationTestCase.php @@ -0,0 +1,42 @@ +assertEquals(1, $this->_countForeignKeys($firstId, $secondId)); + } + + public function assertForeignKeysNotContain($firstId, $secondId) + { + $this->assertEquals(0, $this->_countForeignKeys($firstId, $secondId)); + } + + protected function _countForeignKeys($firstId, $secondId) + { + return count($this->_em->getConnection()->executeQuery(" + SELECT {$this->_firstField} + FROM {$this->_table} + WHERE {$this->_firstField} = ? + AND {$this->_secondField} = ? + ", array($firstId, $secondId))->fetchAll()); + } + + public function assertCollectionEquals(Collection $first, Collection $second) + { + return $first->forAll(function($k, $e) use($second) { return $second->contains($e); }); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AdvancedAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AdvancedAssociationTest.php new file mode 100644 index 0000000..f152796 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AdvancedAssociationTest.php @@ -0,0 +1,598 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Phrase'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\PhraseType'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Definition'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Lemma'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Type') + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + + public function testIssue() + { + //setup + $phrase = new Phrase; + $phrase->setPhrase('lalala'); + + $type = new PhraseType; + $type->setType('nonsense'); + $type->setAbbreviation('non'); + + $def1 = new Definition; + $def1->setDefinition('def1'); + $def2 = new Definition; + $def2->setDefinition('def2'); + + $phrase->setType($type); + $phrase->addDefinition($def1); + $phrase->addDefinition($def2); + + $this->_em->persist($phrase); + $this->_em->persist($type); + + $this->_em->flush(); + $this->_em->clear(); + //end setup + + // test1 - lazy-loading many-to-one after find() + $phrase2 = $this->_em->find('Doctrine\Tests\ORM\Functional\Phrase', $phrase->getId()); + $this->assertTrue(is_numeric($phrase2->getType()->getId())); + + $this->_em->clear(); + + // test2 - eager load in DQL query + $query = $this->_em->createQuery("SELECT p,t FROM Doctrine\Tests\ORM\Functional\Phrase p JOIN p.type t"); + $res = $query->getResult(); + $this->assertEquals(1, count($res)); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\PhraseType', $res[0]->getType()); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $res[0]->getType()->getPhrases()); + $this->assertFalse($res[0]->getType()->getPhrases()->isInitialized()); + + $this->_em->clear(); + + // test2 - eager load in DQL query with double-join back and forth + $query = $this->_em->createQuery("SELECT p,t,pp FROM Doctrine\Tests\ORM\Functional\Phrase p JOIN p.type t JOIN t.phrases pp"); + $res = $query->getResult(); + $this->assertEquals(1, count($res)); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\PhraseType', $res[0]->getType()); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $res[0]->getType()->getPhrases()); + $this->assertTrue($res[0]->getType()->getPhrases()->isInitialized()); + + $this->_em->clear(); + + // test3 - lazy-loading one-to-many after find() + $phrase3 = $this->_em->find('Doctrine\Tests\ORM\Functional\Phrase', $phrase->getId()); + $definitions = $phrase3->getDefinitions(); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $definitions); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Definition', $definitions[0]); + + $this->_em->clear(); + + // test4 - lazy-loading after DQL query + $query = $this->_em->createQuery("SELECT p FROM Doctrine\Tests\ORM\Functional\Phrase p"); + $res = $query->getResult(); + $definitions = $res[0]->getDefinitions(); + + $this->assertEquals(1, count($res)); + + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Definition', $definitions[0]); + $this->assertEquals(2, $definitions->count()); + } + + public function testManyToMany() + { + $lemma = new Lemma; + $lemma->setLemma('abu'); + + $type = new Type(); + $type->setType('nonsense'); + $type->setAbbreviation('non'); + + $lemma->addType($type); + + $this->_em->persist($lemma); + $this->_em->persist($type); + $this->_em->flush(); + + // test5 ManyToMany + $query = $this->_em->createQuery("SELECT l FROM Doctrine\Tests\ORM\Functional\Lemma l"); + $res = $query->getResult(); + $types = $res[0]->getTypes(); + + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Type', $types[0]); + } +} + +/** + * @Entity + * @Table(name="lemma") + */ +class Lemma { + + const CLASS_NAME = __CLASS__; + + /** + * @var int + * @Id + * @Column(type="integer", name="lemma_id") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * + * @var string + * @Column(type="string", name="lemma_name", unique=true, length=255) + */ + private $lemma; + + /** + * @var kateglo\application\utilities\collections\ArrayCollection + * @ManyToMany(targetEntity="Type", mappedBy="lemmas", cascade={"persist"}) + */ + private $types; + + public function __construct() { + $this->types = new \Doctrine\Common\Collections\ArrayCollection(); + } + + + /** + * + * @return int + */ + public function getId(){ + return $this->id; + } + + /** + * + * @param string $lemma + * @return void + */ + public function setLemma($lemma){ + $this->lemma = $lemma; + } + + /** + * + * @return string + */ + public function getLemma(){ + return $this->lemma; + } + + /** + * + * @param kateglo\application\models\Type $type + * @return void + */ + public function addType(Type $type){ + if (!$this->types->contains($type)) { + $this->types[] = $type; + $type->addLemma($this); + } + } + + /** + * + * @param kateglo\application\models\Type $type + * @return void + */ + public function removeType(Type $type) + { + $removed = $this->sources->removeElement($type); + if ($removed !== null) { + $removed->removeLemma($this); + } + } + + /** + * + * @return kateglo\application\helpers\collections\ArrayCollection + */ + public function getTypes() + { + return $this->types; + } +} + +/** + * @Entity + * @Table(name="type") + */ +class Type { + + const CLASS_NAME = __CLASS__; + + /** + * + * @var int + * @Id + * @Column(type="integer", name="type_id") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * + * @var string + * @Column(type="string", name="type_name", unique=true) + */ + private $type; + + /** + * + * @var string + * @Column(type="string", name="type_abbreviation", unique=true) + */ + private $abbreviation; + + /** + * @var kateglo\application\helpers\collections\ArrayCollection + * @ManyToMany(targetEntity="Lemma") + * @JoinTable(name="lemma_type", + * joinColumns={@JoinColumn(name="type_id", referencedColumnName="type_id")}, + * inverseJoinColumns={@JoinColumn(name="lemma_id", referencedColumnName="lemma_id")} + * ) + */ + private $lemmas; + + public function __construct(){ + $this->lemmas = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * + * @return int + */ + public function getId(){ + return $this->id; + } + + /** + * + * @param string $type + * @return void + */ + public function setType($type){ + $this->type = $type; + } + + /** + * + * @return string + */ + public function getType(){ + return $this->type; + } + + /** + * + * @param string $abbreviation + * @return void + */ + public function setAbbreviation($abbreviation){ + $this->abbreviation = $abbreviation; + } + + /** + * + * @return string + */ + public function getAbbreviation(){ + return $this->abbreviation; + } + + /** + * + * @param kateglo\application\models\Lemma $lemma + * @return void + */ + public function addLemma(Lemma $lemma) + { + if (!$this->lemmas->contains($lemma)) { + $this->lemmas[] = $lemma; + $lemma->addType($this); + } + } + + /** + * + * @param kateglo\application\models\Lemma $lemma + * @return void + */ + public function removeLEmma(Lemma $lemma) + { + $removed = $this->lemmas->removeElement($lemma); + if ($removed !== null) { + $removed->removeType($this); + } + } + + /** + * + * @return kateglo\application\helpers\collections\ArrayCollection + */ + public function getCategories() + { + return $this->categories; + } + +} + + +/** + * @Entity + * @Table(name="phrase") + */ +class Phrase { + + const CLASS_NAME = __CLASS__; + + /** + * @Id + * @Column(type="integer", name="phrase_id") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @Column(type="string", name="phrase_name", unique=true, length=255) + */ + private $phrase; + + /** + * @ManyToOne(targetEntity="PhraseType") + * @JoinColumn(name="phrase_type_id", referencedColumnName="phrase_type_id") + */ + private $type; + + /** + * @OneToMany(targetEntity="Definition", mappedBy="phrase", cascade={"persist"}) + */ + private $definitions; + + public function __construct() { + $this->definitions = new \Doctrine\Common\Collections\ArrayCollection; + } + + /** + * + * @param Definition $definition + * @return void + */ + public function addDefinition(Definition $definition){ + $this->definitions[] = $definition; + $definition->setPhrase($this); + } + + /** + * @return int + */ + public function getId(){ + return $this->id; + } + + /** + * @param string $phrase + * @return void + */ + public function setPhrase($phrase){ + $this->phrase = $phrase; + } + + /** + * @return string + */ + public function getPhrase(){ + return $this->phrase; + } + + /** + * + * @param PhraseType $type + * @return void + */ + public function setType(PhraseType $type){ + $this->type = $type; + } + + /** + * + * @return PhraseType + */ + public function getType(){ + return $this->type; + } + + /** + * + * @return ArrayCollection + */ + public function getDefinitions(){ + return $this->definitions; + } +} + +/** + * @Entity + * @Table(name="phrase_type") + */ +class PhraseType { + + const CLASS_NAME = __CLASS__; + + /** + * @Id + * @Column(type="integer", name="phrase_type_id") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @Column(type="string", name="phrase_type_name", unique=true) + */ + private $type; + + /** + * @Column(type="string", name="phrase_type_abbreviation", unique=true) + */ + private $abbreviation; + + /** + * @OneToMany(targetEntity="Phrase", mappedBy="type") + */ + private $phrases; + + public function __construct() { + $this->phrases = new \Doctrine\Common\Collections\ArrayCollection; + } + + /** + * @return int + */ + public function getId(){ + return $this->id; + } + + /** + * @param string $type + * @return void + */ + public function setType($type){ + $this->type = $type; + } + + /** + * @return string + */ + public function getType(){ + return $this->type; + } + + /** + * @param string $abbreviation + * @return void + */ + public function setAbbreviation($abbreviation){ + $this->abbreviation = $abbreviation; + } + + /** + * @return string + */ + public function getAbbreviation(){ + return $this->abbreviation; + } + + /** + * @param ArrayCollection $phrases + * @return void + */ + public function setPhrases($phrases){ + $this->phrases = $phrases; + } + + /** + * + * @return ArrayCollection + */ + public function getPhrases(){ + return $this->phrases; + } + +} + +/** + * @Entity + * @Table(name="definition") + */ +class Definition { + + const CLASS_NAME = __CLASS__; + + /** + * @Id + * @Column(type="integer", name="definition_id") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @ManyToOne(targetEntity="Phrase") + * @JoinColumn(name="definition_phrase_id", referencedColumnName="phrase_id") + */ + private $phrase; + + /** + * @Column(type="text", name="definition_text") + */ + private $definition; + + /** + * @return int + */ + public function getId(){ + return $this->id; + } + + /** + * @param Phrase $phrase + * @return void + */ + public function setPhrase(Phrase $phrase){ + $this->phrase = $phrase; + } + + /** + * @return Phrase + */ + public function getPhrase(){ + return $this->phrase; + } + + public function removePhrase() { + if ($this->phrase !== null) { + /*@var $phrase kateglo\application\models\Phrase */ + $phrase = $this->phrase; + $this->phrase = null; + $phrase->removeDefinition($this); + } + } + + /** + * @param string $definition + * @return void + */ + public function setDefinition($definition){ + $this->definition = $definition; + } + + /** + * @return string + */ + public function getDefinition(){ + return $this->definition; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AdvancedDqlQueryTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AdvancedDqlQueryTest.php new file mode 100644 index 0000000..a5c06e3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/AdvancedDqlQueryTest.php @@ -0,0 +1,183 @@ + + */ +class AdvancedDqlQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + protected function setUp() + { + $this->useModelSet('company'); + parent::setUp(); + + $this->generateFixture(); + } + + public function testAggregateWithHavingClause() + { + $dql = 'SELECT p.department, AVG(p.salary) AS avgSalary '. + 'FROM Doctrine\Tests\Models\Company\CompanyEmployee p '. + 'GROUP BY p.department HAVING SUM(p.salary) > 200000 ORDER BY p.department'; + + $result = $this->_em->createQuery($dql)->getScalarResult(); + + $this->assertEquals(2, count($result)); + $this->assertEquals('IT', $result[0]['department']); + $this->assertEquals(150000, $result[0]['avgSalary']); + $this->assertEquals('IT2', $result[1]['department']); + $this->assertEquals(600000, $result[1]['avgSalary']); + } + + public function testUnnamedScalarResultsAreOneBased() + { + $dql = 'SELECT p.department, AVG(p.salary) '. + 'FROM Doctrine\Tests\Models\Company\CompanyEmployee p '. + 'GROUP BY p.department HAVING SUM(p.salary) > 200000 ORDER BY p.department'; + + $result = $this->_em->createQuery($dql)->getScalarResult(); + + $this->assertEquals(2, count($result)); + $this->assertEquals(150000, $result[0][1]); + $this->assertEquals(600000, $result[1][1]); + } + + public function testOrderByResultVariableCollectionSize() + { + $dql = 'SELECT p.name, size(p.friends) AS friends ' . + 'FROM Doctrine\Tests\Models\Company\CompanyPerson p ' . + 'WHERE p.friends IS NOT EMPTY ' . + 'ORDER BY friends DESC, p.name DESC'; + + $result = $this->_em->createQuery($dql)->getScalarResult(); + + $this->assertEquals(4, count($result)); + + $this->assertEquals("Jonathan W.", $result[0]['name']); + $this->assertEquals(3, $result[0]['friends']); + + $this->assertEquals('Guilherme B.', $result[1]['name']); + $this->assertEquals(2, $result[1]['friends']); + + $this->assertEquals('Benjamin E.', $result[2]['name']); + $this->assertEquals(2, $result[2]['friends']); + + $this->assertEquals('Roman B.', $result[3]['name']); + $this->assertEquals(1, $result[3]['friends']); + } + + public function testIsNullAssocation() + { + $dql = 'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p '. + 'WHERE p.spouse IS NULL'; + $result = $this->_em->createQuery($dql)->getResult(); + + $this->assertEquals(2, count($result)); + $this->assertTrue($result[0]->getId() > 0); + $this->assertNull($result[0]->getSpouse()); + + $this->assertTrue($result[1]->getId() > 0); + $this->assertNull($result[1]->getSpouse()); + } + + public function testSelectSubselect() + { + $dql = 'SELECT p, (SELECT c.brand FROM Doctrine\Tests\Models\Company\CompanyCar c WHERE p.car = c) brandName '. + 'FROM Doctrine\Tests\Models\Company\CompanyManager p'; + $result = $this->_em->createQuery($dql)->getArrayResult(); + + $this->assertEquals(1, count($result)); + $this->assertEquals("Caramba", $result[0]['brandName']); + } + + public function testInSubselect() + { + $dql = "SELECT p.name FROM Doctrine\Tests\Models\Company\CompanyPerson p ". + "WHERE p.name IN (SELECT n.name FROM Doctrine\Tests\Models\Company\CompanyPerson n WHERE n.name = 'Roman B.')"; + $result = $this->_em->createQuery($dql)->getScalarResult(); + + $this->assertEquals(1, count($result)); + $this->assertEquals('Roman B.', $result[0]['name']); + } + + public function testGroupByMultipleFields() + { + $dql = 'SELECT p.department, p.name, count(p.id) FROM Doctrine\Tests\Models\Company\CompanyEmployee p '. + 'GROUP BY p.department, p.name'; + $result = $this->_em->createQuery($dql)->getResult(); + + $this->assertEquals(4, count($result)); + } + + public function testUpdateAs() + { + $dql = 'UPDATE Doctrine\Tests\Models\Company\CompanyEmployee AS p SET p.salary = 1'; + $this->_em->createQuery($dql)->execute(); + + $this->assertTrue(count($this->_em->createQuery( + 'SELECT count(p.id) FROM Doctrine\Tests\Models\Company\CompanyEmployee p WHERE p.salary = 1')->getResult()) > 0); + } + + public function testDeleteAs() + { + $dql = 'DELETE Doctrine\Tests\Models\Company\CompanyEmployee AS p'; + $this->_em->createQuery($dql)->getResult(); + + $dql = 'SELECT count(p) FROM Doctrine\Tests\Models\Company\CompanyEmployee p'; + $result = $this->_em->createQuery($dql)->getSingleScalarResult(); + + $this->assertEquals(0, $result); + } + + public function generateFixture() + { + $car = new CompanyCar('Caramba'); + + $manager1 = new CompanyManager(); + $manager1->setName('Roman B.'); + $manager1->setTitle('Foo'); + $manager1->setDepartment('IT'); + $manager1->setSalary(100000); + $manager1->setCar($car); + + $person2 = new CompanyEmployee(); + $person2->setName('Benjamin E.'); + $person2->setDepartment('IT'); + $person2->setSalary(200000); + + $person3 = new CompanyEmployee(); + $person3->setName('Guilherme B.'); + $person3->setDepartment('IT2'); + $person3->setSalary(400000); + + $person4 = new CompanyEmployee(); + $person4->setName('Jonathan W.'); + $person4->setDepartment('IT2'); + $person4->setSalary(800000); + + $person2->setSpouse($person3); + + $manager1->addFriend($person4); + $person2->addFriend($person3); + $person2->addFriend($person4); + $person3->addFriend($person4); + + $this->_em->persist($car); + $this->_em->persist($manager1); + $this->_em->persist($person2); + $this->_em->persist($person3); + $this->_em->persist($person4); + $this->_em->flush(); + $this->_em->clear(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php new file mode 100644 index 0000000..415069a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php @@ -0,0 +1,1290 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testBasicUnitsOfWorkWithOneToManyAssociation() + { + // Create + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'developer'; + $this->_em->persist($user); + + $this->_em->flush(); + + $this->assertTrue(is_numeric($user->id)); + $this->assertTrue($this->_em->contains($user)); + + // Read + $user2 = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->id); + $this->assertTrue($user === $user2); + + // Add a phonenumber + $ph = new CmsPhonenumber; + $ph->phonenumber = "12345"; + $user->addPhonenumber($ph); + $this->_em->flush(); + $this->assertTrue($this->_em->contains($ph)); + $this->assertTrue($this->_em->contains($user)); + //$this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $user->phonenumbers); + + // Update name + $user->name = 'guilherme'; + $this->_em->flush(); + $this->assertEquals('guilherme', $user->name); + + // Add another phonenumber + $ph2 = new CmsPhonenumber; + $ph2->phonenumber = "6789"; + $user->addPhonenumber($ph2); + $this->_em->flush(); + $this->assertTrue($this->_em->contains($ph2)); + + // Delete + $this->_em->remove($user); + $this->assertTrue($this->_em->getUnitOfWork()->isScheduledForDelete($user)); + $this->assertTrue($this->_em->getUnitOfWork()->isScheduledForDelete($ph)); + $this->assertTrue($this->_em->getUnitOfWork()->isScheduledForDelete($ph2)); + $this->_em->flush(); + $this->assertFalse($this->_em->getUnitOfWork()->isScheduledForDelete($user)); + $this->assertFalse($this->_em->getUnitOfWork()->isScheduledForDelete($ph)); + $this->assertFalse($this->_em->getUnitOfWork()->isScheduledForDelete($ph2)); + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user)); + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($ph)); + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($ph2)); + } + + public function testOneToManyAssociationModification() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'developer'; + + $ph1 = new CmsPhonenumber; + $ph1->phonenumber = "0301234"; + $ph2 = new CmsPhonenumber; + $ph2->phonenumber = "987654321"; + + $user->addPhonenumber($ph1); + $user->addPhonenumber($ph2); + + $this->_em->persist($user); + $this->_em->flush(); + + //$this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $user->phonenumbers); + + // Remove the first element from the collection + unset($user->phonenumbers[0]); + $ph1->user = null; // owning side! + + $this->_em->flush(); + + $this->assertEquals(1, count($user->phonenumbers)); + $this->assertNull($ph1->user); + } + + public function testBasicOneToOne() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'developer'; + + $address = new CmsAddress; + $address->country = 'Germany'; + $address->city = 'Berlin'; + $address->zip = '12345'; + + $user->address = $address; // inverse side + $address->user = $user; // owning side! + + $this->_em->persist($user); + $this->_em->flush(); + + // Check that the foreign key has been set + $userId = $this->_em->getConnection()->executeQuery( + "SELECT user_id FROM cms_addresses WHERE id=?", array($address->id) + )->fetchColumn(); + $this->assertTrue(is_numeric($userId)); + + $this->_em->clear(); + + $user2 = $this->_em->createQuery('select u from \Doctrine\Tests\Models\CMS\CmsUser u where u.id=?1') + ->setParameter(1, $userId) + ->getSingleResult(); + + // Address has been eager-loaded because it cant be lazy + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $user2->address); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $user2->address); + } + + /** + * @group DDC-1230 + */ + public function testRemove() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_NEW"); + + $this->_em->persist($user); + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_MANAGED"); + + $this->_em->remove($user); + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_NEW"); + + $this->_em->persist($user); + $this->_em->flush(); + $id = $user->getId(); + + $this->_em->remove($user); + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_REMOVED, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_REMOVED"); + $this->_em->flush(); + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($user), "State should be UnitOfWork::STATE_NEW"); + + $this->assertNull($this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $id)); + } + + public function testOneToManyOrphanRemoval() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + for ($i=0; $i<3; ++$i) { + $phone = new CmsPhonenumber; + $phone->phonenumber = 100 + $i; + $user->addPhonenumber($phone); + } + + $this->_em->persist($user); + + $this->_em->flush(); + + $user->getPhonenumbers()->remove(0); + $this->assertEquals(2, count($user->getPhonenumbers())); + + $this->_em->flush(); + + // Check that there are just 2 phonenumbers left + $count = $this->_em->getConnection()->fetchColumn("SELECT COUNT(*) FROM cms_phonenumbers"); + $this->assertEquals(2, $count); // only 2 remaining + + // check that clear() removes the others via orphan removal + $user->getPhonenumbers()->clear(); + $this->_em->flush(); + $this->assertEquals(0, $this->_em->getConnection()->fetchColumn("select count(*) from cms_phonenumbers")); + } + + public function testBasicQuery() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + $this->_em->persist($user); + $this->_em->flush(); + + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u"); + + $users = $query->getResult(); + + $this->assertEquals(1, count($users)); + $this->assertEquals('Guilherme', $users[0]->name); + $this->assertEquals('gblanco', $users[0]->username); + $this->assertEquals('developer', $users[0]->status); + //$this->assertNull($users[0]->phonenumbers); + //$this->assertNull($users[0]->articles); + + $usersArray = $query->getArrayResult(); + + $this->assertTrue(is_array($usersArray)); + $this->assertEquals(1, count($usersArray)); + $this->assertEquals('Guilherme', $usersArray[0]['name']); + $this->assertEquals('gblanco', $usersArray[0]['username']); + $this->assertEquals('developer', $usersArray[0]['status']); + + $usersScalar = $query->getScalarResult(); + + $this->assertTrue(is_array($usersScalar)); + $this->assertEquals(1, count($usersScalar)); + $this->assertEquals('Guilherme', $usersScalar[0]['u_name']); + $this->assertEquals('gblanco', $usersScalar[0]['u_username']); + $this->assertEquals('developer', $usersScalar[0]['u_status']); + } + + public function testBasicOneToManyInnerJoin() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + $this->_em->persist($user); + $this->_em->flush(); + + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p"); + + $users = $query->getResult(); + + $this->assertEquals(0, count($users)); + } + + public function testBasicOneToManyLeftJoin() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + $this->_em->persist($user); + $this->_em->flush(); + + $query = $this->_em->createQuery("select u,p from Doctrine\Tests\Models\CMS\CmsUser u left join u.phonenumbers p"); + + $users = $query->getResult(); + + $this->assertEquals(1, count($users)); + $this->assertEquals('Guilherme', $users[0]->name); + $this->assertEquals('gblanco', $users[0]->username); + $this->assertEquals('developer', $users[0]->status); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $users[0]->phonenumbers); + $this->assertTrue($users[0]->phonenumbers->isInitialized()); + $this->assertEquals(0, $users[0]->phonenumbers->count()); + //$this->assertNull($users[0]->articles); + } + + public function testBasicRefresh() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $this->_em->persist($user); + $this->_em->flush(); + + $user->status = 'mascot'; + + $this->assertEquals('mascot', $user->status); + $this->_em->refresh($user); + $this->assertEquals('developer', $user->status); + } + + /** + * @group DDC-833 + */ + public function testRefreshResetsCollection() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + // Add a phonenumber + $ph1 = new CmsPhonenumber; + $ph1->phonenumber = "12345"; + $user->addPhonenumber($ph1); + + // Add a phonenumber + $ph2 = new CmsPhonenumber; + $ph2->phonenumber = "54321"; + + $this->_em->persist($user); + $this->_em->persist($ph1); + $this->_em->persist($ph2); + $this->_em->flush(); + + $user->addPhonenumber($ph2); + + $this->assertEquals(2, count($user->phonenumbers)); + $this->_em->refresh($user); + + $this->assertEquals(1, count($user->phonenumbers)); + } + + /** + * @group DDC-833 + */ + public function testDqlRefreshResetsCollection() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + // Add a phonenumber + $ph1 = new CmsPhonenumber; + $ph1->phonenumber = "12345"; + $user->addPhonenumber($ph1); + + // Add a phonenumber + $ph2 = new CmsPhonenumber; + $ph2->phonenumber = "54321"; + + $this->_em->persist($user); + $this->_em->persist($ph1); + $this->_em->persist($ph2); + $this->_em->flush(); + + $user->addPhonenumber($ph2); + + $this->assertEquals(2, count($user->phonenumbers)); + $dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1"; + $user = $this->_em->createQuery($dql) + ->setParameter(1, $user->id) + ->setHint(Query::HINT_REFRESH, true) + ->getSingleResult(); + + $this->assertEquals(1, count($user->phonenumbers)); + } + + /** + * @group DDC-833 + */ + public function testCreateEntityOfProxy() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + // Add a phonenumber + $ph1 = new CmsPhonenumber; + $ph1->phonenumber = "12345"; + $user->addPhonenumber($ph1); + + // Add a phonenumber + $ph2 = new CmsPhonenumber; + $ph2->phonenumber = "54321"; + + $this->_em->persist($user); + $this->_em->persist($ph1); + $this->_em->persist($ph2); + $this->_em->flush(); + $this->_em->clear(); + + $userId = $user->id; + $user = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $user->id); + + $dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1"; + $user = $this->_em->createQuery($dql) + ->setParameter(1, $userId) + ->getSingleResult(); + + $this->assertEquals(1, count($user->phonenumbers)); + } + + public function testAddToCollectionDoesNotInitialize() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + for ($i=0; $i<3; ++$i) { + $phone = new CmsPhonenumber; + $phone->phonenumber = 100 + $i; + $user->addPhonenumber($phone); + } + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $this->assertEquals(3, $user->getPhonenumbers()->count()); + + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username='gblanco'"); + + $gblanco = $query->getSingleResult(); + + $this->assertFalse($gblanco->getPhonenumbers()->isInitialized()); + + $newPhone = new CmsPhonenumber; + $newPhone->phonenumber = 555; + $gblanco->addPhonenumber($newPhone); + + $this->assertFalse($gblanco->getPhonenumbers()->isInitialized()); + $this->_em->persist($gblanco); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p where u.username='gblanco'"); + $gblanco2 = $query->getSingleResult(); + $this->assertEquals(4, $gblanco2->getPhonenumbers()->count()); + } + + public function testInitializeCollectionWithNewObjectsRetainsNewObjects() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + for ($i=0; $i<3; ++$i) { + $phone = new CmsPhonenumber; + $phone->phonenumber = 100 + $i; + $user->addPhonenumber($phone); + } + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $this->assertEquals(3, $user->getPhonenumbers()->count()); + + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username='gblanco'"); + + $gblanco = $query->getSingleResult(); + + $this->assertFalse($gblanco->getPhonenumbers()->isInitialized()); + + $newPhone = new CmsPhonenumber; + $newPhone->phonenumber = 555; + $gblanco->addPhonenumber($newPhone); + + $this->assertFalse($gblanco->getPhonenumbers()->isInitialized()); + $this->assertEquals(4, $gblanco->getPhonenumbers()->count()); + $this->assertTrue($gblanco->getPhonenumbers()->isInitialized()); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p where u.username='gblanco'"); + $gblanco2 = $query->getSingleResult(); + $this->assertEquals(4, $gblanco2->getPhonenumbers()->count()); + } + + public function testSetSetAssociationWithGetReference() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + $this->_em->persist($user); + + $address = new CmsAddress; + $address->country = 'Germany'; + $address->city = 'Berlin'; + $address->zip = '12345'; + $this->_em->persist($address); + + $this->_em->flush(); + $this->_em->detach($address); + + $this->assertFalse($this->_em->contains($address)); + $this->assertTrue($this->_em->contains($user)); + + // Assume we only got the identifier of the address and now want to attach + // that address to the user without actually loading it, using getReference(). + $addressRef = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsAddress', $address->getId()); + + //$addressRef->getId(); + //\Doctrine\Common\Util\Debug::dump($addressRef); + + $user->setAddress($addressRef); // Ugh! Initializes address 'cause of $address->setUser($user)! + + $this->_em->flush(); + $this->_em->clear(); + + // Check with a fresh load that the association is indeed there + $query = $this->_em->createQuery("select u, a from Doctrine\Tests\Models\CMS\CmsUser u join u.address a where u.username='gblanco'"); + $gblanco = $query->getSingleResult(); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $gblanco); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $gblanco->getAddress()); + $this->assertEquals('Berlin', $gblanco->getAddress()->getCity()); + + } + + public function testOneToManyCascadeRemove() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + for ($i=0; $i<3; ++$i) { + $phone = new CmsPhonenumber; + $phone->phonenumber = 100 + $i; + $user->addPhonenumber($phone); + } + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username='gblanco'"); + $gblanco = $query->getSingleResult(); + + $this->_em->remove($gblanco); + $this->_em->flush(); + + $this->_em->clear(); + + $this->assertEquals(0, $this->_em->createQuery( + "select count(p.phonenumber) from Doctrine\Tests\Models\CMS\CmsPhonenumber p") + ->getSingleScalarResult()); + + $this->assertEquals(0, $this->_em->createQuery( + "select count(u.id) from Doctrine\Tests\Models\CMS\CmsUser u") + ->getSingleScalarResult()); + } + + public function testTextColumnSaveAndRetrieve() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $this->_em->persist($user); + + $article = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article->text = "Lorem ipsum dolor sunt."; + $article->topic = "A Test Article!"; + $article->setAuthor($user); + + $this->_em->persist($article); + $this->_em->flush(); + $articleId = $article->id; + + $this->_em->clear(); + + // test find() with leading backslash at the same time + $articleNew = $this->_em->find('\Doctrine\Tests\Models\CMS\CmsArticle', $articleId); + $this->assertTrue($this->_em->contains($articleNew)); + $this->assertEquals("Lorem ipsum dolor sunt.", $articleNew->text); + + $this->assertNotSame($article, $articleNew); + + $articleNew->text = "Lorem ipsum dolor sunt. And stuff!"; + + $this->_em->flush(); + $this->_em->clear(); + + $articleNew = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $articleId); + $this->assertEquals("Lorem ipsum dolor sunt. And stuff!", $articleNew->text); + $this->assertTrue($this->_em->contains($articleNew)); + } + + public function testFlushDoesNotIssueUnnecessaryUpdates() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $address = new CmsAddress; + $address->country = 'Germany'; + $address->city = 'Berlin'; + $address->zip = '12345'; + + $address->user = $user; + $user->address = $address; + + $article = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article->text = "Lorem ipsum dolor sunt."; + $article->topic = "A Test Article!"; + $article->setAuthor($user); + + $this->_em->persist($article); + $this->_em->persist($user); + + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery('select u,a,ad from Doctrine\Tests\Models\CMS\CmsUser u join u.articles a join u.address ad'); + $user2 = $query->getSingleResult(); + + $this->assertEquals(1, count($user2->articles)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $user2->address); + + $oldLogger = $this->_em->getConnection()->getConfiguration()->getSQLLogger(); + $debugStack = new \Doctrine\DBAL\Logging\DebugStack; + $this->_em->getConnection()->getConfiguration()->setSQLLogger($debugStack); + + $this->_em->flush(); + $this->assertEquals(0, count($debugStack->queries)); + + $this->_em->getConnection()->getConfiguration()->setSQLLogger($oldLogger); + } + + public function testRemoveEntityByReference() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $userRef = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $user->getId()); + $this->_em->remove($userRef); + $this->_em->flush(); + $this->_em->clear(); + + $this->assertEquals(0, $this->_em->getConnection()->fetchColumn("select count(*) from cms_users")); + + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(null); + } + + public function testQueryEntityByReference() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $address = new CmsAddress; + $address->country = 'Germany'; + $address->city = 'Berlin'; + $address->zip = '12345'; + + $user->setAddress($address); + + $this->_em->transactional(function($em) use($user) { + $em->persist($user); + }); + $this->_em->clear(); + + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $userRef = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $user->getId()); + $address2 = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsAddress a where a.user = :user') + ->setParameter('user', $userRef) + ->getSingleResult(); + + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $address2->getUser()); + $this->assertTrue($userRef === $address2->getUser()); + $this->assertFalse($userRef->__isInitialized__); + $this->assertEquals('Germany', $address2->country); + $this->assertEquals('Berlin', $address2->city); + $this->assertEquals('12345', $address2->zip); + } + + public function testOneToOneNullUpdate() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + + $address = new CmsAddress(); + $address->city = "Bonn"; + $address->zip = "12354"; + $address->country = "Germany"; + $address->street = "somestreet"; + $address->user = $user; + + $this->_em->persist($address); + $this->_em->persist($user); + $this->_em->flush(); + + $this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select 1 from cms_addresses where user_id = ".$user->id)); + + $address->user = null; + $this->_em->flush(); + + $this->assertNotEquals(1, $this->_em->getConnection()->fetchColumn("select 1 from cms_addresses where user_id = ".$user->id)); + } + + /** + * @group DDC-600 + * @group DDC-455 + */ + public function testNewAssociatedEntityDuringFlushThrowsException() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + + $address = new CmsAddress(); + $address->city = "Bonn"; + $address->zip = "12354"; + $address->country = "Germany"; + $address->street = "somestreet"; + $address->user = $user; + + $this->_em->persist($address); + // pretend we forgot to persist $user + try { + $this->_em->flush(); // should raise an exception + $this->fail(); + } catch (\InvalidArgumentException $expected) {} + } + + /** + * @group DDC-600 + * @group DDC-455 + */ + public function testNewAssociatedEntityDuringFlushThrowsException2() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + + $address = new CmsAddress(); + $address->city = "Bonn"; + $address->zip = "12354"; + $address->country = "Germany"; + $address->street = "somestreet"; + $address->user = $user; + + $this->_em->persist($address); + $this->_em->persist($user); + $this->_em->flush(); + + $u2 = new CmsUser; + $u2->username = "beberlei"; + $u2->name = "Benjamin E."; + $u2->status = 'inactive'; + $address->user = $u2; + // pretend we forgot to persist $u2 + try { + $this->_em->flush(); // should raise an exception + $this->fail(); + } catch (\InvalidArgumentException $expected) {} + } + + /** + * @group DDC-600 + * @group DDC-455 + */ + public function testNewAssociatedEntityDuringFlushThrowsException3() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $art = new CmsArticle(); + $art->topic = 'topic'; + $art->text = 'the text'; + + $com = new CmsComment(); + $com->topic = 'Good'; + $com->text = 'Really good!'; + $art->addComment($com); + + $this->_em->persist($art); + // pretend we forgot to persist $com + try { + $this->_em->flush(); // should raise an exception + $this->fail(); + } catch (\InvalidArgumentException $expected) {} + } + + public function testOneToOneOrphanRemoval() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + + $address = new CmsAddress(); + $address->city = "Bonn"; + $address->zip = "12354"; + $address->country = "Germany"; + $address->street = "somestreet"; + $address->user = $user; + $user->address = $address; + + $this->_em->persist($address); + $this->_em->persist($user); + $this->_em->flush(); + $addressId = $address->getId(); + + $user->address = null; + + $this->_em->flush(); + + $this->assertEquals(0, $this->_em->getConnection()->fetchColumn("select count(*) from cms_addresses")); + + // check orphan removal through replacement + $user->address = $address; + $address->user = $user; + + $this->_em->flush(); + $this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select count(*) from cms_addresses")); + + // remove $address to free up unique key id + $this->_em->remove($address); + $this->_em->flush(); + + $newAddress = new CmsAddress(); + $newAddress->city = "NewBonn"; + $newAddress->zip = "12354"; + $newAddress->country = "NewGermany"; + $newAddress->street = "somenewstreet"; + $newAddress->user = $user; + $user->address = $newAddress; + + $this->_em->flush(); + $this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select count(*) from cms_addresses")); + } + + public function testGetPartialReferenceToUpdateObjectWithoutLoadingIt() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + $this->_em->persist($user); + $this->_em->flush(); + $userId = $user->id; + $this->_em->clear(); + + $user = $this->_em->getPartialReference('Doctrine\Tests\Models\CMS\CmsUser', $userId); + $this->assertTrue($this->_em->contains($user)); + $this->assertNull($user->getName()); + $this->assertEquals($userId, $user->id); + + $user->name = 'Stephan'; + $this->_em->flush(); + $this->_em->clear(); + + $this->assertEquals('Benjamin E.', $this->_em->find(get_class($user), $userId)->name); + } + + public function testMergePersistsNewEntities() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + + $managedUser = $this->_em->merge($user); + $this->assertEquals('beberlei', $managedUser->username); + $this->assertEquals('Benjamin E.', $managedUser->name); + $this->assertEquals('active', $managedUser->status); + + $this->assertTrue($user !== $managedUser); + $this->assertTrue($this->_em->contains($managedUser)); + + $this->_em->flush(); + $userId = $managedUser->id; + $this->_em->clear(); + + $user2 = $this->_em->find(get_class($managedUser), $userId); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $user2); + } + + public function testMergeNonPersistedProperties() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + $user->nonPersistedProperty = 'test'; + $user->nonPersistedPropertyObject = new CmsPhonenumber(); + + $managedUser = $this->_em->merge($user); + $this->assertEquals('test', $managedUser->nonPersistedProperty); + $this->assertSame($user->nonPersistedProperty, $managedUser->nonPersistedProperty); + $this->assertSame($user->nonPersistedPropertyObject, $managedUser->nonPersistedPropertyObject); + + $this->assertTrue($user !== $managedUser); + $this->assertTrue($this->_em->contains($managedUser)); + + $this->_em->flush(); + $userId = $managedUser->id; + $this->_em->clear(); + + $user2 = $this->_em->find(get_class($managedUser), $userId); + $this->assertNull($user2->nonPersistedProperty); + $this->assertNull($user2->nonPersistedPropertyObject); + $this->assertEquals('active', $user2->status); + } + + public function testMergeThrowsExceptionIfEntityWithGeneratedIdentifierDoesNotExist() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + $user->id = 42; + try { + $this->_em->merge($user); + $this->fail(); + } catch (\Doctrine\ORM\EntityNotFoundException $enfe) {} + } + + /** + * @group DDC-634 + */ + public function testOneToOneMergeSetNull() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + + $ph = new CmsPhonenumber(); + $ph->phonenumber = "12345"; + $user->addPhonenumber($ph); + + $this->_em->persist($user); + $this->_em->persist($ph); + $this->_em->flush(); + + $this->_em->clear(); + + $ph->user = null; + $managedPh = $this->_em->merge($ph); + + $this->_em->flush(); + $this->_em->clear(); + + $this->assertNull($this->_em->find(get_class($ph), $ph->phonenumber)->getUser()); + } + + /** + * @group DDC-952 + */ + public function testManyToOneFetchModeQuery() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin E."; + $user->status = 'active'; + + $article = new CmsArticle(); + $article->topic = "foo"; + $article->text = "bar"; + $article->user = $user; + + $this->_em->persist($article); + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $qc = $this->getCurrentQueryCount(); + $dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.id = ?1"; + $article = $this->_em->createQuery($dql) + ->setParameter(1, $article->id) + ->setFetchMode('Doctrine\Tests\Models\CMS\CmsArticle', 'user', \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER) + ->getSingleResult(); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $article->user, "It IS a proxy, ..."); + $this->assertTrue($article->user->__isInitialized__, "...but its initialized!"); + $this->assertEquals($qc+2, $this->getCurrentQueryCount()); + } + + /** + * @group DDC-1278 + */ + public function testClearWithEntityName() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + + $address = new CmsAddress(); + $address->city = "Springfield"; + $address->zip = "12354"; + $address->country = "Germany"; + $address->street = "Foo Street"; + $address->user = $user; + $user->address = $address; + + $article1 = new CmsArticle(); + $article1->topic = 'Foo'; + $article1->text = 'Foo Text'; + + $article2 = new CmsArticle(); + $article2->topic = 'Bar'; + $article2->text = 'Bar Text'; + + $user->addArticle($article1); + $user->addArticle($article2); + + $this->_em->persist($article1); + $this->_em->persist($article2); + $this->_em->persist($address); + $this->_em->persist($user); + $this->_em->flush(); + + $unitOfWork = $this->_em->getUnitOfWork(); + + $this->_em->clear('Doctrine\Tests\Models\CMS\CmsUser'); + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_DETACHED, $unitOfWork->getEntityState($user)); + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $unitOfWork->getEntityState($address)); + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $unitOfWork->getEntityState($article1)); + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $unitOfWork->getEntityState($article2)); + + $this->_em->clear(); + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_DETACHED, $unitOfWork->getEntityState($address)); + } + + public function testFlushManyExplicitEntities() + { + $userA = new CmsUser; + $userA->username = 'UserA'; + $userA->name = 'UserA'; + + $userB = new CmsUser; + $userB->username = 'UserB'; + $userB->name = 'UserB'; + + $userC = new CmsUser; + $userC->username = 'UserC'; + $userC->name = 'UserC'; + + $this->_em->persist($userA); + $this->_em->persist($userB); + $this->_em->persist($userC); + + $this->_em->flush(array($userA, $userB, $userB)); + + $userC->name = 'changed name'; + + $this->_em->flush(array($userA, $userB)); + $this->_em->refresh($userC); + + $this->assertTrue($userA->id > 0, 'user a has an id'); + $this->assertTrue($userB->id > 0, 'user b has an id'); + $this->assertTrue($userC->id > 0, 'user c has an id'); + $this->assertEquals('UserC', $userC->name, 'name has not changed because we did not flush it'); + } + + /** + * @group DDC-720 + */ + public function testFlushSingleManagedEntity() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + + $this->_em->persist($user); + $this->_em->flush(); + + $user->status = 'administrator'; + $this->_em->flush($user); + $this->_em->clear(); + + $user = $this->_em->find(get_class($user), $user->id); + $this->assertEquals('administrator', $user->status); + } + + /** + * @group DDC-720 + */ + public function testFlushSingleUnmanagedEntity() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + + $this->setExpectedException('InvalidArgumentException', 'Entity has to be managed for single computation'); + $this->_em->flush($user); + } + + /** + * @group DDC-720 + */ + public function testFlushSingleAndNewEntity() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + + $this->_em->persist($user); + $this->_em->flush(); + + $otherUser = new CmsUser; + $otherUser->name = 'Dominik2'; + $otherUser->username = 'domnikl2'; + $otherUser->status = 'developer'; + + $user->status = 'administrator'; + + $this->_em->persist($otherUser); + $this->_em->flush($user); + + $this->assertTrue($this->_em->contains($otherUser), "Other user is contained in EntityManager"); + $this->assertTrue($otherUser->id > 0, "other user has an id"); + } + + /** + * @group DDC-720 + */ + public function testFlushAndCascadePersist() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + + $this->_em->persist($user); + $this->_em->flush(); + + $address = new CmsAddress(); + $address->city = "Springfield"; + $address->zip = "12354"; + $address->country = "Germany"; + $address->street = "Foo Street"; + $address->user = $user; + $user->address = $address; + + $this->_em->flush($user); + + $this->assertTrue($this->_em->contains($address), "Other user is contained in EntityManager"); + $this->assertTrue($address->id > 0, "other user has an id"); + } + + /** + * @group DDC-720 + */ + public function testFlushSingleAndNoCascade() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + + $this->_em->persist($user); + $this->_em->flush(); + + $article1 = new CmsArticle(); + $article1->topic = 'Foo'; + $article1->text = 'Foo Text'; + $article1->author = $user; + $user->articles[] = $article1; + + $this->setExpectedException('InvalidArgumentException', "A new entity was found through the relationship 'Doctrine\Tests\Models\CMS\CmsUser#articles'"); + $this->_em->flush($user); + } + + /** + * @group DDC-720 + * @group DDC-1612 + */ + public function testFlushSingleNewEntity() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + + $this->_em->persist($user); + $this->_em->flush($user); + } + + /** + * @group DDC-720 + */ + public function testProxyIsIgnored() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->getReference(get_class($user), $user->id); + + $otherUser = new CmsUser; + $otherUser->name = 'Dominik2'; + $otherUser->username = 'domnikl2'; + $otherUser->status = 'developer'; + + $this->_em->persist($otherUser); + $this->_em->flush($user); + + $this->assertTrue($this->_em->contains($otherUser), "Other user is contained in EntityManager"); + $this->assertTrue($otherUser->id > 0, "other user has an id"); + } + + /** + * @group DDC-720 + */ + public function testFlushSingleSaveOnlySingle() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + $this->_em->persist($user); + + $user2 = new CmsUser; + $user2->name = 'Dominik'; + $user2->username = 'domnikl2'; + $user2->status = 'developer'; + $this->_em->persist($user2); + + $this->_em->flush(); + + $user->status = 'admin'; + $user2->status = 'admin'; + + $this->_em->flush($user); + $this->_em->clear(); + + $user2 = $this->_em->find(get_class($user2), $user2->id); + $this->assertEquals('developer', $user2->status); + } + + /** + * @group DDC-1585 + */ + public function testWrongAssocationInstance() + { + $user = new CmsUser; + $user->name = 'Dominik'; + $user->username = 'domnikl'; + $user->status = 'developer'; + $user->address = $user; + + $this->_em->persist($user); + + $this->setExpectedException("Doctrine\ORM\ORMException", "Found entity of type Doctrine\Tests\Models\CMS\CmsUser on association Doctrine\Tests\Models\CMS\CmsUser#address, but expecting Doctrine\Tests\Models\CMS\CmsAddress"); + $this->_em->flush(); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php new file mode 100644 index 0000000..c5193ea --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php @@ -0,0 +1,497 @@ +useModelSet('company'); + parent::setUp(); + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + } + + public function testCRUD() + { + $person = new CompanyPerson; + $person->setName('Roman S. Borschel'); + + $this->_em->persist($person); + + $employee = new CompanyEmployee; + $employee->setName('Roman S. Borschel'); + $employee->setSalary(100000); + $employee->setDepartment('IT'); + + $this->_em->persist($employee); + + $employee->setName('Guilherme Blanco'); + $this->_em->flush(); + + $this->_em->clear(); + + $query = $this->_em->createQuery("select p from Doctrine\Tests\Models\Company\CompanyPerson p order by p.name desc"); + + $entities = $query->getResult(); + + $this->assertEquals(2, count($entities)); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyPerson', $entities[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $entities[1]); + $this->assertTrue(is_numeric($entities[0]->getId())); + $this->assertTrue(is_numeric($entities[1]->getId())); + $this->assertEquals('Roman S. Borschel', $entities[0]->getName()); + $this->assertEquals('Guilherme Blanco', $entities[1]->getName()); + $this->assertEquals(100000, $entities[1]->getSalary()); + + $this->_em->clear(); + + $query = $this->_em->createQuery("select p from Doctrine\Tests\Models\Company\CompanyEmployee p"); + + $entities = $query->getResult(); + + $this->assertEquals(1, count($entities)); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $entities[0]); + $this->assertTrue(is_numeric($entities[0]->getId())); + $this->assertEquals('Guilherme Blanco', $entities[0]->getName()); + $this->assertEquals(100000, $entities[0]->getSalary()); + + $this->_em->clear(); + + $guilherme = $this->_em->getRepository(get_class($employee))->findOneBy(array('name' => 'Guilherme Blanco')); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $guilherme); + $this->assertEquals('Guilherme Blanco', $guilherme->getName()); + + $this->_em->clear(); + + $query = $this->_em->createQuery("update Doctrine\Tests\Models\Company\CompanyEmployee p set p.name = ?1, p.department = ?2 where p.name='Guilherme Blanco' and p.salary = ?3"); + $query->setParameter(1, 'NewName', 'string'); + $query->setParameter(2, 'NewDepartment'); + $query->setParameter(3, 100000); + $query->getSql(); + $numUpdated = $query->execute(); + $this->assertEquals(1, $numUpdated); + + $query = $this->_em->createQuery("delete from Doctrine\Tests\Models\Company\CompanyPerson p"); + $numDeleted = $query->execute(); + $this->assertEquals(2, $numDeleted); + } + + public function testMultiLevelUpdateAndFind() { + $manager = new CompanyManager; + $manager->setName('Roman S. Borschel'); + $manager->setSalary(100000); + $manager->setDepartment('IT'); + $manager->setTitle('CTO'); + $this->_em->persist($manager); + $this->_em->flush(); + + $manager->setName('Roman B.'); + $manager->setSalary(119000); + $manager->setTitle('CEO'); + $this->_em->persist($manager); + $this->_em->flush(); + + $this->_em->clear(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $manager->getId()); + + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyManager', $manager); + $this->assertEquals('Roman B.', $manager->getName()); + $this->assertEquals(119000, $manager->getSalary()); + $this->assertEquals('CEO', $manager->getTitle()); + $this->assertTrue(is_numeric($manager->getId())); + } + + public function testFindOnBaseClass() { + $manager = new CompanyManager; + $manager->setName('Roman S. Borschel'); + $manager->setSalary(100000); + $manager->setDepartment('IT'); + $manager->setTitle('CTO'); + $this->_em->persist($manager); + $this->_em->flush(); + + $this->_em->clear(); + + $person = $this->_em->find('Doctrine\Tests\Models\Company\CompanyPerson', $manager->getId()); + + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyManager', $person); + $this->assertEquals('Roman S. Borschel', $person->getName()); + $this->assertEquals(100000, $person->getSalary()); + $this->assertEquals('CTO', $person->getTitle()); + $this->assertTrue(is_numeric($person->getId())); + //$this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyCar', $person->getCar()); + } + + public function testSelfReferencingOneToOne() { + $manager = new CompanyManager; + $manager->setName('John Smith'); + $manager->setSalary(100000); + $manager->setDepartment('IT'); + $manager->setTitle('CTO'); + + $wife = new CompanyPerson; + $wife->setName('Mary Smith'); + $wife->setSpouse($manager); + + $this->assertSame($manager, $wife->getSpouse()); + $this->assertSame($wife, $manager->getSpouse()); + + $this->_em->persist($manager); + $this->_em->persist($wife); + + $this->_em->flush(); + + //var_dump($this->_em->getConnection()->fetchAll('select * from company_persons')); + //var_dump($this->_em->getConnection()->fetchAll('select * from company_employees')); + //var_dump($this->_em->getConnection()->fetchAll('select * from company_managers')); + + $this->_em->clear(); + + $query = $this->_em->createQuery('select p, s from Doctrine\Tests\Models\Company\CompanyPerson p join p.spouse s where p.name=\'Mary Smith\''); + + $result = $query->getResult(); + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyPerson', $result[0]); + $this->assertEquals('Mary Smith', $result[0]->getName()); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result[0]->getSpouse()); + $this->assertEquals('John Smith', $result[0]->getSpouse()->getName()); + $this->assertSame($result[0], $result[0]->getSpouse()->getSpouse()); + } + + public function testSelfReferencingManyToMany() + { + $person1 = new CompanyPerson; + $person1->setName('Roman'); + + $person2 = new CompanyPerson; + $person2->setName('Jonathan'); + + $person1->addFriend($person2); + + $this->assertEquals(1, count($person1->getFriends())); + $this->assertEquals(1, count($person2->getFriends())); + + + $this->_em->persist($person1); + $this->_em->persist($person2); + + $this->_em->flush(); + + $this->_em->clear(); + + $query = $this->_em->createQuery('select p, f from Doctrine\Tests\Models\Company\CompanyPerson p join p.friends f where p.name=?1'); + $query->setParameter(1, 'Roman'); + + $result = $query->getResult(); + $this->assertEquals(1, count($result)); + $this->assertEquals(1, count($result[0]->getFriends())); + $this->assertEquals('Roman', $result[0]->getName()); + + $friends = $result[0]->getFriends(); + $this->assertEquals('Jonathan', $friends[0]->getName()); + } + + public function testLazyLoading1() + { + $org = new CompanyOrganization; + $event1 = new CompanyAuction; + $event1->setData('auction'); + $org->addEvent($event1); + $event2 = new CompanyRaffle; + $event2->setData('raffle'); + $org->addEvent($event2); + + $this->_em->persist($org); + $this->_em->flush(); + $this->_em->clear(); + + $orgId = $org->getId(); + + $q = $this->_em->createQuery('select a from Doctrine\Tests\Models\Company\CompanyOrganization a where a.id = ?1'); + $q->setParameter(1, $orgId); + + $result = $q->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyOrganization', $result[0]); + $this->assertNull($result[0]->getMainEvent()); + + $events = $result[0]->getEvents(); + + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $events); + $this->assertFalse($events->isInitialized()); + + $this->assertEquals(2, count($events)); + if ($events[0] instanceof CompanyAuction) { + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyRaffle', $events[1]); + } else { + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyRaffle', $events[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyAuction', $events[1]); + } + } + + + public function testLazyLoading2() + { + $org = new CompanyOrganization; + $event1 = new CompanyAuction; + $event1->setData('auction'); + $org->setMainEvent($event1); + + $this->_em->persist($org); + $this->_em->flush(); + $this->_em->clear(); + + $q = $this->_em->createQuery('select a from Doctrine\Tests\Models\Company\CompanyEvent a where a.id = ?1'); + $q->setParameter(1, $event1->getId()); + + $result = $q->getResult(); + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyAuction', $result[0], sprintf("Is of class %s",get_class($result[0]))); + + $this->_em->clear(); + + $q = $this->_em->createQuery('select a from Doctrine\Tests\Models\Company\CompanyOrganization a where a.id = ?1'); + $q->setParameter(1, $org->getId()); + + $result = $q->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyOrganization', $result[0]); + + $mainEvent = $result[0]->getMainEvent(); + // mainEvent should have been loaded because it can't be lazy + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyAuction', $mainEvent); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $mainEvent); + } + + /** + * @group DDC-368 + */ + public function testBulkUpdateIssueDDC368() + { + $dql = 'UPDATE Doctrine\Tests\Models\Company\CompanyEmployee AS p SET p.salary = 1'; + $this->_em->createQuery($dql)->execute(); + + $this->assertTrue(count($this->_em->createQuery( + 'SELECT count(p.id) FROM Doctrine\Tests\Models\Company\CompanyEmployee p WHERE p.salary = 1') + ->getResult()) > 0); + } + + /** + * @group DDC-1341 + */ + public function testBulkUpdateNonScalarParameterDDC1341() + { + $dql = 'UPDATE Doctrine\Tests\Models\Company\CompanyEmployee AS p SET p.startDate = ?0 WHERE p.department = ?1'; + $query = $this->_em->createQuery($dql) + ->setParameter(0, new \DateTime()) + ->setParameter(1, 'IT'); + + $result = $query->execute(); + + } + + /** + * @group DDC-130 + */ + public function testDeleteJoinTableRecords() + { + #$this->markTestSkipped('Nightmare! friends adds both ID 6-7 and 7-6 into two rows of the join table. How to detect this?'); + + $employee1 = new CompanyEmployee(); + $employee1->setName('gblanco'); + $employee1->setSalary(0); + $employee1->setDepartment('IT'); + + $employee2 = new CompanyEmployee(); + $employee2->setName('jwage'); + $employee2->setSalary(0); + $employee2->setDepartment('IT'); + + $employee1->addFriend($employee2); + + $this->_em->persist($employee1); + $this->_em->persist($employee2); + $this->_em->flush(); + + $employee1Id = $employee1->getId(); + + $this->_em->remove($employee1); + $this->_em->flush(); + + $this->assertNull($this->_em->find(get_class($employee1), $employee1Id)); + } + + /** + * @group DDC-728 + */ + public function testQueryForInheritedSingleValuedAssociation() + { + $manager = new CompanyManager(); + $manager->setName('gblanco'); + $manager->setSalary(1234); + $manager->setTitle('Awesome!'); + $manager->setDepartment('IT'); + + $person = new CompanyPerson(); + $person->setName('spouse'); + + $manager->setSpouse($person); + + $this->_em->persist($manager); + $this->_em->persist($person); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT m FROM Doctrine\Tests\Models\Company\CompanyManager m WHERE m.spouse = ?1"; + $dqlManager = $this->_em->createQuery($dql)->setParameter(1, $person->getId())->getSingleResult(); + + $this->assertEquals($manager->getId(), $dqlManager->getId()); + $this->assertEquals($person->getId(), $dqlManager->getSpouse()->getId()); + } + + /** + * @group DDC-817 + */ + public function testFindByAssociation() + { + $manager = new CompanyManager(); + $manager->setName('gblanco'); + $manager->setSalary(1234); + $manager->setTitle('Awesome!'); + $manager->setDepartment('IT'); + + $person = new CompanyPerson(); + $person->setName('spouse'); + + $manager->setSpouse($person); + + $this->_em->persist($manager); + $this->_em->persist($person); + $this->_em->flush(); + $this->_em->clear(); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager'); + $pmanager = $repos->findOneBy(array('spouse' => $person->getId())); + + $this->assertEquals($manager->getId(), $pmanager->getId()); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyPerson'); + $pmanager = $repos->findOneBy(array('spouse' => $person->getId())); + + $this->assertEquals($manager->getId(), $pmanager->getId()); + } + + /** + * @group DDC-834 + */ + public function testGetReferenceEntityWithSubclasses() + { + $manager = new CompanyManager(); + $manager->setName('gblanco'); + $manager->setSalary(1234); + $manager->setTitle('Awesome!'); + $manager->setDepartment('IT'); + + $this->_em->persist($manager); + $this->_em->flush(); + $this->_em->clear(); + + $ref = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyPerson', $manager->getId()); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $ref, "Cannot Request a proxy from a class that has subclasses."); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyPerson', $ref); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $ref, "Direct fetch of the reference has to load the child class Emplyoee directly."); + $this->_em->clear(); + + $ref = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyManager', $manager->getId()); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $ref, "A proxy can be generated only if no subclasses exists for the requested reference."); + } + + /** + * @group DDC-992 + */ + public function testGetSubClassManyToManyCollection() + { + $manager = new CompanyManager(); + $manager->setName('gblanco'); + $manager->setSalary(1234); + $manager->setTitle('Awesome!'); + $manager->setDepartment('IT'); + + $person = new CompanyPerson(); + $person->setName('friend'); + + $manager->addFriend($person); + + $this->_em->persist($manager); + $this->_em->persist($person); + $this->_em->flush(); + $this->_em->clear(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $manager->getId()); + $this->assertEquals(1, count($manager->getFriends())); + } + + /** + * @group DDC-1777 + */ + public function testExistsSubclass() + { + $manager = new CompanyManager(); + $manager->setName('gblanco'); + $manager->setSalary(1234); + $manager->setTitle('Awesome!'); + $manager->setDepartment('IT'); + + $this->assertFalse($this->_em->getUnitOfWork()->getEntityPersister(get_class($manager))->exists($manager)); + + $this->_em->persist($manager); + $this->_em->flush(); + + $this->assertTrue($this->_em->getUnitOfWork()->getEntityPersister(get_class($manager))->exists($manager)); + } + + /** + * @group DDC-1637 + */ + public function testMatching() + { + $manager = new CompanyManager(); + $manager->setName('gblanco'); + $manager->setSalary(1234); + $manager->setTitle('Awesome!'); + $manager->setDepartment('IT'); + + $this->_em->persist($manager); + $this->_em->flush(); + + $repository = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyEmployee"); + $users = $repository->matching(new Criteria( + Criteria::expr()->eq('department', 'IT') + )); + $this->assertEquals(1, count($users)); + + $repository = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyManager"); + $users = $repository->matching(new Criteria( + Criteria::expr()->eq('department', 'IT') + )); + $this->assertEquals(1, count($users)); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest2.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest2.php new file mode 100644 index 0000000..531b100 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest2.php @@ -0,0 +1,176 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\CTIParent'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\CTIChild'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\CTIRelated'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\CTIRelated2') + )); + } catch (\Exception $ignored) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + + public function testOneToOneAssocToBaseTypeBidirectional() + { + $child = new CTIChild; + $child->setData('hello'); + + $related = new CTIRelated; + $related->setCTIParent($child); + + $this->_em->persist($related); + $this->_em->persist($child); + + $this->_em->flush(); + $this->_em->clear(); + + $relatedId = $related->getId(); + + $related2 = $this->_em->find('Doctrine\Tests\ORM\Functional\CTIRelated', $relatedId); + + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\CTIRelated', $related2); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\CTIChild', $related2->getCTIParent()); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $related2->getCTIParent()); + $this->assertEquals('hello', $related2->getCTIParent()->getData()); + + $this->assertSame($related2, $related2->getCTIParent()->getRelated()); + } + + public function testManyToManyToCTIHierarchy() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger()); + $mmrel = new CTIRelated2; + $child = new CTIChild; + $child->setData('child'); + $mmrel->addCTIChild($child); + + $this->_em->persist($mmrel); + $this->_em->persist($child); + + $this->_em->flush(); + $this->_em->clear(); + + $mmrel2 = $this->_em->find(get_class($mmrel), $mmrel->getId()); + $this->assertFalse($mmrel2->getCTIChildren()->isInitialized()); + $this->assertEquals(1, count($mmrel2->getCTIChildren())); + $this->assertTrue($mmrel2->getCTIChildren()->isInitialized()); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\CTIChild', $mmrel2->getCTIChildren()->get(0)); + } +} + +/** + * @Entity @Table(name="cti_parents") + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="type", type="string") + * @DiscriminatorMap({"parent" = "CTIParent", "child" = "CTIChild"}) + */ +class CTIParent { + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** @OneToOne(targetEntity="CTIRelated", mappedBy="ctiParent") */ + private $related; + + public function getId() { + return $this->id; + } + + public function getRelated() { + return $this->related; + } + + public function setRelated($related) { + $this->related = $related; + $related->setCTIParent($this); + } +} + +/** + * @Entity @Table(name="cti_children") + */ +class CTIChild extends CTIParent { + /** + * @Column(type="string") + */ + private $data; + + public function getData() { + return $this->data; + } + + public function setData($data) { + $this->data = $data; + } + +} + +/** @Entity */ +class CTIRelated { + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @OneToOne(targetEntity="CTIParent") + * @JoinColumn(name="ctiparent_id", referencedColumnName="id") + */ + private $ctiParent; + + public function getId() { + return $this->id; + } + + public function getCTIParent() { + return $this->ctiParent; + } + + public function setCTIParent($ctiParent) { + $this->ctiParent = $ctiParent; + } +} + +/** @Entity */ +class CTIRelated2 +{ + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; + /** @ManyToMany(targetEntity="CTIChild") */ + private $ctiChildren; + + + public function __construct() { + $this->ctiChildren = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function getId() { + return $this->id; + } + + public function addCTIChild(CTIChild $child) { + $this->ctiChildren->add($child); + } + + public function getCTIChildren() { + return $this->ctiChildren; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClearEventTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClearEventTest.php new file mode 100644 index 0000000..e86edb5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ClearEventTest.php @@ -0,0 +1,40 @@ + + */ +class ClearEventTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + protected function setUp() { + parent::setUp(); + } + + public function testEventIsCalledOnClear() + { + $listener = new OnClearListener; + $this->_em->getEventManager()->addEventListener(Events::onClear, $listener); + + $this->_em->clear(); + + $this->assertTrue($listener->called); + } +} + +class OnClearListener +{ + public $called = false; + + public function onClear(OnClearEventArgs $args) + { + $this->called = true; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/CompositePrimaryKeyTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/CompositePrimaryKeyTest.php new file mode 100644 index 0000000..1af930a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/CompositePrimaryKeyTest.php @@ -0,0 +1,144 @@ +useModelSet('navigation'); + parent::setUp(); + } + + public function putGermanysBrandenburderTor() + { + $country = new NavCountry("Germany"); + $this->_em->persist($country); + $poi = new NavPointOfInterest(100, 200, "Brandenburger Tor", $country); + $this->_em->persist($poi); + $this->_em->flush(); + $this->_em->clear(); + } + + public function putTripAroundEurope() + { + $poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('lat' => 100, 'long' => 200)); + + $tour = new NavTour("Trip around Europe"); + $tour->addPointOfInterest($poi); + + $this->_em->persist($tour); + $this->_em->flush(); + $this->_em->clear(); + + return $tour; + } + + public function testPersistCompositePkEntity() + { + $this->putGermanysBrandenburderTor(); + + $poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('lat' => 100, 'long' => 200)); + + $this->assertInstanceOf('Doctrine\Tests\Models\Navigation\NavPointOfInterest', $poi); + $this->assertEquals(100, $poi->getLat()); + $this->assertEquals(200, $poi->getLong()); + $this->assertEquals('Brandenburger Tor', $poi->getName()); + } + + /** + * @group DDC-1651 + */ + public function testSetParameterCompositeKeyObject() + { + $this->putGermanysBrandenburderTor(); + + $poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('lat' => 100, 'long' => 200)); + $photo = new NavPhotos($poi, "asdf"); + $this->_em->persist($photo); + $this->_em->flush(); + $this->_em->clear(); + + $dql = 'SELECT t FROM Doctrine\Tests\Models\Navigation\NavPhotos t WHERE t.poi = ?1'; + + $this->setExpectedException('Doctrine\ORM\Query\QueryException', 'A single-valued association path expression to an entity with a composite primary key is not supported.'); + $sql = $this->_em->createQuery($dql)->getSQL(); + } + + public function testManyToManyCompositeRelation() + { + $this->putGermanysBrandenburderTor(); + $tour = $this->putTripAroundEurope(); + + $tour = $this->_em->find('Doctrine\Tests\Models\Navigation\NavTour', $tour->getId()); + + $this->assertEquals(1, count($tour->getPointOfInterests())); + } + + public function testCompositeDqlEagerFetching() + { + $this->putGermanysBrandenburderTor(); + $this->putTripAroundEurope(); + + $dql = 'SELECT t, p, c FROM Doctrine\Tests\Models\Navigation\NavTour t ' . + 'INNER JOIN t.pois p INNER JOIN p.country c'; + $tours = $this->_em->createQuery($dql)->getResult(); + + $this->assertEquals(1, count($tours)); + + $pois = $tours[0]->getPointOfInterests(); + + $this->assertEquals(1, count($pois)); + $this->assertEquals('Brandenburger Tor', $pois[0]->getName()); + } + + public function testCompositeCollectionMemberExpression() + { + $this->markTestSkipped('How to test this?'); + + $this->putGermanysBrandenburderTor(); + $this->putTripAroundEurope(); + + $dql = 'SELECT t FROM Doctrine\Tests\Models\Navigation\NavTour t, Doctrine\Tests\Models\Navigation\NavPointOfInterest p ' . + 'WHERE p MEMBER OF t.pois'; + $tours = $this->_em->createQuery($dql) + ->getResult(); + + $this->assertEquals(1, count($tours)); + } + + public function testSpecifiyUnknownIdentifierPrimaryKeyFails() + { + $this->setExpectedException('Doctrine\ORM\ORMException', 'The identifier long is missing for a query of Doctrine\Tests\Models\Navigation\NavPointOfInterest'); + $poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('key1' => 100)); + } + + /** + * @group DDC-1939 + */ + public function testDeleteCompositePersistentCollection() + { + $this->putGermanysBrandenburderTor(); + + $poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('lat' => 100, 'long' => 200)); + $poi->addVisitor(new NavUser("test1")); + $poi->addVisitor(new NavUser("test2")); + + $this->_em->flush(); + + $poi->getVisitors()->clear(); + + $this->_em->flush(); + $this->_em->clear(); + + $poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('lat' => 100, 'long' => 200)); + $this->assertEquals(0, count($poi->getVisitors())); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/CustomTreeWalkersTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/CustomTreeWalkersTest.php new file mode 100644 index 0000000..72fc6d5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/CustomTreeWalkersTest.php @@ -0,0 +1,157 @@ +. + */ + +namespace Doctrine\Tests\ORM\Functional; + +use Doctrine\ORM\Query; + +require_once __DIR__ . '/../../TestInit.php'; + +/** + * Test case for custom AST walking and modification. + * + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + */ +class CustomTreeWalkersTest extends \Doctrine\Tests\OrmTestCase +{ + private $_em; + + protected function setUp() + { + $this->_em = $this->_getTestEntityManager(); + } + + public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed) + { + try { + $query = $this->_em->createQuery($dqlToBeTested); + $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\Tests\ORM\Functional\CustomTreeWalker')) + ->useQueryCache(false); + + $this->assertEquals($sqlToBeConfirmed, $query->getSql()); + $query->free(); + } catch (\Exception $e) { + $this->fail($e->getMessage() . ' at "' . $e->getFile() . '" on line ' . $e->getLine()); + + } + } + + public function testSupportsQueriesWithoutWhere() + { + $this->assertSqlGeneration( + 'select u from Doctrine\Tests\Models\CMS\CmsUser u', + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ WHERE c0_.id = 1" + ); + } + + public function testSupportsQueriesWithMultipleConditionalExpressions() + { + $this->assertSqlGeneration( + 'select u from Doctrine\Tests\Models\CMS\CmsUser u where u.name = :name or u.name = :otherName', + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ WHERE (c0_.name = ? OR c0_.name = ?) AND c0_.id = 1" + ); + } + + public function testSupportsQueriesWithSimpleConditionalExpression() + { + $this->assertSqlGeneration( + 'select u from Doctrine\Tests\Models\CMS\CmsUser u where u.name = :name', + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ WHERE c0_.name = ? AND c0_.id = 1" + ); + } +} + +class CustomTreeWalker extends Query\TreeWalkerAdapter +{ + public function walkSelectStatement(Query\AST\SelectStatement $selectStatement) + { + // Get the DQL aliases of all the classes we want to modify + $dqlAliases = array(); + + foreach ($this->_getQueryComponents() as $dqlAlias => $comp) { + // Hard-coded check just for demonstration: We want to modify the query if + // it involves the CmsUser class. + if ($comp['metadata']->name == 'Doctrine\Tests\Models\CMS\CmsUser') { + $dqlAliases[] = $dqlAlias; + } + } + + // Create our conditions for all involved classes + $factors = array(); + foreach ($dqlAliases as $alias) { + $pathExpr = new Query\AST\PathExpression(Query\AST\PathExpression::TYPE_STATE_FIELD, $alias, 'id'); + $pathExpr->type = Query\AST\PathExpression::TYPE_STATE_FIELD; + $comparisonExpr = new Query\AST\ComparisonExpression($pathExpr, '=', 1); + + $condPrimary = new Query\AST\ConditionalPrimary; + $condPrimary->simpleConditionalExpression = $comparisonExpr; + + $factor = new Query\AST\ConditionalFactor($condPrimary); + $factors[] = $factor; + } + + if (($whereClause = $selectStatement->whereClause) !== null) { + // There is already a WHERE clause, so append the conditions + $condExpr = $whereClause->conditionalExpression; + + // Since Phase 1 AST optimizations were included, we need to re-add the ConditionalExpression + if ( ! ($condExpr instanceof Query\AST\ConditionalExpression)) { + $condExpr = new Query\AST\ConditionalExpression(array($condExpr)); + + $whereClause->conditionalExpression = $condExpr; + } + + $existingTerms = $whereClause->conditionalExpression->conditionalTerms; + + if (count($existingTerms) > 1) { + // More than one term, so we need to wrap all these terms in a single root term + // i.e: "WHERE u.name = :foo or u.other = :bar" => "WHERE (u.name = :foo or u.other = :bar) AND " + + $primary = new Query\AST\ConditionalPrimary; + $primary->conditionalExpression = new Query\AST\ConditionalExpression($existingTerms); + $existingFactor = new Query\AST\ConditionalFactor($primary); + $term = new Query\AST\ConditionalTerm(array_merge(array($existingFactor), $factors)); + + $selectStatement->whereClause->conditionalExpression->conditionalTerms = array($term); + } else { + // Just one term so we can simply append our factors to that term + $singleTerm = $selectStatement->whereClause->conditionalExpression->conditionalTerms[0]; + + // Since Phase 1 AST optimizations were included, we need to re-add the ConditionalExpression + if ( ! ($singleTerm instanceof Query\AST\ConditionalTerm)) { + $singleTerm = new Query\AST\ConditionalTerm(array($singleTerm)); + + $selectStatement->whereClause->conditionalExpression->conditionalTerms[0] = $singleTerm; + } + + $singleTerm->conditionalFactors = array_merge($singleTerm->conditionalFactors, $factors); + $selectStatement->whereClause->conditionalExpression->conditionalTerms = array($singleTerm); + } + } else { + // Create a new WHERE clause with our factors + $term = new Query\AST\ConditionalTerm($factors); + $condExpr = new Query\AST\ConditionalExpression(array($term)); + $whereClause = new Query\AST\WhereClause($condExpr); + $selectStatement->whereClause = $whereClause; + } + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTest.php new file mode 100644 index 0000000..999d52d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DatabaseDriverTest.php @@ -0,0 +1,166 @@ +useModelSet('cms'); + parent::setUp(); + + $this->_sm = $this->_em->getConnection()->getSchemaManager(); + } + + public function testLoadMetadataFromDatabase() + { + if (!$this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped('Platform does not support foreign keys.'); + } + + $table = new \Doctrine\DBAL\Schema\Table("dbdriver_foo"); + $table->addColumn('id', 'integer'); + $table->setPrimaryKey(array('id')); + $table->addColumn('bar', 'string', array('notnull' => false, 'length' => 200)); + + $this->_sm->dropAndCreateTable($table); + + $metadatas = $this->extractClassMetadata(array("DbdriverFoo")); + + $this->assertArrayHasKey('DbdriverFoo', $metadatas); + $metadata = $metadatas['DbdriverFoo']; + + $this->assertArrayHasKey('id', $metadata->fieldMappings); + $this->assertEquals('id', $metadata->fieldMappings['id']['fieldName']); + $this->assertEquals('id', strtolower($metadata->fieldMappings['id']['columnName'])); + $this->assertEquals('integer', (string)$metadata->fieldMappings['id']['type']); + + $this->assertArrayHasKey('bar', $metadata->fieldMappings); + $this->assertEquals('bar', $metadata->fieldMappings['bar']['fieldName']); + $this->assertEquals('bar', strtolower($metadata->fieldMappings['bar']['columnName'])); + $this->assertEquals('string', (string)$metadata->fieldMappings['bar']['type']); + $this->assertEquals(200, $metadata->fieldMappings['bar']['length']); + $this->assertTrue($metadata->fieldMappings['bar']['nullable']); + } + + public function testLoadMetadataWithForeignKeyFromDatabase() + { + if (!$this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped('Platform does not support foreign keys.'); + } + + $tableB = new \Doctrine\DBAL\Schema\Table("dbdriver_bar"); + $tableB->addColumn('id', 'integer'); + $tableB->setPrimaryKey(array('id')); + + $this->_sm->dropAndCreateTable($tableB); + + $tableA = new \Doctrine\DBAL\Schema\Table("dbdriver_baz"); + $tableA->addColumn('id', 'integer'); + $tableA->setPrimaryKey(array('id')); + $tableA->addColumn('bar_id', 'integer'); + $tableA->addForeignKeyConstraint('dbdriver_bar', array('bar_id'), array('id')); + + $this->_sm->dropAndCreateTable($tableA); + + $metadatas = $this->extractClassMetadata(array("DbdriverBar", "DbdriverBaz")); + + $this->assertArrayHasKey('DbdriverBaz', $metadatas); + $bazMetadata = $metadatas['DbdriverBaz']; + + $this->assertArrayNotHasKey('barId', $bazMetadata->fieldMappings, "The foreign Key field should not be inflected as 'barId' field, its an association."); + $this->assertArrayHasKey('id', $bazMetadata->fieldMappings); + + $bazMetadata->associationMappings = \array_change_key_case($bazMetadata->associationMappings, \CASE_LOWER); + + $this->assertArrayHasKey('bar', $bazMetadata->associationMappings); + $this->assertEquals(ClassMetadataInfo::MANY_TO_ONE, $bazMetadata->associationMappings['bar']['type']); + } + + public function testDetectManyToManyTables() + { + if (!$this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped('Platform does not support foreign keys.'); + } + + $metadatas = $this->extractClassMetadata(array("CmsUsers", "CmsGroups")); + + $this->assertArrayHasKey('CmsUsers', $metadatas, 'CmsUsers entity was not detected.'); + $this->assertArrayHasKey('CmsGroups', $metadatas, 'CmsGroups entity was not detected.'); + + $this->assertEquals(2, count($metadatas['CmsUsers']->associationMappings)); + $this->assertArrayHasKey('group', $metadatas['CmsUsers']->associationMappings); + $this->assertEquals(1, count($metadatas['CmsGroups']->associationMappings)); + $this->assertArrayHasKey('user', $metadatas['CmsGroups']->associationMappings); + } + + public function testIgnoreManyToManyTableWithoutFurtherForeignKeyDetails() + { + $tableB = new \Doctrine\DBAL\Schema\Table("dbdriver_bar"); + $tableB->addColumn('id', 'integer'); + $tableB->setPrimaryKey(array('id')); + + $tableA = new \Doctrine\DBAL\Schema\Table("dbdriver_baz"); + $tableA->addColumn('id', 'integer'); + $tableA->setPrimaryKey(array('id')); + + $tableMany = new \Doctrine\DBAL\Schema\Table("dbdriver_bar_baz"); + $tableMany->addColumn('bar_id', 'integer'); + $tableMany->addColumn('baz_id', 'integer'); + $tableMany->addForeignKeyConstraint('dbdriver_bar', array('bar_id'), array('id')); + + $metadatas = $this->convertToClassMetadata(array($tableA, $tableB), array($tableMany)); + + $this->assertEquals(0, count($metadatas['DbdriverBaz']->associationMappings), "no association mappings should be detected."); + } + + protected function convertToClassMetadata(array $entityTables, array $manyTables = array()) + { + $driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($this->_sm); + $driver->setTables($entityTables, $manyTables); + + $metadatas = array(); + foreach ($driver->getAllClassNames() AS $className) { + $class = new ClassMetadataInfo($className); + $driver->loadMetadataForClass($className, $class); + $metadatas[$className] = $class; + } + + return $metadatas; + } + + /** + * @param string $className + * @return ClassMetadata + */ + protected function extractClassMetadata(array $classNames) + { + $classNames = array_map('strtolower', $classNames); + $metadatas = array(); + + $driver = new \Doctrine\ORM\Mapping\Driver\DatabaseDriver($this->_sm); + foreach ($driver->getAllClassNames() as $className) { + if (!in_array(strtolower($className), $classNames)) { + continue; + } + $class = new ClassMetadataInfo($className); + $driver->loadMetadataForClass($className, $class); + $metadatas[$className] = $class; + } + + if (count($metadatas) != count($classNames)) { + $this->fail("Have not found all classes matching the names '" . implode(", ", $classNames) . "' only tables " . implode(", ", array_keys($metadatas))); + } + return $metadatas; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DefaultValuesTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DefaultValuesTest.php new file mode 100644 index 0000000..11511a0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DefaultValuesTest.php @@ -0,0 +1,150 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\DefaultValueUser'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\DefaultValueAddress') + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + + public function testSimpleDetachMerge() { + $user = new DefaultValueUser; + $user->name = 'romanb'; + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $userId = $user->id; // e.g. from $_REQUEST + $user2 = $this->_em->getReference(get_class($user), $userId); + + $this->_em->flush(); + $this->assertFalse($user2->__isInitialized__); + + $a = new DefaultValueAddress; + $a->country = 'de'; + $a->zip = '12345'; + $a->city = 'Berlin'; + $a->street = 'Sesamestreet'; + + $a->user = $user2; + $this->_em->persist($a); + $this->_em->flush(); + + $this->assertFalse($user2->__isInitialized__); + $this->_em->clear(); + + $a2 = $this->_em->find(get_class($a), $a->id); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\DefaultValueUser', $a2->getUser()); + $this->assertEquals($userId, $a2->getUser()->getId()); + $this->assertEquals('Poweruser', $a2->getUser()->type); + } + + /** + * @group DDC-1386 + */ + public function testGetPartialReferenceWithDefaultValueNotEvalutedInFlush() + { + $user = new DefaultValueUser; + $user->name = 'romanb'; + $user->type = 'Normaluser'; + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->getPartialReference('Doctrine\Tests\ORM\Functional\DefaultValueUser', $user->id); + $this->assertTrue($this->_em->getUnitOfWork()->isReadOnly($user)); + + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find('Doctrine\Tests\ORM\Functional\DefaultValueUser', $user->id); + + $this->assertEquals('Normaluser', $user->type); + } +} + + +/** + * @Entity @Table(name="defaultvalueuser") + */ +class DefaultValueUser +{ + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + /** + * @Column(type="string") + */ + public $name = ''; + /** + * @Column(type="string") + */ + public $type = 'Poweruser'; + /** + * @OneToOne(targetEntity="DefaultValueAddress", mappedBy="user", cascade={"persist"}) + */ + public $address; + + public function getId() {return $this->id;} +} + +/** + * CmsAddress + * + * @Entity @Table(name="defaultvalueaddresses") + */ +class DefaultValueAddress +{ + /** + * @Column(type="integer") + * @Id @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @Column(type="string", length=50) + */ + public $country; + + /** + * @Column(type="string", length=50) + */ + public $zip; + + /** + * @Column(type="string", length=50) + */ + public $city; + + /** + * Testfield for Schema Updating Tests. + */ + public $street; + + /** + * @OneToOne(targetEntity="DefaultValueUser") + * @JoinColumn(name="user_id", referencedColumnName="id") + */ + public $user; + + public function getUser() {return $this->user;} +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php new file mode 100644 index 0000000..f5c50eb --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php @@ -0,0 +1,218 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testSimpleDetachMerge() { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'dev'; + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + // $user is now detached + + $this->assertFalse($this->_em->contains($user)); + + $user->name = 'Roman B.'; + + //$this->assertEquals(UnitOfWork::STATE_DETACHED, $this->_em->getUnitOfWork()->getEntityState($user)); + + $user2 = $this->_em->merge($user); + + $this->assertFalse($user === $user2); + $this->assertTrue($this->_em->contains($user2)); + $this->assertEquals('Roman B.', $user2->name); + } + + public function testSerializeUnserializeModifyMerge() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $ph1 = new CmsPhonenumber; + $ph1->phonenumber = "1234"; + $user->addPhonenumber($ph1); + + $this->_em->persist($user); + $this->_em->flush(); + $this->assertTrue($this->_em->contains($user)); + $this->assertTrue($user->phonenumbers->isInitialized()); + + $serialized = serialize($user); + $this->_em->clear(); + $this->assertFalse($this->_em->contains($user)); + unset($user); + + $user = unserialize($serialized); + + $this->assertEquals(1, count($user->getPhonenumbers()), "Pre-Condition: 1 Phonenumber"); + + $ph2 = new CmsPhonenumber; + $ph2->phonenumber = "56789"; + $user->addPhonenumber($ph2); + $oldPhonenumbers = $user->getPhonenumbers(); + $this->assertEquals(2, count($oldPhonenumbers), "Pre-Condition: 2 Phonenumbers"); + $this->assertFalse($this->_em->contains($user)); + + $this->_em->persist($ph2); + + // Merge back in + $user = $this->_em->merge($user); // merge cascaded to phonenumbers + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $user->phonenumbers[0]->user); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $user->phonenumbers[1]->user); + $im = $this->_em->getUnitOfWork()->getIdentityMap(); + $this->_em->flush(); + + $this->assertTrue($this->_em->contains($user), "Failed to assert that merged user is contained inside EntityManager persistence context."); + $phonenumbers = $user->getPhonenumbers(); + $this->assertNotSame($oldPhonenumbers, $phonenumbers, "Merge should replace the Detached Collection with a new PersistentCollection."); + $this->assertEquals(2, count($phonenumbers), "Failed to assert that two phonenumbers are contained in the merged users phonenumber collection."); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $phonenumbers[1]); + $this->assertTrue($this->_em->contains($phonenumbers[1]), "Failed to assert that second phonenumber in collection is contained inside EntityManager persistence context."); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $phonenumbers[0]); + $this->assertTrue($this->_em->getUnitOfWork()->isInIdentityMap($phonenumbers[0])); + $this->assertTrue($this->_em->contains($phonenumbers[0]), "Failed to assert that first phonenumber in collection is contained inside EntityManager persistence context."); + } + + /** + * @group DDC-203 + */ + public function testDetachedEntityThrowsExceptionOnFlush() + { + $ph = new CmsPhonenumber(); + $ph->phonenumber = '12345'; + $this->_em->persist($ph); + $this->_em->flush(); + $this->_em->clear(); + $this->_em->persist($ph); + try { + $this->_em->flush(); + $this->fail(); + } catch (\Exception $expected) {} + } + + public function testUninitializedLazyAssociationsAreIgnoredOnMerge() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $address = new CmsAddress; + $address->city = 'Berlin'; + $address->country = 'Germany'; + $address->street = 'Sesamestreet'; + $address->zip = 12345; + $address->setUser($user); + $this->_em->persist($address); + $this->_em->persist($user); + + $this->_em->flush(); + $this->_em->clear(); + + $address2 = $this->_em->find(get_class($address), $address->id); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $address2->user); + $this->assertFalse($address2->user->__isInitialized__); + $detachedAddress2 = unserialize(serialize($address2)); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $detachedAddress2->user); + $this->assertFalse($detachedAddress2->user->__isInitialized__); + + $managedAddress2 = $this->_em->merge($detachedAddress2); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $managedAddress2->user); + $this->assertFalse($managedAddress2->user === $detachedAddress2->user); + $this->assertFalse($managedAddress2->user->__isInitialized__); + } + + /** + * @group DDC-822 + */ + public function testUseDetachedEntityAsQueryParameter() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $this->_em->persist($user); + + $this->_em->flush(); + $this->_em->detach($user); + + $dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1"; + $query = $this->_em->createQuery($dql); + $query->setParameter(1, $user); + + $newUser = $query->getSingleResult(); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $newUser); + $this->assertEquals('gblanco', $newUser->username); + } + + /** + * @group DDC-920 + */ + public function testDetachManagedUnpersistedEntity() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $this->_em->persist($user); + $this->_em->detach($user); + + $this->_em->flush(); + + $this->assertFalse($this->_em->contains($user)); + $this->assertFalse($this->_em->getUnitOfWork()->isInIdentityMap($user)); + } + + /** + * @group DDC-1340 + */ + public function testMergeArticleWrongVersion() + { + $article = new CmsArticle(); + $article->topic = "test"; + $article->text = "test"; + + $this->_em->persist($article); + $this->_em->flush(); + + $this->_em->detach($article); + + $sql = "UPDATE cms_articles SET version = version+1 WHERE id = " . $article->id; + $this->_em->getConnection()->executeUpdate($sql); + + $this->setExpectedException('Doctrine\ORM\OptimisticLockException', 'The optimistic lock failed, version 1 was expected, but is actually 2'); + $this->_em->merge($article); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryCriteriaTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryCriteriaTest.php new file mode 100644 index 0000000..8631e52 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryCriteriaTest.php @@ -0,0 +1,87 @@ +. + */ + +namespace Doctrine\Tests\ORM\Functional; + +use Doctrine\Tests\Models\Generic\DateTimeModel; +use Doctrine\Common\Collections\Criteria; + +/** + * @author Josiah + */ +class EntityRepositoryCriteriaTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + protected function setUp() + { + $this->useModelSet('generic'); + parent::setUp(); + } + + public function tearDown() + { + if ($this->_em) { + $this->_em->getConfiguration()->setEntityNamespaces(array()); + } + parent::tearDown(); + } + + public function loadFixture() + { + $today = new DateTimeModel(); + $today->datetime = + $today->date = + $today->time = + new \DateTime('today'); + $this->_em->persist($today); + + $tomorrow = new DateTimeModel(); + $tomorrow->datetime = + $tomorrow->date = + $tomorrow->time = + new \DateTime('tomorrow'); + $this->_em->persist($tomorrow); + + $yesterday = new DateTimeModel(); + $yesterday->datetime = + $yesterday->date = + $yesterday->time = + new \DateTime('yesterday'); + $this->_em->persist($yesterday); + + $this->_em->flush(); + + unset($today); + unset($tomorrow); + unset($yesterday); + + $this->_em->clear(); + } + + public function testLteDateComparison() + { + $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\Generic\DateTimeModel'); + $dates = $repository->matching(new Criteria( + Criteria::expr()->lte('datetime', new \DateTime('today')) + )); + + $this->assertEquals(2, count($dates)); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php new file mode 100644 index 0000000..2ce9494 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php @@ -0,0 +1,696 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function tearDown() + { + if ($this->_em) { + $this->_em->getConfiguration()->setEntityNamespaces(array()); + } + parent::tearDown(); + } + + public function loadFixture() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'freak'; + $this->_em->persist($user); + + $user2 = new CmsUser; + $user2->name = 'Guilherme'; + $user2->username = 'gblanco'; + $user2->status = 'dev'; + $this->_em->persist($user2); + + $user3 = new CmsUser; + $user3->name = 'Benjamin'; + $user3->username = 'beberlei'; + $user3->status = null; + $this->_em->persist($user3); + + $user4 = new CmsUser; + $user4->name = 'Alexander'; + $user4->username = 'asm89'; + $user4->status = 'dev'; + $this->_em->persist($user4); + + $this->_em->flush(); + + $user1Id = $user->getId(); + + unset($user); + unset($user2); + unset($user3); + unset($user4); + + $this->_em->clear(); + + return $user1Id; + } + + public function loadAssociatedFixture() + { + $address = new CmsAddress(); + $address->city = "Berlin"; + $address->country = "Germany"; + $address->street = "Foostreet"; + $address->zip = "12345"; + + $user = new CmsUser(); + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'freak'; + $user->setAddress($address); + + $this->_em->persist($user); + $this->_em->persist($address); + $this->_em->flush(); + $this->_em->clear(); + + return array($user->id, $address->id); + } + + public function buildUser($name, $username, $status, $address) + { + $user = new CmsUser(); + $user->name = $name; + $user->username = $username; + $user->status = $status; + $user->setAddress($address); + + $this->_em->persist($user); + $this->_em->flush(); + + return $user; + } + + public function buildAddress($country, $city, $street, $zip) + { + $address = new CmsAddress(); + $address->country = $country; + $address->city = $city; + $address->street = $street; + $address->zip = $zip; + + $this->_em->persist($address); + $this->_em->flush(); + + return $address; + } + + public function testBasicFind() + { + $user1Id = $this->loadFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $user = $repos->find($user1Id); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser',$user); + $this->assertEquals('Roman', $user->name); + $this->assertEquals('freak', $user->status); + } + + public function testFindByField() + { + $user1Id = $this->loadFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $users = $repos->findBy(array('status' => 'dev')); + $this->assertEquals(2, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser',$users[0]); + $this->assertEquals('Guilherme', $users[0]->name); + $this->assertEquals('dev', $users[0]->status); + } + + public function testFindByAssociationWithIntegerAsParameter() + { + $address1 = $this->buildAddress('Germany', 'Berlim', 'Foo st.', '123456'); + $user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1); + + $address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321'); + $user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2); + + $address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654'); + $user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3); + + unset($address1); + unset($address2); + unset($address3); + + $this->_em->clear(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $addresses = $repository->findBy(array('user' => array($user1->getId(), $user2->getId()))); + + $this->assertEquals(2, count($addresses)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress',$addresses[0]); + } + + public function testFindByAssociationWithObjectAsParameter() + { + $address1 = $this->buildAddress('Germany', 'Berlim', 'Foo st.', '123456'); + $user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1); + + $address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321'); + $user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2); + + $address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654'); + $user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3); + + unset($address1); + unset($address2); + unset($address3); + + $this->_em->clear(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $addresses = $repository->findBy(array('user' => array($user1, $user2))); + + $this->assertEquals(2, count($addresses)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress',$addresses[0]); + } + + public function testFindFieldByMagicCall() + { + $user1Id = $this->loadFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $users = $repos->findByStatus('dev'); + $this->assertEquals(2, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser',$users[0]); + $this->assertEquals('Guilherme', $users[0]->name); + $this->assertEquals('dev', $users[0]->status); + } + + public function testFindAll() + { + $user1Id = $this->loadFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $users = $repos->findAll(); + $this->assertEquals(4, count($users)); + } + + public function testFindByAlias() + { + $user1Id = $this->loadFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $this->_em->getConfiguration()->addEntityNamespace('CMS', 'Doctrine\Tests\Models\CMS'); + + $repos = $this->_em->getRepository('CMS:CmsUser'); + + $users = $repos->findAll(); + $this->assertEquals(4, count($users)); + } + + /** + * @expectedException \Doctrine\ORM\ORMException + */ + public function testExceptionIsThrownWhenCallingFindByWithoutParameter() { + $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser') + ->findByStatus(); + } + + /** + * @expectedException \Doctrine\ORM\ORMException + */ + public function testExceptionIsThrownWhenUsingInvalidFieldName() { + $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser') + ->findByThisFieldDoesNotExist('testvalue'); + } + + /** + * @group locking + * @group DDC-178 + */ + public function testPessimisticReadLockWithoutTransaction_ThrowsException() + { + $this->setExpectedException('Doctrine\ORM\TransactionRequiredException'); + + $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser') + ->find(1, \Doctrine\DBAL\LockMode::PESSIMISTIC_READ); + } + + /** + * @group locking + * @group DDC-178 + */ + public function testPessimisticWriteLockWithoutTransaction_ThrowsException() + { + $this->setExpectedException('Doctrine\ORM\TransactionRequiredException'); + + $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser') + ->find(1, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE); + } + + /** + * @group locking + * @group DDC-178 + */ + public function testOptimisticLockUnversionedEntity_ThrowsException() + { + $this->setExpectedException('Doctrine\ORM\OptimisticLockException'); + + $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser') + ->find(1, \Doctrine\DBAL\LockMode::OPTIMISTIC); + } + + /** + * @group locking + * @group DDC-178 + */ + public function testIdentityMappedOptimisticLockUnversionedEntity_ThrowsException() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'freak'; + $this->_em->persist($user); + $this->_em->flush(); + + $userId = $user->id; + + $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId); + + $this->setExpectedException('Doctrine\ORM\OptimisticLockException'); + $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId, \Doctrine\DBAL\LockMode::OPTIMISTIC); + } + + /** + * @group DDC-819 + */ + public function testFindMagicCallByNullValue() + { + $this->loadFixture(); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $users = $repos->findByStatus(null); + $this->assertEquals(1, count($users)); + } + + /** + * @group DDC-819 + */ + public function testInvalidMagicCall() + { + $this->setExpectedException('BadMethodCallException'); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $repos->foo(); + } + + /** + * @group DDC-817 + */ + public function testFindByAssociationKey_ExceptionOnInverseSide() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $this->setExpectedException('Doctrine\ORM\ORMException', "You cannot search for the association field 'Doctrine\Tests\Models\CMS\CmsUser#address', because it is the inverse side of an association. Find methods only work on owning side associations."); + $user = $repos->findBy(array('address' => $addressId)); + } + + /** + * @group DDC-817 + */ + public function testFindOneByAssociationKey() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $address = $repos->findOneBy(array('user' => $userId)); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $address); + $this->assertEquals($addressId, $address->id); + } + + /** + * @group DDC-817 + */ + public function testFindByAssociationKey() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $addresses = $repos->findBy(array('user' => $userId)); + + $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsAddress', $addresses); + $this->assertEquals(1, count($addresses)); + $this->assertEquals($addressId, $addresses[0]->id); + } + + /** + * @group DDC-817 + */ + public function testFindAssociationByMagicCall() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $addresses = $repos->findByUser($userId); + + $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsAddress', $addresses); + $this->assertEquals(1, count($addresses)); + $this->assertEquals($addressId, $addresses[0]->id); + } + + /** + * @group DDC-817 + */ + public function testFindOneAssociationByMagicCall() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $address = $repos->findOneByUser($userId); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $address); + $this->assertEquals($addressId, $address->id); + } + + public function testValidNamedQueryRetrieval() + { + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $query = $repos->createNamedQuery('all'); + + $this->assertInstanceOf('Doctrine\ORM\Query', $query); + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', $query->getDQL()); + } + + public function testInvalidNamedQueryRetrieval() + { + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + + $repos->createNamedQuery('invalidNamedQuery'); + } + + /** + * @group DDC-1087 + */ + public function testIsNullCriteriaDoesNotGenerateAParameter() + { + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repos->findBy(array('status' => null, 'username' => 'romanb')); + + $params = $this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['params']; + $this->assertEquals(1, count($params), "Should only execute with one parameter."); + $this->assertEquals(array('romanb'), $params); + } + + public function testIsNullCriteria() + { + $this->loadFixture(); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $users = $repos->findBy(array('status' => null)); + $this->assertEquals(1, count($users)); + } + + /** + * @group DDC-1094 + */ + public function testFindByLimitOffset() + { + $this->loadFixture(); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $users1 = $repos->findBy(array(), null, 1, 0); + $users2 = $repos->findBy(array(), null, 1, 1); + + $this->assertEquals(4, count($repos->findBy(array()))); + $this->assertEquals(1, count($users1)); + $this->assertEquals(1, count($users2)); + $this->assertNotSame($users1[0], $users2[0]); + } + + /** + * @group DDC-1094 + */ + public function testFindByOrderBy() + { + $this->loadFixture(); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $usersAsc = $repos->findBy(array(), array("username" => "ASC")); + $usersDesc = $repos->findBy(array(), array("username" => "DESC")); + + $this->assertEquals(4, count($usersAsc), "Pre-condition: only four users in fixture"); + $this->assertEquals(4, count($usersDesc), "Pre-condition: only four users in fixture"); + $this->assertSame($usersAsc[0], $usersDesc[3]); + $this->assertSame($usersAsc[3], $usersDesc[0]); + } + + /** + * @group DDC-1426 + */ + public function testFindFieldByMagicCallOrderBy() + { + $this->loadFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $usersAsc = $repos->findByStatus('dev', array('username' => "ASC")); + $usersDesc = $repos->findByStatus('dev', array('username' => "DESC")); + + $this->assertEquals(2, count($usersAsc)); + $this->assertEquals(2, count($usersDesc)); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser',$usersAsc[0]); + $this->assertEquals('Alexander', $usersAsc[0]->name); + $this->assertEquals('dev', $usersAsc[0]->status); + + $this->assertSame($usersAsc[0], $usersDesc[1]); + $this->assertSame($usersAsc[1], $usersDesc[0]); + } + + /** + * @group DDC-1426 + */ + public function testFindFieldByMagicCallLimitOffset() + { + $this->loadFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $users1 = $repos->findByStatus('dev', array(), 1, 0); + $users2 = $repos->findByStatus('dev', array(), 1, 1); + + $this->assertEquals(1, count($users1)); + $this->assertEquals(1, count($users2)); + $this->assertNotSame($users1[0], $users2[0]); + } + + /** + * @group DDC-753 + */ + public function testDefaultRepositoryClassName() + { + $this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository"); + $this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753DefaultRepository"); + $this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\Tests\Models\DDC753\DDC753DefaultRepository"); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithDefaultCustomRepository'); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753DefaultRepository", $repos); + $this->assertTrue($repos->isDefaultRepository()); + + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithCustomRepository'); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753CustomRepository", $repos); + $this->assertTrue($repos->isCustomRepository()); + + $this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\Tests\Models\DDC753\DDC753DefaultRepository"); + $this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\ORM\EntityRepository"); + $this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository"); + + } + + + /** + * @group DDC-753 + * @expectedException Doctrine\ORM\ORMException + * @expectedExceptionMessage Invalid repository class 'Doctrine\Tests\Models\DDC753\DDC753InvalidRepository'. It must be a Doctrine\Common\Persistence\ObjectRepository. + */ + public function testSetDefaultRepositoryInvalidClassError() + { + $this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository"); + $this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753InvalidRepository"); + } + + /** + * @group DDC-1500 + */ + public function testInvalidOrientation() + { + $this->setExpectedException('Doctrine\ORM\ORMException', 'Invalid order by orientation specified for Doctrine\Tests\Models\CMS\CmsUser#username'); + + $repo = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $repo->findBy(array('status' => 'test'), array('username' => 'INVALID')); + } + + /** + * @group DDC-1713 + */ + public function testFindByAssocationArray() + { + $repo = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsArticle'); + $data = $repo->findBy(array('user' => array(1, 2, 3))); + + $query = array_pop($this->_sqlLoggerStack->queries); + $this->assertEquals(array(1,2,3), $query['params'][0]); + $this->assertEquals(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY, $query['types'][0]); + } + + /** + * @group DDC-1637 + */ + public function testMatchingEmptyCriteria() + { + $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repository->matching(new Criteria()); + + $this->assertEquals(4, count($users)); + } + + /** + * @group DDC-1637 + */ + public function testMatchingCriteriaEqComparison() + { + $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repository->matching(new Criteria( + Criteria::expr()->eq('username', 'beberlei') + )); + + $this->assertEquals(1, count($users)); + } + + /** + * @group DDC-1637 + */ + public function testMatchingCriteriaNeqComparison() + { + $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repository->matching(new Criteria( + Criteria::expr()->neq('username', 'beberlei') + )); + + $this->assertEquals(3, count($users)); + } + + /** + * @group DDC-1637 + */ + public function testMatchingCriteriaInComparison() + { + $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repository->matching(new Criteria( + Criteria::expr()->in('username', array('beberlei', 'gblanco')) + )); + + $this->assertEquals(2, count($users)); + } + + /** + * @group DDC-1637 + */ + public function testMatchingCriteriaNotInComparison() + { + $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repository->matching(new Criteria( + Criteria::expr()->notIn('username', array('beberlei', 'gblanco', 'asm89')) + )); + + $this->assertEquals(1, count($users)); + } + + /** + * @group DDC-1637 + */ + public function testMatchingCriteriaLtComparison() + { + $firstUserId = $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repository->matching(new Criteria( + Criteria::expr()->lt('id', $firstUserId + 1) + )); + + $this->assertEquals(1, count($users)); + } + + /** + * @group DDC-1637 + */ + public function testMatchingCriteriaLeComparison() + { + $firstUserId = $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repository->matching(new Criteria( + Criteria::expr()->lte('id', $firstUserId + 1) + )); + + $this->assertEquals(2, count($users)); + } + + /** + * @group DDC-1637 + */ + public function testMatchingCriteriaGtComparison() + { + $firstUserId = $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repository->matching(new Criteria( + Criteria::expr()->gt('id', $firstUserId) + )); + + $this->assertEquals(3, count($users)); + } + + /** + * @group DDC-1637 + */ + public function testMatchingCriteriaGteComparison() + { + $firstUserId = $this->loadFixture(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $users = $repository->matching(new Criteria( + Criteria::expr()->gte('id', $firstUserId) + )); + + $this->assertEquals(4, count($users)); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php new file mode 100644 index 0000000..f8b41e0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php @@ -0,0 +1,583 @@ +useModelSet('cms'); + parent::setUp(); + + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); + $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + + $this->loadFixture(); + } + + public function tearDown() + { + parent::tearDown(); + + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); + $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + } + + /** + * @group DDC-546 + */ + public function testCountNotInitializesCollection() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $queryCount = $this->getCurrentQueryCount(); + + $this->assertFalse($user->groups->isInitialized()); + $this->assertEquals(3, count($user->groups)); + $this->assertFalse($user->groups->isInitialized()); + + foreach ($user->groups AS $group) { } + + $this->assertEquals($queryCount + 2, $this->getCurrentQueryCount(), "Expecting two queries to be fired for count, then iteration."); + } + + /** + * @group DDC-546 + */ + public function testCountWhenNewEntityPresent() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + + $newGroup = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $newGroup->name = "Test4"; + + $user->addGroup($newGroup); + $this->_em->persist($newGroup); + + $this->assertFalse($user->groups->isInitialized()); + $this->assertEquals(4, count($user->groups)); + $this->assertFalse($user->groups->isInitialized()); + } + + /** + * @group DDC-546 + */ + public function testCountWhenInitialized() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $queryCount = $this->getCurrentQueryCount(); + + foreach ($user->groups AS $group) { } + + $this->assertTrue($user->groups->isInitialized()); + $this->assertEquals(3, count($user->groups)); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Should only execute one query to initialize colleciton, no extra query for count() more."); + } + + /** + * @group DDC-546 + */ + public function testCountInverseCollection() + { + $group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId); + $this->assertFalse($group->users->isInitialized(), "Pre-Condition"); + + $this->assertEquals(4, count($group->users)); + $this->assertFalse($group->users->isInitialized(), "Extra Lazy collection should not be initialized by counting the collection."); + } + + /** + * @group DDC-546 + */ + public function testCountOneToMany() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $this->assertFalse($user->groups->isInitialized(), "Pre-Condition"); + + $this->assertEquals(2, count($user->articles)); + } + + /** + * @group DDC-546 + */ + public function testFullSlice() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized."); + + $someGroups = $user->groups->slice(null); + $this->assertEquals(3, count($someGroups)); + } + + /** + * @group DDC-546 + */ + public function testSlice() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized."); + + $queryCount = $this->getCurrentQueryCount(); + + $someGroups = $user->groups->slice(0, 2); + + $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsGroup', $someGroups); + $this->assertEquals(2, count($someGroups)); + $this->assertFalse($user->groups->isInitialized(), "Slice should not initialize the collection if it wasn't before!"); + + $otherGroup = $user->groups->slice(2, 1); + + $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsGroup', $otherGroup); + $this->assertEquals(1, count($otherGroup)); + $this->assertFalse($user->groups->isInitialized()); + + foreach ($user->groups AS $group) { } + + $this->assertTrue($user->groups->isInitialized()); + $this->assertEquals(3, count($user->groups)); + + $this->assertEquals($queryCount + 3, $this->getCurrentQueryCount()); + } + + /** + * @group DDC-546 + */ + public function testSliceInitializedCollection() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $queryCount = $this->getCurrentQueryCount(); + + foreach ($user->groups AS $group) { } + + $someGroups = $user->groups->slice(0, 2); + + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + + $this->assertEquals(2, count($someGroups)); + $this->assertTrue($user->groups->contains($someGroups[0])); + $this->assertTrue($user->groups->contains($someGroups[1])); + } + + /** + * @group DDC-546 + */ + public function testSliceInverseCollection() + { + $group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId); + $this->assertFalse($group->users->isInitialized(), "Pre-Condition"); + $queryCount = $this->getCurrentQueryCount(); + + $someUsers = $group->users->slice(0, 2); + $otherUsers = $group->users->slice(2, 2); + + $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsUser', $someUsers); + $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsUser', $otherUsers); + $this->assertEquals(2, count($someUsers)); + $this->assertEquals(2, count($otherUsers)); + + // +2 queries executed by slice + $this->assertEquals($queryCount + 2, $this->getCurrentQueryCount(), "Slicing two parts should only execute two additional queries."); + } + + /** + * @group DDC-546 + */ + public function testSliceOneToMany() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized."); + + $queryCount = $this->getCurrentQueryCount(); + + $someArticle = $user->articles->slice(0, 1); + $otherArticle = $user->articles->slice(1, 1); + + $this->assertEquals($queryCount + 2, $this->getCurrentQueryCount()); + } + + /** + * @group DDC-546 + */ + public function testContainsOneToMany() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized."); + + // Test One to Many existance retrieved from DB + $article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId); + $queryCount = $this->getCurrentQueryCount(); + + $this->assertTrue($user->articles->contains($article)); + $this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized."); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + + // Test One to Many existance with state new + $article = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article->topic = "Testnew"; + $article->text = "blub"; + + $queryCount = $this->getCurrentQueryCount(); + $this->assertFalse($user->articles->contains($article)); + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed."); + + // Test One to Many existance with state clear + $this->_em->persist($article); + $this->_em->flush(); + + $queryCount = $this->getCurrentQueryCount(); + $this->assertFalse($user->articles->contains($article)); + $this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of persisted entity should cause one query to be executed."); + $this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized."); + + // Test One to Many existance with state managed + $article = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article->topic = "How to not fail anymore on tests"; + $article->text = "That is simple! Just write more tests!"; + + $this->_em->persist($article); + + $queryCount = $this->getCurrentQueryCount(); + + $this->assertFalse($user->articles->contains($article)); + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of managed entity (but not persisted) should cause no query to be executed."); + $this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized."); + } + + /** + * @group DDC-546 + */ + public function testContainsManyToMany() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized."); + + // Test Many to Many existance retrieved from DB + $group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId); + $queryCount = $this->getCurrentQueryCount(); + + $this->assertTrue($user->groups->contains($group)); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + + // Test Many to Many existance with state new + $group = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $group->name = "A New group!"; + + $queryCount = $this->getCurrentQueryCount(); + + $this->assertFalse($user->groups->contains($group)); + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + + // Test Many to Many existance with state clear + $this->_em->persist($group); + $this->_em->flush(); + + $queryCount = $this->getCurrentQueryCount(); + + $this->assertFalse($user->groups->contains($group)); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Checking for contains of persisted entity should cause one query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + + // Test Many to Many existance with state managed + $group = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $group->name = "My managed group"; + + $this->_em->persist($group); + + $queryCount = $this->getCurrentQueryCount(); + + $this->assertFalse($user->groups->contains($group)); + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of managed entity (but not persisted) should cause no query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + } + + /** + * @group DDC-546 + */ + public function testContainsManyToManyInverse() + { + $group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId); + $this->assertFalse($group->users->isInitialized(), "Pre-Condition: Collection is not initialized."); + + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + + $queryCount = $this->getCurrentQueryCount(); + $this->assertTrue($group->users->contains($user)); + $this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + + $newUser = new \Doctrine\Tests\Models\CMS\CmsUser(); + $newUser->name = "A New group!"; + + $queryCount = $this->getCurrentQueryCount(); + $this->assertFalse($group->users->contains($newUser)); + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + } + + /** + * + */ + public function testRemoveElementOneToMany() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized."); + + // Test One to Many removal with Entity retrieved from DB + $article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId); + $queryCount = $this->getCurrentQueryCount(); + + $user->articles->removeElement($article); + + $this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized."); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + + // Test One to Many removal with Entity state as new + $article = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article->topic = "Testnew"; + $article->text = "blub"; + + $queryCount = $this->getCurrentQueryCount(); + + $user->articles->removeElement($article); + + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing a new entity should cause no query to be executed."); + + // Test One to Many removal with Entity state as clean + $this->_em->persist($article); + $this->_em->flush(); + + $queryCount = $this->getCurrentQueryCount(); + + $user->articles->removeElement($article); + + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a persisted entity should cause one query to be executed."); + $this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized."); + + // Test One to Many removal with Entity state as managed + $article = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article->topic = "How to not fail anymore on tests"; + $article->text = "That is simple! Just write more tests!"; + + $this->_em->persist($article); + + $queryCount = $this->getCurrentQueryCount(); + + $user->articles->removeElement($article); + + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing a managed entity should cause no query to be executed."); + } + + /** + * + */ + public function testRemoveElementManyToMany() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized."); + + // Test Many to Many removal with Entity retrieved from DB + $group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId); + $queryCount = $this->getCurrentQueryCount(); + + $user->groups->removeElement($group); + + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a persisted entity should cause one query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + + // Test Many to Many removal with Entity state as new + $group = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $group->name = "A New group!"; + + $queryCount = $this->getCurrentQueryCount(); + + $user->groups->removeElement($group); + + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing new entity should cause no query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + + // Test Many to Many removal with Entity state as clean + $this->_em->persist($group); + $this->_em->flush(); + + $queryCount = $this->getCurrentQueryCount(); + + $user->groups->removeElement($group); + + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a persisted entity should cause one query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + + // Test Many to Many removal with Entity state as managed + $group = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $group->name = "A New group!"; + + $this->_em->persist($group); + + $queryCount = $this->getCurrentQueryCount(); + + $user->groups->removeElement($group); + + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing a managed entity should cause no query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + } + + /** + * + */ + public function testRemoveElementManyToManyInverse() + { + $group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId); + $this->assertFalse($group->users->isInitialized(), "Pre-Condition: Collection is not initialized."); + + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $queryCount = $this->getCurrentQueryCount(); + + $group->users->removeElement($user); + + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a managed entity should cause one query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + + $newUser = new \Doctrine\Tests\Models\CMS\CmsUser(); + $newUser->name = "A New group!"; + + $queryCount = $this->getCurrentQueryCount(); + + $group->users->removeElement($newUser); + + $this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing a new entity should cause no query to be executed."); + $this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized."); + } + + /** + * @group DDC-1399 + */ + public function testCountAfterAddThenFlush() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + + $newGroup = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $newGroup->name = "Test4"; + + $user->addGroup($newGroup); + $this->_em->persist($newGroup); + + $this->assertFalse($user->groups->isInitialized()); + $this->assertEquals(4, count($user->groups)); + $this->assertFalse($user->groups->isInitialized()); + + $this->_em->flush(); + + $this->assertEquals(4, count($user->groups)); + } + + /** + * @group DDC-1462 + */ + public function testSliceOnDirtyCollection() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + /* @var $user CmsUser */ + + $newGroup = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $newGroup->name = "Test4"; + + $user->addGroup($newGroup); + $this->_em->persist($newGroup); + + $qc = $this->getCurrentQueryCount(); + $groups = $user->groups->slice(0, 10); + + $this->assertEquals(4, count($groups)); + $this->assertEquals($qc + 1, $this->getCurrentQueryCount()); + } + + private function loadFixture() + { + $user1 = new \Doctrine\Tests\Models\CMS\CmsUser(); + $user1->username = "beberlei"; + $user1->name = "Benjamin"; + $user1->status = "active"; + + $user2 = new \Doctrine\Tests\Models\CMS\CmsUser(); + $user2->username = "jwage"; + $user2->name = "Jonathan"; + $user2->status = "active"; + + $user3 = new \Doctrine\Tests\Models\CMS\CmsUser(); + $user3->username = "romanb"; + $user3->name = "Roman"; + $user3->status = "active"; + + $user4 = new \Doctrine\Tests\Models\CMS\CmsUser(); + $user4->username = "gblanco"; + $user4->name = "Guilherme"; + $user4->status = "active"; + + $this->_em->persist($user1); + $this->_em->persist($user2); + $this->_em->persist($user3); + $this->_em->persist($user4); + + $group1 = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $group1->name = "Test1"; + + $group2 = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $group2->name = "Test2"; + + $group3 = new \Doctrine\Tests\Models\CMS\CmsGroup(); + $group3->name = "Test3"; + + $user1->addGroup($group1); + $user1->addGroup($group2); + $user1->addGroup($group3); + + $user2->addGroup($group1); + $user3->addGroup($group1); + $user4->addGroup($group1); + + $this->_em->persist($group1); + $this->_em->persist($group2); + $this->_em->persist($group3); + + $article1 = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article1->topic = "Test"; + $article1->text = "Test"; + $article1->setAuthor($user1); + + $article2 = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article2->topic = "Test"; + $article2->text = "Test"; + $article2->setAuthor($user1); + + $this->_em->persist($article1); + $this->_em->persist($article2); + + $this->_em->flush(); + $this->_em->clear(); + + $this->articleId = $article1->id; + $this->userId = $user1->getId(); + $this->groupId = $group1->id; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/FlushEventTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/FlushEventTest.php new file mode 100644 index 0000000..8167e85 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/FlushEventTest.php @@ -0,0 +1,94 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testPersistNewEntitiesOnPreFlush() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_em->getEventManager()->addEventListener(Events::onFlush, new OnFlushListener); + + $user = new CmsUser; + $user->username = 'romanb'; + $user->name = 'Roman'; + $user->status = 'Dev'; + + $this->_em->persist($user); + + $this->assertEquals(0, $user->phonenumbers->count()); + + $this->_em->flush(); + + $this->assertEquals(1, $user->phonenumbers->count()); + $this->assertTrue($this->_em->contains($user->phonenumbers->get(0))); + $this->assertTrue($user->phonenumbers->get(0)->getUser() === $user); + + $this->assertFalse($user->phonenumbers->isDirty()); + + // Can be used together with SQL Logging to check that a subsequent flush has + // nothing to do. This proofs the correctness of the changes that happened in onFlush. + //echo "SECOND FLUSH"; + //$this->_em->flush(); + } +} + +class OnFlushListener +{ + public function onFlush(OnFlushEventArgs $args) + { + //echo "---preFlush".PHP_EOL; + + $em = $args->getEntityManager(); + $uow = $em->getUnitOfWork(); + + foreach ($uow->getScheduledEntityInsertions() as $entity) { + + if ($entity instanceof CmsUser) { + // Adds a phonenumber to every newly persisted CmsUser ... + + $phone = new CmsPhonenumber; + $phone->phonenumber = 12345; + // Update object model + $entity->addPhonenumber($phone); + // Invoke regular persist call + $em->persist($phone); + // Explicitly calculate the changeset since onFlush is raised + // after changeset calculation! + $uow->computeChangeSet($em->getClassMetadata(get_class($phone)), $phone); + + // Take a snapshot because the UoW wont do this for us, because + // the UoW did not visit this collection. + // Alternatively we could provide an ->addVisitedCollection() method + // on the UoW. + $entity->getPhonenumbers()->takeSnapshot(); + } + + /*foreach ($uow->getEntityChangeSet($entity) as $field => $change) { + list ($old, $new) = $change; + + var_dump($old); + }*/ + + } + } +} + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/HydrationCacheTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/HydrationCacheTest.php new file mode 100644 index 0000000..9dc556d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/HydrationCacheTest.php @@ -0,0 +1,88 @@ +useModelSet('cms'); + + parent::setUp(); + + $user = new CmsUser; + $user->name = "Benjamin"; + $user->username = "beberlei"; + $user->status = 'active'; + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + } + + public function testHydrationCache() + { + $cache = new ArrayCache(); + $dql = "SELECT u FROM Doctrine\Tests\Models\Cms\CmsUser u"; + + $users = $this->_em->createQuery($dql) + ->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache)) + ->getResult(); + + $c = $this->getCurrentQueryCount(); + $users = $this->_em->createQuery($dql) + ->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache)) + ->getResult(); + + $this->assertEquals($c, $this->getCurrentQueryCount(), "Should not execute query. Its cached!"); + + $users = $this->_em->createQuery($dql) + ->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache)) + ->getArrayResult(); + + $this->assertEquals($c + 1, $this->getCurrentQueryCount(), "Hydration is part of cache key."); + + $users = $this->_em->createQuery($dql) + ->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache)) + ->getArrayResult(); + + $this->assertEquals($c + 1, $this->getCurrentQueryCount(), "Hydration now cached"); + + $users = $this->_em->createQuery($dql) + ->setHydrationCacheProfile(new QueryCacheProfile(null, 'cachekey', $cache)) + ->getArrayResult(); + + $this->assertTrue($cache->contains('cachekey'), 'Explicit cache key'); + + $users = $this->_em->createQuery($dql) + ->setHydrationCacheProfile(new QueryCacheProfile(null, 'cachekey', $cache)) + ->getArrayResult(); + $this->assertEquals($c + 2, $this->getCurrentQueryCount(), "Hydration now cached"); + } + + public function testHydrationParametersSerialization() + { + $cache = new ArrayCache(); + + $dql = "SELECT u FROM Doctrine\Tests\Models\Cms\CmsUser u WHERE u.id = ?1"; + $query = $this->_em->createQuery($dql) + ->setParameter(1, $userId = 1) + ->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache)); + + $query->getResult(); + + $c = $this->getCurrentQueryCount(); + + $query->getResult(); + + $this->assertEquals($c, $this->getCurrentQueryCount(), "Should not execute query. Its cached!"); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/IdentityMapTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/IdentityMapTest.php new file mode 100644 index 0000000..84d0064 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/IdentityMapTest.php @@ -0,0 +1,288 @@ + + */ +class IdentityMapTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + protected function setUp() { + $this->useModelSet('cms'); + parent::setUp(); + } + + public function testBasicIdentityManagement() + { + $user = new CmsUser; + $user->status = 'dev'; + $user->username = 'romanb'; + $user->name = 'Roman B.'; + + $address = new CmsAddress; + $address->country = 'de'; + $address->zip = 1234; + $address->city = 'Berlin'; + + $user->setAddress($address); + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $user2 = $this->_em->find(get_class($user), $user->getId()); + $this->assertTrue($user2 !== $user); + $user3 = $this->_em->find(get_class($user), $user->getId()); + $this->assertTrue($user2 === $user3); + + $address2 = $this->_em->find(get_class($address), $address->getId()); + $this->assertTrue($address2 !== $address); + $address3 = $this->_em->find(get_class($address), $address->getId()); + $this->assertTrue($address2 === $address3); + + $this->assertTrue($user2->getAddress() === $address2); // !!! + } + + public function testSingleValuedAssociationIdentityMapBehaviorWithRefresh() + { + $address = new CmsAddress; + $address->country = 'de'; + $address->zip = '12345'; + $address->city = 'Berlin'; + + $user1 = new CmsUser; + $user1->status = 'dev'; + $user1->username = 'romanb'; + $user1->name = 'Roman B.'; + + $user2 = new CmsUser; + $user2->status = 'dev'; + $user2->username = 'gblanco'; + $user2->name = 'Guilherme Blanco'; + + $address->setUser($user1); + + $this->_em->persist($address); + $this->_em->persist($user1); + $this->_em->persist($user2); + $this->_em->flush(); + + $this->assertSame($user1, $address->user); + + //external update to CmsAddress + $this->_em->getConnection()->executeUpdate('update cms_addresses set user_id = ?', array($user2->getId())); + + // But we want to have this external change! + // Solution 1: refresh(), broken atm! + $this->_em->refresh($address); + + // Now the association should be "correct", referencing $user2 + $this->assertSame($user2, $address->user); + $this->assertSame($user2->address, $address); // check back reference also + + // Attention! refreshes can result in broken bidirectional associations! this is currently expected! + // $user1 still points to $address! + $this->assertSame($user1->address, $address); + } + + public function testSingleValuedAssociationIdentityMapBehaviorWithRefreshQuery() + { + $address = new CmsAddress; + $address->country = 'de'; + $address->zip = '12345'; + $address->city = 'Berlin'; + + $user1 = new CmsUser; + $user1->status = 'dev'; + $user1->username = 'romanb'; + $user1->name = 'Roman B.'; + + $user2 = new CmsUser; + $user2->status = 'dev'; + $user2->username = 'gblanco'; + $user2->name = 'Guilherme Blanco'; + + $address->setUser($user1); + + $this->_em->persist($address); + $this->_em->persist($user1); + $this->_em->persist($user2); + $this->_em->flush(); + + + $this->assertSame($user1, $address->user); + + //external update to CmsAddress + $this->_em->getConnection()->executeUpdate('update cms_addresses set user_id = ?', array($user2->getId())); + + //select + $q = $this->_em->createQuery('select a, u from Doctrine\Tests\Models\CMS\CmsAddress a join a.user u'); + $address2 = $q->getSingleResult(); + + $this->assertSame($address, $address2); + + // Should still be $user1 + $this->assertSame($user1, $address2->user); + $this->assertTrue($user2->address === null); + + // But we want to have this external change! + // Solution 2: Alternatively, a refresh query should work + $q = $this->_em->createQuery('select a, u from Doctrine\Tests\Models\CMS\CmsAddress a join a.user u'); + $q->setHint(Query::HINT_REFRESH, true); + $address3 = $q->getSingleResult(); + + $this->assertSame($address, $address3); // should still be the same, always from identity map + + // Now the association should be "correct", referencing $user2 + $this->assertSame($user2, $address2->user); + $this->assertSame($user2->address, $address2); // check back reference also + + // Attention! refreshes can result in broken bidirectional associations! this is currently expected! + // $user1 still points to $address2! + $this->assertSame($user1->address, $address2); + } + + public function testCollectionValuedAssociationIdentityMapBehaviorWithRefreshQuery() + { + $user = new CmsUser; + $user->status = 'dev'; + $user->username = 'romanb'; + $user->name = 'Roman B.'; + + $phone1 = new CmsPhonenumber; + $phone1->phonenumber = 123; + + $phone2 = new CmsPhonenumber; + $phone2->phonenumber = 234; + + $phone3 = new CmsPhonenumber; + $phone3->phonenumber = 345; + + $user->addPhonenumber($phone1); + $user->addPhonenumber($phone2); + $user->addPhonenumber($phone3); + + $this->_em->persist($user); // cascaded to phone numbers + $this->_em->flush(); + + $this->assertEquals(3, count($user->getPhonenumbers())); + $this->assertFalse($user->getPhonenumbers()->isDirty()); + + //external update to CmsAddress + $this->_em->getConnection()->executeUpdate('insert into cms_phonenumbers (phonenumber, user_id) VALUES (?,?)', array(999, $user->getId())); + + //select + $q = $this->_em->createQuery('select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p'); + $user2 = $q->getSingleResult(); + + $this->assertSame($user, $user2); + + // Should still be the same 3 phonenumbers + $this->assertEquals(3, count($user2->getPhonenumbers())); + + // But we want to have this external change! + // Solution 1: refresh(). + //$this->_em->refresh($user2); broken atm! + // Solution 2: Alternatively, a refresh query should work + $q = $this->_em->createQuery('select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p'); + $q->setHint(Query::HINT_REFRESH, true); + $user3 = $q->getSingleResult(); + + $this->assertSame($user, $user3); // should still be the same, always from identity map + + // Now the collection should be refreshed with correct count + $this->assertEquals(4, count($user3->getPhonenumbers())); + } + + public function testCollectionValuedAssociationIdentityMapBehaviorWithRefresh() + { + $user = new CmsUser; + $user->status = 'dev'; + $user->username = 'romanb'; + $user->name = 'Roman B.'; + + $phone1 = new CmsPhonenumber; + $phone1->phonenumber = 123; + + $phone2 = new CmsPhonenumber; + $phone2->phonenumber = 234; + + $phone3 = new CmsPhonenumber; + $phone3->phonenumber = 345; + + $user->addPhonenumber($phone1); + $user->addPhonenumber($phone2); + $user->addPhonenumber($phone3); + + $this->_em->persist($user); // cascaded to phone numbers + $this->_em->flush(); + + $this->assertEquals(3, count($user->getPhonenumbers())); + + //external update to CmsAddress + $this->_em->getConnection()->executeUpdate('insert into cms_phonenumbers (phonenumber, user_id) VALUES (?,?)', array(999, $user->getId())); + + //select + $q = $this->_em->createQuery('select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p'); + $user2 = $q->getSingleResult(); + + $this->assertSame($user, $user2); + + // Should still be the same 3 phonenumbers + $this->assertEquals(3, count($user2->getPhonenumbers())); + + // But we want to have this external change! + // Solution 1: refresh(). + $this->_em->refresh($user2); + + $this->assertSame($user, $user2); // should still be the same, always from identity map + + // Now the collection should be refreshed with correct count + $this->assertEquals(4, count($user2->getPhonenumbers())); + } + + public function testReusedSplObjectHashDoesNotConfuseUnitOfWork() + { + $hash1 = $this->subRoutine($this->_em); + // Make sure cycles are collected NOW, because a PersistentCollection references + // its owner, hence without forcing gc on cycles now the object will not (yet) + // be garbage collected and thus the object hash is not reused. + // This is not a memory leak! + gc_collect_cycles(); + + $user1 = new CmsUser; + $user1->status = 'dev'; + $user1->username = 'jwage'; + $user1->name = 'Jonathan W.'; + $hash2 = spl_object_hash($user1); + $this->assertEquals($hash1, $hash2); // Hash reused! + $this->_em->persist($user1); + $this->_em->flush(); + } + + private function subRoutine($em) { + $user = new CmsUser; + $user->status = 'dev'; + $user->username = 'romanb'; + $user->name = 'Roman B.'; + $em->persist($user); + $em->flush(); + $em->remove($user); + $em->flush(); + + return spl_object_hash($user); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/IndexByAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/IndexByAssociationTest.php new file mode 100644 index 0000000..bca4ea5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/IndexByAssociationTest.php @@ -0,0 +1,105 @@ +useModelSet('stockexchange'); + parent::setUp(); + $this->loadFixture(); + } + + public function loadFixture() + { + $this->market = new Market("Some Exchange"); + $stock1 = new Stock("AAPL", 10, $this->market); + $stock2 = new Stock("GOOG", 20, $this->market); + + $this->bond = new Bond("MyBond"); + $this->bond->addStock($stock1); + $this->bond->addStock($stock2); + + $this->_em->persist($this->market); + $this->_em->persist($stock1); + $this->_em->persist($stock2); + $this->_em->persist($this->bond); + $this->_em->flush(); + $this->_em->clear(); + } + + public function testManyToOneFinder() + { + /* @var $market Doctrine\Tests\Models\StockExchange\Market */ + $market = $this->_em->find('Doctrine\Tests\Models\StockExchange\Market', $this->market->getId()); + + $this->assertEquals(2, count($market->stocks)); + $this->assertTrue(isset($market->stocks['AAPL']), "AAPL symbol has to be key in indexed assocation."); + $this->assertTrue(isset($market->stocks['GOOG']), "GOOG symbol has to be key in indexed assocation."); + $this->assertEquals("AAPL", $market->stocks['AAPL']->getSymbol()); + $this->assertEquals("GOOG", $market->stocks['GOOG']->getSymbol()); + } + + public function testManyToOneDQL() + { + $dql = "SELECT m, s FROM Doctrine\Tests\Models\StockExchange\Market m JOIN m.stocks s WHERE m.id = ?1"; + $market = $this->_em->createQuery($dql)->setParameter(1, $this->market->getId())->getSingleResult(); + + $this->assertEquals(2, count($market->stocks)); + $this->assertTrue(isset($market->stocks['AAPL']), "AAPL symbol has to be key in indexed assocation."); + $this->assertTrue(isset($market->stocks['GOOG']), "GOOG symbol has to be key in indexed assocation."); + $this->assertEquals("AAPL", $market->stocks['AAPL']->getSymbol()); + $this->assertEquals("GOOG", $market->stocks['GOOG']->getSymbol()); + } + + public function testManyToMany() + { + $bond = $this->_em->find('Doctrine\Tests\Models\StockExchange\Bond', $this->bond->getId()); + + $this->assertEquals(2, count($bond->stocks)); + $this->assertTrue(isset($bond->stocks['AAPL']), "AAPL symbol has to be key in indexed assocation."); + $this->assertTrue(isset($bond->stocks['GOOG']), "GOOG symbol has to be key in indexed assocation."); + $this->assertEquals("AAPL", $bond->stocks['AAPL']->getSymbol()); + $this->assertEquals("GOOG", $bond->stocks['GOOG']->getSymbol()); + } + + public function testManytoManyDQL() + { + $dql = "SELECT b, s FROM Doctrine\Tests\Models\StockExchange\Bond b JOIN b.stocks s WHERE b.id = ?1"; + $bond = $this->_em->createQuery($dql)->setParameter(1, $this->bond->getId())->getSingleResult(); + + $this->assertEquals(2, count($bond->stocks)); + $this->assertTrue(isset($bond->stocks['AAPL']), "AAPL symbol has to be key in indexed assocation."); + $this->assertTrue(isset($bond->stocks['GOOG']), "GOOG symbol has to be key in indexed assocation."); + $this->assertEquals("AAPL", $bond->stocks['AAPL']->getSymbol()); + $this->assertEquals("GOOG", $bond->stocks['GOOG']->getSymbol()); + } + + public function testDqlOverrideIndexBy() + { + $dql = "SELECT b, s FROM Doctrine\Tests\Models\StockExchange\Bond b JOIN b.stocks s INDEX BY s.id WHERE b.id = ?1"; + $bond = $this->_em->createQuery($dql)->setParameter(1, $this->bond->getId())->getSingleResult(); + + $this->assertEquals(2, count($bond->stocks)); + $this->assertFalse(isset($bond->stocks['AAPL']), "AAPL symbol not exists in re-indexed assocation."); + $this->assertFalse(isset($bond->stocks['GOOG']), "GOOG symbol not exists in re-indexed assocation."); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/LifecycleCallbackTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/LifecycleCallbackTest.php new file mode 100644 index 0000000..230f562 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/LifecycleCallbackTest.php @@ -0,0 +1,311 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestUser'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackCascader'), + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + + public function testPreSavePostSaveCallbacksAreInvoked() + { + $entity = new LifecycleCallbackTestEntity; + $entity->value = 'hello'; + $this->_em->persist($entity); + $this->_em->flush(); + + $this->assertTrue($entity->prePersistCallbackInvoked); + $this->assertTrue($entity->postPersistCallbackInvoked); + + $this->_em->clear(); + + $query = $this->_em->createQuery("select e from Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity e"); + $result = $query->getResult(); + $this->assertTrue($result[0]->postLoadCallbackInvoked); + + $result[0]->value = 'hello again'; + + $this->_em->flush(); + + $this->assertEquals('changed from preUpdate callback!', $result[0]->value); + } + + public function testPreFlushCallbacksAreInvoked() + { + $entity = new LifecycleCallbackTestEntity; + $entity->value = 'hello'; + $this->_em->persist($entity); + + $this->_em->flush(); + + $this->assertTrue($entity->prePersistCallbackInvoked); + $this->assertTrue($entity->preFlushCallbackInvoked); + + $entity->preFlushCallbackInvoked = false; + $this->_em->flush(); + + $this->assertTrue($entity->preFlushCallbackInvoked); + + $entity->value = 'bye'; + $entity->preFlushCallbackInvoked = false; + $this->_em->flush(); + + $this->assertTrue($entity->preFlushCallbackInvoked); + } + + public function testChangesDontGetLost() + { + $user = new LifecycleCallbackTestUser; + $user->setName('Bob'); + $user->setValue('value'); + $this->_em->persist($user); + $this->_em->flush(); + + $user->setName('Alice'); + $this->_em->flush(); // Triggers preUpdate + + $this->_em->clear(); + + $user2 = $this->_em->find(get_class($user), $user->getId()); + + $this->assertEquals('Alice', $user2->getName()); + $this->assertEquals('Hello World', $user2->getValue()); + } + + /** + * @group DDC-194 + */ + public function testGetReferenceWithPostLoadEventIsDelayedUntilProxyTrigger() + { + $entity = new LifecycleCallbackTestEntity; + $entity->value = 'hello'; + $this->_em->persist($entity); + $this->_em->flush(); + $id = $entity->getId(); + + $this->_em->clear(); + + $reference = $this->_em->getReference('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity', $id); + $this->assertFalse($reference->postLoadCallbackInvoked); + + $reference->getValue(); // trigger proxy load + $this->assertTrue($reference->postLoadCallbackInvoked); + } + + /** + * @group DDC-958 + */ + public function testPostLoadTriggeredOnRefresh() + { + $entity = new LifecycleCallbackTestEntity; + $entity->value = 'hello'; + $this->_em->persist($entity); + $this->_em->flush(); + $id = $entity->getId(); + + $this->_em->clear(); + + $reference = $this->_em->find('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity', $id); + $this->assertTrue($reference->postLoadCallbackInvoked); + $reference->postLoadCallbackInvoked = false; + + $this->_em->refresh($reference); + $this->assertTrue($reference->postLoadCallbackInvoked, "postLoad should be invoked when refresh() is called."); + } + + /** + * @group DDC-113 + */ + public function testCascadedEntitiesCallsPrePersist() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $e1 = new LifecycleCallbackTestEntity; + $e2 = new LifecycleCallbackTestEntity; + + $c = new LifecycleCallbackCascader(); + $this->_em->persist($c); + + $c->entities[] = $e1; + $c->entities[] = $e2; + $e1->cascader = $c; + $e2->cascader = $c; + + //$this->_em->persist($c); + $this->_em->flush(); + + $this->assertTrue($e1->prePersistCallbackInvoked); + $this->assertTrue($e2->prePersistCallbackInvoked); + } + + public function testLifecycleCallbacksGetInherited() + { + $childMeta = $this->_em->getClassMetadata(__NAMESPACE__ . '\LifecycleCallbackChildEntity'); + $this->assertEquals(array('prePersist' => array(0 => 'doStuff')), $childMeta->lifecycleCallbacks); + } + + public function testLifecycleListener_ChangeUpdateChangeSet() + { + $listener = new LifecycleListenerPreUpdate; + $this->_em->getEventManager()->addEventListener(array('preUpdate'), $listener); + + $user = new LifecycleCallbackTestUser; + $user->setName('Bob'); + $user->setValue('value'); + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT u FROM Doctrine\Tests\ORM\Functional\LifecycleCallbackTestUser u WHERE u.name = 'Bob'"; + $bob = $this->_em->createQuery($dql)->getSingleResult(); + $bob->setName('Alice'); + + $this->_em->flush(); // preUpdate reverts Alice to Bob + $this->_em->clear(); + + $this->_em->getEventManager()->removeEventListener(array('preUpdate'), $listener); + + $bob = $this->_em->createQuery($dql)->getSingleResult(); + + $this->assertEquals('Bob', $bob->getName()); + } +} + +/** @Entity @HasLifecycleCallbacks */ +class LifecycleCallbackTestUser { + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; + /** @Column(type="string") */ + private $value; + /** @Column(type="string") */ + private $name; + public function getId() {return $this->id;} + public function getValue() {return $this->value;} + public function setValue($value) {$this->value = $value;} + public function getName() {return $this->name;} + public function setName($name) {$this->name = $name;} + /** @PreUpdate */ + public function testCallback() {$this->value = 'Hello World';} +} + +/** + * @Entity + * @HasLifecycleCallbacks + * @Table(name="lc_cb_test_entity") + */ +class LifecycleCallbackTestEntity +{ + /* test stuff */ + public $prePersistCallbackInvoked = false; + public $postPersistCallbackInvoked = false; + public $postLoadCallbackInvoked = false; + + public $preFlushCallbackInvoked = false; + + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + /** + * @Column(type="string", nullable=true) + */ + public $value; + + /** + * @ManyToOne(targetEntity="LifecycleCallbackCascader") + * @JoinColumn(name="cascader_id", referencedColumnName="id") + */ + public $cascader; + + public function getId() { + return $this->id; + } + + public function getValue() { + return $this->value; + } + + /** @PrePersist */ + public function doStuffOnPrePersist() { + $this->prePersistCallbackInvoked = true; + } + + /** @PostPersist */ + public function doStuffOnPostPersist() { + $this->postPersistCallbackInvoked = true; + } + + /** @PostLoad */ + public function doStuffOnPostLoad() { + $this->postLoadCallbackInvoked = true; + } + + /** @PreUpdate */ + public function doStuffOnPreUpdate() { + $this->value = 'changed from preUpdate callback!'; + } + + /** @PreFlush */ + public function doStuffOnPreFlush() { + $this->preFlushCallbackInvoked = true; + } +} + +/** + * @Entity + * @Table(name="lc_cb_test_cascade") + */ +class LifecycleCallbackCascader +{ + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @OneToMany(targetEntity="LifecycleCallbackTestEntity", mappedBy="cascader", cascade={"persist"}) + */ + public $entities; + + public function __construct() + { + $this->entities = new \Doctrine\Common\Collections\ArrayCollection(); + } +} + +/** @MappedSuperclass @HasLifecycleCallbacks */ +class LifecycleCallbackParentEntity { + /** @PrePersist */ + function doStuff() { + + } +} + +/** @Entity @Table(name="lc_cb_childentity") */ +class LifecycleCallbackChildEntity extends LifecycleCallbackParentEntity { + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; +} + +class LifecycleListenerPreUpdate +{ + public function preUpdate(PreUpdateEventArgs $eventArgs) + { + $eventArgs->setNewValue('name', 'Bob'); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/GearmanLockTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/GearmanLockTest.php new file mode 100644 index 0000000..a67a44d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/GearmanLockTest.php @@ -0,0 +1,180 @@ +markTestSkipped('pecl/gearman is required for this test to run.'); + } + + $this->useModelSet('cms'); + parent::setUp(); + $this->tasks = array(); + + $this->gearman = new \GearmanClient(); + $this->gearman->addServer(); + $this->gearman->setCompleteCallback(array($this, "gearmanTaskCompleted")); + + $article = new CmsArticle(); + $article->text = "my article"; + $article->topic = "Hello"; + + $this->_em->persist($article); + $this->_em->flush(); + + $this->articleId = $article->id; + } + + public function gearmanTaskCompleted($task) + { + $this->maxRunTime = max($this->maxRunTime, $task->data()); + } + + public function testFindWithLock() + { + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + + $this->assertLockWorked(); + } + + public function testFindWithWriteThenReadLock() + { + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_READ); + + $this->assertLockWorked(); + } + + public function testFindWithReadThenWriteLock() + { + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_READ); + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + + $this->assertLockWorked(); + } + + public function testFindWithOneLock() + { + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::NONE); + + $this->assertLockDoesNotBlock(); + } + + public function testDqlWithLock() + { + $this->asyncDqlWithLock('SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a', array(), LockMode::PESSIMISTIC_WRITE); + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + + $this->assertLockWorked(); + } + + public function testLock() + { + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + $this->asyncLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + + $this->assertLockWorked(); + } + + public function testLock2() + { + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + $this->asyncLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_READ); + + $this->assertLockWorked(); + } + + public function testLock3() + { + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_READ); + $this->asyncLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + + $this->assertLockWorked(); + } + + public function testLock4() + { + $this->asyncFindWithLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::NONE); + $this->asyncLock('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId, LockMode::PESSIMISTIC_WRITE); + + $this->assertLockDoesNotBlock(); + } + + protected function assertLockDoesNotBlock() + { + $this->assertLockWorked($onlyForSeconds = 1); + } + + protected function assertLockWorked($forTime = 2, $notLongerThan = null) + { + if ($notLongerThan === null) { + $notLongerThan = $forTime + 1; + } + + $this->gearman->runTasks(); + + $this->assertTrue($this->maxRunTime > $forTime, + "Because of locking this tests should have run at least " . $forTime . " seconds, ". + "but only did for " . $this->maxRunTime . " seconds."); + $this->assertTrue($this->maxRunTime < $notLongerThan, + "The longest task should not run longer than " . $notLongerThan . " seconds, ". + "but did for " . $this->maxRunTime . " seconds." + ); + } + + protected function asyncFindWithLock($entityName, $entityId, $lockMode) + { + $this->startJob('findWithLock', array( + 'entityName' => $entityName, + 'entityId' => $entityId, + 'lockMode' => $lockMode, + )); + } + + protected function asyncDqlWithLock($dql, $params, $lockMode) + { + $this->startJob('dqlWithLock', array( + 'dql' => $dql, + 'dqlParams' => $params, + 'lockMode' => $lockMode, + )); + } + + protected function asyncLock($entityName, $entityId, $lockMode) + { + $this->startJob('lock', array( + 'entityName' => $entityName, + 'entityId' => $entityId, + 'lockMode' => $lockMode, + )); + } + + protected function startJob($fn, $fixture) + { + $this->gearman->addTask($fn, serialize(array( + 'conn' => $this->_em->getConnection()->getParams(), + 'fixture' => $fixture + ))); + + $this->assertEquals(GEARMAN_SUCCESS, $this->gearman->returnCode()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/LockAgentWorker.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/LockAgentWorker.php new file mode 100644 index 0000000..2db6cce --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/LockAgentWorker.php @@ -0,0 +1,112 @@ +addServer(); + $worker->addFunction("findWithLock", array($lockAgent, "findWithLock")); + $worker->addFunction("dqlWithLock", array($lockAgent, "dqlWithLock")); + $worker->addFunction('lock', array($lockAgent, 'lock')); + + while($worker->work()) { + if ($worker->returnCode() != GEARMAN_SUCCESS) { + echo "return_code: " . $worker->returnCode() . "\n"; + break; + } + } + } + + protected function process($job, \Closure $do) + { + $fixture = $this->processWorkload($job); + + $s = microtime(true); + $this->em->beginTransaction(); + $do($fixture, $this->em); + + sleep(1); + $this->em->rollback(); + $this->em->clear(); + $this->em->close(); + $this->em->getConnection()->close(); + + return (microtime(true) - $s); + } + + public function findWithLock($job) + { + return $this->process($job, function($fixture, $em) { + $entity = $em->find($fixture['entityName'], $fixture['entityId'], $fixture['lockMode']); + }); + } + + public function dqlWithLock($job) + { + return $this->process($job, function($fixture, $em) { + /* @var $query Doctrine\ORM\Query */ + $query = $em->createQuery($fixture['dql']); + $query->setLockMode($fixture['lockMode']); + $query->setParameters($fixture['dqlParams']); + $result = $query->getResult(); + }); + } + + public function lock($job) + { + return $this->process($job, function($fixture, $em) { + $entity = $em->find($fixture['entityName'], $fixture['entityId']); + $em->lock($entity, $fixture['lockMode']); + }); + } + + protected function processWorkload($job) + { + echo "Received job: " . $job->handle() . " for function " . $job->functionName() . "\n"; + + $workload = $job->workload(); + $workload = unserialize($workload); + + if (!isset($workload['conn']) || !is_array($workload['conn'])) { + throw new \InvalidArgumentException("Missing Database parameters"); + } + + $this->em = $this->createEntityManager($workload['conn']); + + if (!isset($workload['fixture'])) { + throw new \InvalidArgumentException("Missing Fixture parameters"); + } + return $workload['fixture']; + } + + protected function createEntityManager($conn) + { + $config = new \Doctrine\ORM\Configuration(); + $config->setProxyDir(__DIR__ . '/../../../Proxies'); + $config->setProxyNamespace('MyProject\Proxies'); + $config->setAutoGenerateProxyClasses(true); + + $annotDriver = $config->newDefaultAnnotationDriver(array(__DIR__ . '/../../../Models/'), true); + $config->setMetadataDriverImpl($annotDriver); + + $cache = new \Doctrine\Common\Cache\ArrayCache(); + $config->setMetadataCacheImpl($cache); + $config->setQueryCacheImpl($cache); + $config->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger()); + + $em = \Doctrine\ORM\EntityManager::create($conn, $config); + + return $em; + } +} + +LockAgentWorker::run(); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/LockTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/LockTest.php new file mode 100644 index 0000000..e7ec0f7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/LockTest.php @@ -0,0 +1,186 @@ +useModelSet('cms'); + parent::setUp(); + $this->handles = array(); + } + + /** + * @group DDC-178 + * @group locking + */ + public function testLockVersionedEntity() { + $article = new CmsArticle(); + $article->text = "my article"; + $article->topic = "Hello"; + + $this->_em->persist($article); + $this->_em->flush(); + + $this->_em->lock($article, LockMode::OPTIMISTIC, $article->version); + } + + /** + * @group DDC-178 + * @group locking + */ + public function testLockVersionedEntity_MissmatchThrowsException() { + $article = new CmsArticle(); + $article->text = "my article"; + $article->topic = "Hello"; + + $this->_em->persist($article); + $this->_em->flush(); + + $this->setExpectedException('Doctrine\ORM\OptimisticLockException'); + $this->_em->lock($article, LockMode::OPTIMISTIC, $article->version + 1); + } + + /** + * @group DDC-178 + * @group locking + */ + public function testLockUnversionedEntity_ThrowsException() { + $user = new CmsUser(); + $user->name = "foo"; + $user->status = "active"; + $user->username = "foo"; + + $this->_em->persist($user); + $this->_em->flush(); + + $this->setExpectedException('Doctrine\ORM\OptimisticLockException'); + $this->_em->lock($user, LockMode::OPTIMISTIC); + } + + /** + * @group DDC-178 + * @group locking + */ + public function testLockUnmanagedEntity_ThrowsException() { + $article = new CmsArticle(); + + $this->setExpectedException('InvalidArgumentException', 'Entity Doctrine\Tests\Models\CMS\CmsArticle'); + $this->_em->lock($article, LockMode::OPTIMISTIC, $article->version + 1); + } + + /** + * @group DDC-178 + * @group locking + */ + public function testLockPessimisticRead_NoTransaction_ThrowsException() { + $article = new CmsArticle(); + $article->text = "my article"; + $article->topic = "Hello"; + + $this->_em->persist($article); + $this->_em->flush(); + + $this->setExpectedException('Doctrine\ORM\TransactionRequiredException'); + $this->_em->lock($article, LockMode::PESSIMISTIC_READ); + } + + /** + * @group DDC-178 + * @group locking + */ + public function testLockPessimisticWrite_NoTransaction_ThrowsException() { + $article = new CmsArticle(); + $article->text = "my article"; + $article->topic = "Hello"; + + $this->_em->persist($article); + $this->_em->flush(); + + $this->setExpectedException('Doctrine\ORM\TransactionRequiredException'); + $this->_em->lock($article, LockMode::PESSIMISTIC_WRITE); + } + + /** + * @group DDC-178 + * @group locking + */ + public function testLockPessimisticWrite() { + $writeLockSql = $this->_em->getConnection()->getDatabasePlatform()->getWriteLockSql(); + if (strlen($writeLockSql) == 0) { + $this->markTestSkipped('Database Driver has no Write Lock support.'); + } + + $article = new CmsArticle(); + $article->text = "my article"; + $article->topic = "Hello"; + + $this->_em->persist($article); + $this->_em->flush(); + + $this->_em->beginTransaction(); + try { + $this->_em->lock($article, LockMode::PESSIMISTIC_WRITE); + $this->_em->commit(); + } catch (\Exception $e) { + $this->_em->rollback(); + throw $e; + } + + $query = array_pop( $this->_sqlLoggerStack->queries ); + $query = array_pop( $this->_sqlLoggerStack->queries ); + $this->assertContains($writeLockSql, $query['sql']); + } + + /** + * @group DDC-178 + */ + public function testLockPessimisticRead() { + $readLockSql = $this->_em->getConnection()->getDatabasePlatform()->getReadLockSql(); + if (strlen($readLockSql) == 0) { + $this->markTestSkipped('Database Driver has no Write Lock support.'); + } + + $article = new CmsArticle(); + $article->text = "my article"; + $article->topic = "Hello"; + + $this->_em->persist($article); + $this->_em->flush(); + + $this->_em->beginTransaction(); + try { + $this->_em->lock($article, LockMode::PESSIMISTIC_READ); + $this->_em->commit(); + } catch (\Exception $e) { + $this->_em->rollback(); + throw $e; + } + + $query = array_pop( $this->_sqlLoggerStack->queries ); + $query = array_pop( $this->_sqlLoggerStack->queries ); + $this->assertContains($readLockSql, $query['sql']); + } + + /** + * @group DDC-1693 + */ + public function testLockOptimisticNonVersionedThrowsExceptionInDQL() + { + $dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'"; + + $this->setExpectedException('Doctrine\ORM\OptimisticLockException', 'The optimistic lock on an entity failed.'); + $sql = $this->_em->createQuery($dql)->setHint( + \Doctrine\ORM\Query::HINT_LOCK_MODE, \Doctrine\DBAL\LockMode::OPTIMISTIC + )->getSQL(); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/OptimisticTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/OptimisticTest.php new file mode 100644 index 0000000..e2341a1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Locking/OptimisticTest.php @@ -0,0 +1,277 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Locking\OptimisticJoinedParent'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Locking\OptimisticJoinedChild'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Locking\OptimisticStandard'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Locking\OptimisticTimestamp') + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + $this->_conn = $this->_em->getConnection(); + } + + public function testJoinedChildInsertSetsInitialVersionValue() + { + $test = new OptimisticJoinedChild(); + $test->name = 'child'; + $test->whatever = 'whatever'; + $this->_em->persist($test); + $this->_em->flush(); + + $this->assertEquals(1, $test->version); + + return $test; + } + + /** + * @depends testJoinedChildInsertSetsInitialVersionValue + */ + public function testJoinedChildFailureThrowsException(OptimisticJoinedChild $child) + { + $q = $this->_em->createQuery('SELECT t FROM Doctrine\Tests\ORM\Functional\Locking\OptimisticJoinedChild t WHERE t.id = :id'); + $q->setParameter('id', $child->id); + $test = $q->getSingleResult(); + + // Manually update/increment the version so we can try and save the same + // $test and make sure the exception is thrown saying the record was + // changed or updated since you read it + $this->_conn->executeQuery('UPDATE optimistic_joined_parent SET version = ? WHERE id = ?', array(2, $test->id)); + + // Now lets change a property and try and save it again + $test->whatever = 'ok'; + try { + $this->_em->flush(); + } catch (OptimisticLockException $e) { + $this->assertSame($test, $e->getEntity()); + } + } + + public function testJoinedParentInsertSetsInitialVersionValue() + { + $test = new OptimisticJoinedParent(); + $test->name = 'parent'; + $this->_em->persist($test); + $this->_em->flush(); + + $this->assertEquals(1, $test->version); + + return $test; + } + + /** + * @depends testJoinedParentInsertSetsInitialVersionValue + */ + public function testJoinedParentFailureThrowsException(OptimisticJoinedParent $parent) + { + $q = $this->_em->createQuery('SELECT t FROM Doctrine\Tests\ORM\Functional\Locking\OptimisticJoinedParent t WHERE t.id = :id'); + $q->setParameter('id', $parent->id); + $test = $q->getSingleResult(); + + // Manually update/increment the version so we can try and save the same + // $test and make sure the exception is thrown saying the record was + // changed or updated since you read it + $this->_conn->executeQuery('UPDATE optimistic_joined_parent SET version = ? WHERE id = ?', array(2, $test->id)); + + // Now lets change a property and try and save it again + $test->name = 'WHATT???'; + try { + $this->_em->flush(); + } catch (OptimisticLockException $e) { + $this->assertSame($test, $e->getEntity()); + } + } + + public function testMultipleFlushesDoIncrementalUpdates() + { + $test = new OptimisticStandard(); + + for ($i = 0; $i < 5; $i++) { + $test->name = 'test' . $i; + $this->_em->persist($test); + $this->_em->flush(); + + $this->assertInternalType('int', $test->getVersion()); + $this->assertEquals($i + 1, $test->getVersion()); + } + } + + public function testStandardInsertSetsInitialVersionValue() + { + $test = new OptimisticStandard(); + $test->name = 'test'; + $this->_em->persist($test); + $this->_em->flush(); + + $this->assertInternalType('int', $test->getVersion()); + $this->assertEquals(1, $test->getVersion()); + + return $test; + } + + /** + * @depends testStandardInsertSetsInitialVersionValue + */ + public function testStandardFailureThrowsException(OptimisticStandard $entity) + { + $q = $this->_em->createQuery('SELECT t FROM Doctrine\Tests\ORM\Functional\Locking\OptimisticStandard t WHERE t.id = :id'); + $q->setParameter('id', $entity->id); + $test = $q->getSingleResult(); + + // Manually update/increment the version so we can try and save the same + // $test and make sure the exception is thrown saying the record was + // changed or updated since you read it + $this->_conn->executeQuery('UPDATE optimistic_standard SET version = ? WHERE id = ?', array(2, $test->id)); + + // Now lets change a property and try and save it again + $test->name = 'WHATT???'; + try { + $this->_em->flush(); + } catch (OptimisticLockException $e) { + $this->assertSame($test, $e->getEntity()); + } + } + + public function testOptimisticTimestampSetsDefaultValue() + { + $test = new OptimisticTimestamp(); + $test->name = 'Testing'; + + $this->assertNull($test->version, "Pre-Condition"); + + $this->_em->persist($test); + $this->_em->flush(); + + $this->assertInstanceOf('DateTime', $test->version); + + return $test; + } + + /** + * @depends testOptimisticTimestampSetsDefaultValue + */ + public function testOptimisticTimestampFailureThrowsException(OptimisticTimestamp $entity) + { + $q = $this->_em->createQuery('SELECT t FROM Doctrine\Tests\ORM\Functional\Locking\OptimisticTimestamp t WHERE t.id = :id'); + $q->setParameter('id', $entity->id); + $test = $q->getSingleResult(); + + $this->assertInstanceOf('DateTime', $test->version); + + // Manually increment the version datetime column + $format = $this->_em->getConnection()->getDatabasePlatform()->getDateTimeFormatString(); + $this->_conn->executeQuery('UPDATE optimistic_timestamp SET version = ? WHERE id = ?', array(date($format, strtotime($test->version->format($format)) + 3600), $test->id)); + + // Try and update the record and it should throw an exception + $test->name = 'Testing again'; + try { + $this->_em->flush(); + } catch (OptimisticLockException $e) { + $this->assertSame($test, $e->getEntity()); + } + } +} + +/** + * @Entity + * @Table(name="optimistic_joined_parent") + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"parent" = "OptimisticJoinedParent", "child" = "OptimisticJoinedChild"}) + */ +class OptimisticJoinedParent +{ + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @Column(type="string", length=255) + */ + public $name; + + /** + * @Version @Column(type="integer") + */ + public $version; +} + +/** + * @Entity + * @Table(name="optimistic_joined_child") + */ +class OptimisticJoinedChild extends OptimisticJoinedParent +{ + /** + * @Column(type="string", length=255) + */ + public $whatever; +} + +/** + * @Entity + * @Table(name="optimistic_standard") + */ +class OptimisticStandard +{ + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @Column(type="string", length=255) + */ + public $name; + + /** + * @Version @Column(type="integer") + */ + private $version; + + function getVersion() {return $this->version;} +} + +/** + * @Entity + * @Table(name="optimistic_timestamp") + */ +class OptimisticTimestamp +{ + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @Column(type="string", length=255) + */ + public $name; + + /** + * @Version @Column(type="datetime") + */ + public $version; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyBasicAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyBasicAssociationTest.php new file mode 100644 index 0000000..1e1df9d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyBasicAssociationTest.php @@ -0,0 +1,380 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testUnsetManyToMany() + { + $user = $this->addCmsUserGblancoWithGroups(1); + + unset($user->groups[0]->users[0]); // inverse side + unset($user->groups[0]); // owning side! + + $this->_em->flush(); + + // Check that the link in the association table has been deleted + $this->assertGblancoGroupCountIs(0); + } + + public function testBasicManyToManyJoin() + { + $user = $this->addCmsUserGblancoWithGroups(1); + $this->_em->clear(); + + $this->assertEquals(0, $this->_em->getUnitOfWork()->size()); + + $query = $this->_em->createQuery("select u, g from Doctrine\Tests\Models\CMS\CmsUser u join u.groups g"); + + $result = $query->getResult(); + + $this->assertEquals(2, $this->_em->getUnitOfWork()->size()); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertEquals('Guilherme', $result[0]->name); + $this->assertEquals(1, $result[0]->getGroups()->count()); + $groups = $result[0]->getGroups(); + $this->assertEquals('Developers_0', $groups[0]->getName()); + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($result[0])); + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($groups[0])); + + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $groups); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $groups[0]->getUsers()); + + $groups[0]->getUsers()->clear(); + $groups->clear(); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select u, g from Doctrine\Tests\Models\CMS\CmsUser u join u.groups g"); + $this->assertEquals(0, count($query->getResult())); + } + + public function testManyToManyAddRemove() + { + $user = $this->addCmsUserGblancoWithGroups(2); + $this->_em->clear(); + + $uRep = $this->_em->getRepository(get_class($user)); + + // Get user + $user = $uRep->findOneById($user->getId()); + + $this->assertNotNull($user, "Has to return exactly one entry."); + + $this->assertFalse($user->getGroups()->isInitialized()); + + // Check groups + $this->assertEquals(2, $user->getGroups()->count()); + + $this->assertTrue($user->getGroups()->isInitialized()); + + // Remove first group + unset($user->groups[0]); + //$user->getGroups()->remove(0); + + $this->_em->flush(); + $this->_em->clear(); + + // Reload same user + $user2 = $uRep->findOneById($user->getId()); + + // Check groups + $this->assertEquals(1, $user2->getGroups()->count()); + } + + public function testManyToManyInverseSideIgnored() + { + $user = $this->addCmsUserGblancoWithGroups(0); + + $group = new CmsGroup; + $group->name = 'Humans'; + + // modify directly, addUser() would also (properly) set the owning side + $group->users[] = $user; + + $this->_em->persist($user); + $this->_em->persist($group); + $this->_em->flush(); + $this->_em->clear(); + + // Association should not exist + $user2 = $this->_em->find(get_class($user), $user->getId()); + + $this->assertNotNull($user2, "Has to return exactly one entry."); + $this->assertEquals(0, $user2->getGroups()->count()); + } + + public function testManyToManyCollectionClearing() + { + $user = $this->addCmsUserGblancoWithGroups($groupCount = 10); + + // Check that there are indeed 10 links in the association table + $this->assertGblancoGroupCountIs($groupCount); + + $user->groups->clear(); + + $this->_em->flush(); + + // Check that the links in the association table have been deleted + $this->assertGblancoGroupCountIs(0); + } + + public function testManyToManyCollectionClearAndAdd() + { + $user = $this->addCmsUserGblancoWithGroups($groupCount = 10); + + $groups = $user->groups->toArray(); + $user->groups->clear(); + + foreach ($groups AS $group) { + $user->groups[] = $group; + } + + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $user->groups); + $this->assertTrue($user->groups->isDirty()); + + $this->assertEquals($groupCount, count($user->groups), "There should be 10 groups in the collection."); + + $this->_em->flush(); + + $this->assertGblancoGroupCountIs($groupCount); + } + + /** + * @param int $expectedGroupCount + */ + public function assertGblancoGroupCountIs($expectedGroupCount) + { + $countDql = "SELECT count(g.id) FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g WHERE u.username = 'gblanco'"; + $this->assertEquals( + $expectedGroupCount, + $this->_em->createQuery($countDql)->getSingleScalarResult(), + "Failed to verify that CmsUser with username 'gblanco' has a group count of 10 with a DQL count query." + ); + } + + public function testRetrieveManyToManyAndAddMore() + { + $user = $this->addCmsUserGblancoWithGroups(2); + + $group = new CmsGroup(); + $group->name = 'Developers_Fresh'; + $this->_em->persist($group); + $this->_em->flush(); + + $this->_em->clear(); + + /* @var $freshUser CmsUser */ + $freshUser = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->getId()); + $newGroup = new CmsGroup(); + $newGroup->setName('12Monkeys'); + $freshUser->addGroup($newGroup); + + $this->assertFalse($freshUser->groups->isInitialized(), "CmsUser::groups Collection has to be uninitialized for this test."); + + $this->_em->flush(); + + $this->assertFalse($freshUser->groups->isInitialized(), "CmsUser::groups Collection has to be uninitialized for this test."); + $this->assertEquals(3, count($freshUser->getGroups())); + $this->assertEquals(3, count($freshUser->getGroups()->getSnapshot()), "Snapshot of CmsUser::groups should contain 3 entries."); + + $this->_em->clear(); + + $freshUser = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->getId()); + $this->assertEquals(3, count($freshUser->getGroups())); + } + + /** + * @group DDC-130 + */ + public function testRemoveUserWithManyGroups() + { + $user = $this->addCmsUserGblancoWithGroups(2); + $userId = $user->getId(); + + $this->_em->remove($user); + $this->_em->flush(); + + $newUser = $this->_em->find(get_class($user), $userId); + $this->assertNull($newUser); + } + + /** + * @group DDC-130 + */ + public function testRemoveGroupWithUser() + { + $user = $this->addCmsUserGblancoWithGroups(2); + + foreach ($user->getGroups() AS $group) { + $this->_em->remove($group); + } + $this->_em->flush(); + $this->_em->clear(); + + $newUser = $this->_em->find(get_class($user), $user->getId()); + $this->assertEquals(0, count($newUser->getGroups())); + } + + public function testDereferenceCollectionDelete() + { + $user = $this->addCmsUserGblancoWithGroups(2); + $user->groups = null; + + $this->_em->flush(); + $this->_em->clear(); + + $newUser = $this->_em->find(get_class($user), $user->getId()); + $this->assertEquals(0, count($newUser->getGroups())); + } + + /** + * @group DDC-839 + */ + public function testWorkWithDqlHydratedEmptyCollection() + { + $user = $this->addCmsUserGblancoWithGroups(0); + $group = new CmsGroup(); + $group->name = "Developers0"; + $this->_em->persist($group); + + $this->_em->flush(); + $this->_em->clear(); + + $newUser = $this->_em->createQuery('SELECT u, g FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.groups g WHERE u.id = ?1') + ->setParameter(1, $user->getId()) + ->getSingleResult(); + $this->assertEquals(0, count($newUser->groups)); + $this->assertInternalType('array', $newUser->groups->getMapping()); + + $newUser->addGroup($group); + + $this->_em->flush(); + $this->_em->clear(); + + $newUser = $this->_em->find(get_class($user), $user->getId()); + $this->assertEquals(1, count($newUser->groups)); + } + + /** + * @param int $groupCount + * @return CmsUser + */ + public function addCmsUserGblancoWithGroups($groupCount = 1) + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + for ($i=0; $i < $groupCount; ++$i) { + $group = new CmsGroup; + $group->name = 'Developers_' . $i; + $user->addGroup($group); + } + + $this->_em->persist($user); + $this->_em->flush(); + + $this->assertNotNull($user->getId(), "User 'gblanco' should have an ID assigned after the persist()/flush() operation."); + + return $user; + } + + /** + * @group DDC-980 + */ + public function testUpdateDeleteSizeSubselectQueries() + { + $this->_em->createQuery("DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE SIZE(u.groups) = 10")->execute(); + $this->_em->createQuery("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.status = 'inactive' WHERE SIZE(u.groups) = 10")->execute(); + } + + /** + * @group DDC-978 + */ + public function testClearAndResetCollection() + { + $user = $this->addCmsUserGblancoWithGroups(2); + $group1 = new CmsGroup; + $group1->name = 'Developers_New1'; + $group2 = new CmsGroup; + $group2->name = 'Developers_New2'; + + $this->_em->persist($group1); + $this->_em->persist($group2); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find(get_class($user), $user->id); + + $coll = new ArrayCollection(array($group1, $group2)); + $user->groups = $coll; + $this->_em->flush(); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $user->groups, + "UnitOfWork should have replaced ArrayCollection with PersistentCollection."); + $this->_em->flush(); + + $this->_em->clear(); + + $user = $this->_em->find(get_class($user), $user->id); + $this->assertEquals(2, count($user->groups)); + $this->assertEquals('Developers_New1', $user->groups[0]->name); + $this->assertEquals('Developers_New2', $user->groups[1]->name); + } + + /** + * @group DDC-733 + */ + public function testInitializePersistentCollection() + { + $user = $this->addCmsUserGblancoWithGroups(2); + $this->_em->clear(); + + $user = $this->_em->find(get_class($user), $user->id); + + $this->assertFalse($user->groups->isInitialized(), "Pre-condition: lazy collection"); + $this->_em->getUnitOfWork()->initializeObject($user->groups); + $this->assertTrue($user->groups->isInitialized(), "Collection should be initialized after calling UnitOfWork::initializeObject()"); + } + + /** + * @group DDC-1189 + * @group DDC-956 + */ + public function testClearBeforeLazyLoad() + { + $user = $this->addCmsUserGblancoWithGroups(4); + + $this->_em->clear(); + + $user = $this->_em->find(get_class($user), $user->id); + $user->groups->clear(); + $this->assertEquals(0, count($user->groups)); + + $this->_em->flush(); + + $user = $this->_em->find(get_class($user), $user->id); + $this->assertEquals(0, count($user->groups)); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyBidirectionalAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyBidirectionalAssociationTest.php new file mode 100644 index 0000000..cfe9f1e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyBidirectionalAssociationTest.php @@ -0,0 +1,202 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->firstProduct = new ECommerceProduct(); + $this->firstProduct->setName("First Product"); + $this->secondProduct = new ECommerceProduct(); + $this->secondProduct->setName("Second Product"); + $this->firstCategory = new ECommerceCategory(); + $this->firstCategory->setName("Business"); + $this->secondCategory = new ECommerceCategory(); + $this->secondCategory->setName("Home"); + } + + public function testSavesAManyToManyAssociationWithCascadeSaveSet() + { + $this->firstProduct->addCategory($this->firstCategory); + $this->firstProduct->addCategory($this->secondCategory); + $this->_em->persist($this->firstProduct); + $this->_em->flush(); + + $this->assertForeignKeysContain($this->firstProduct->getId(), $this->firstCategory->getId()); + $this->assertForeignKeysContain($this->firstProduct->getId(), $this->secondCategory->getId()); + } + + public function testRemovesAManyToManyAssociation() + { + $this->firstProduct->addCategory($this->firstCategory); + $this->firstProduct->addCategory($this->secondCategory); + $this->_em->persist($this->firstProduct); + $this->firstProduct->removeCategory($this->firstCategory); + + $this->_em->flush(); + + $this->assertForeignKeysNotContain($this->firstProduct->getId(), $this->firstCategory->getId()); + $this->assertForeignKeysContain($this->firstProduct->getId(), $this->secondCategory->getId()); + + $this->firstProduct->getCategories()->remove(1); + $this->_em->flush(); + + $this->assertForeignKeysNotContain($this->firstProduct->getId(), $this->secondCategory->getId()); + } + + public function testEagerLoadFromInverseSideAndLazyLoadFromOwningSide() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_createLoadingFixture(); + $categories = $this->_findCategories(); + $this->assertLazyLoadFromOwningSide($categories); + } + + public function testEagerLoadFromOwningSideAndLazyLoadFromInverseSide() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_createLoadingFixture(); + $products = $this->_findProducts(); + $this->assertLazyLoadFromInverseSide($products); + } + + private function _createLoadingFixture() + { + $this->firstProduct->addCategory($this->firstCategory); + $this->firstProduct->addCategory($this->secondCategory); + $this->secondProduct->addCategory($this->firstCategory); + $this->secondProduct->addCategory($this->secondCategory); + $this->_em->persist($this->firstProduct); + $this->_em->persist($this->secondProduct); + + $this->_em->flush(); + $this->_em->clear(); + } + + protected function _findProducts() + { + $query = $this->_em->createQuery('SELECT p, c FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p LEFT JOIN p.categories c ORDER BY p.id, c.id'); + //$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); + $result = $query->getResult(); + $this->assertEquals(2, count($result)); + $cats1 = $result[0]->getCategories(); + $cats2 = $result[1]->getCategories(); + $this->assertTrue($cats1->isInitialized()); + $this->assertTrue($cats2->isInitialized()); + $this->assertFalse($cats1[0]->getProducts()->isInitialized()); + $this->assertFalse($cats2[0]->getProducts()->isInitialized()); + + return $result; + } + + protected function _findCategories() + { + $query = $this->_em->createQuery('SELECT c, p FROM Doctrine\Tests\Models\ECommerce\ECommerceCategory c LEFT JOIN c.products p ORDER BY c.id, p.id'); + //$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); + $result = $query->getResult(); + $this->assertEquals(2, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $result[1]); + $prods1 = $result[0]->getProducts(); + $prods2 = $result[1]->getProducts(); + $this->assertTrue($prods1->isInitialized()); + $this->assertTrue($prods2->isInitialized()); + + $this->assertFalse($prods1[0]->getCategories()->isInitialized()); + $this->assertFalse($prods2[0]->getCategories()->isInitialized()); + + return $result; + } + + public function assertLazyLoadFromInverseSide($products) + { + list ($firstProduct, $secondProduct) = $products; + + $firstProductCategories = $firstProduct->getCategories(); + $secondProductCategories = $secondProduct->getCategories(); + + $this->assertEquals(2, count($firstProductCategories)); + $this->assertEquals(2, count($secondProductCategories)); + + $this->assertTrue($firstProductCategories[0] === $secondProductCategories[0]); + $this->assertTrue($firstProductCategories[1] === $secondProductCategories[1]); + + $firstCategoryProducts = $firstProductCategories[0]->getProducts(); + $secondCategoryProducts = $firstProductCategories[1]->getProducts(); + + $this->assertFalse($firstCategoryProducts->isInitialized()); + $this->assertFalse($secondCategoryProducts->isInitialized()); + $this->assertEquals(0, $firstCategoryProducts->unwrap()->count()); + $this->assertEquals(0, $secondCategoryProducts->unwrap()->count()); + + $this->assertEquals(2, count($firstCategoryProducts)); // lazy-load + $this->assertTrue($firstCategoryProducts->isInitialized()); + $this->assertFalse($secondCategoryProducts->isInitialized()); + $this->assertEquals(2, count($secondCategoryProducts)); // lazy-load + $this->assertTrue($secondCategoryProducts->isInitialized()); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $firstCategoryProducts[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $firstCategoryProducts[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $secondCategoryProducts[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $secondCategoryProducts[1]); + + $this->assertCollectionEquals($firstCategoryProducts, $secondCategoryProducts); + } + + public function assertLazyLoadFromOwningSide($categories) + { + list ($firstCategory, $secondCategory) = $categories; + + $firstCategoryProducts = $firstCategory->getProducts(); + $secondCategoryProducts = $secondCategory->getProducts(); + + $this->assertEquals(2, count($firstCategoryProducts)); + $this->assertEquals(2, count($secondCategoryProducts)); + + $this->assertTrue($firstCategoryProducts[0] === $secondCategoryProducts[0]); + $this->assertTrue($firstCategoryProducts[1] === $secondCategoryProducts[1]); + + $firstProductCategories = $firstCategoryProducts[0]->getCategories(); + $secondProductCategories = $firstCategoryProducts[1]->getCategories(); + + $this->assertFalse($firstProductCategories->isInitialized()); + $this->assertFalse($secondProductCategories->isInitialized()); + $this->assertEquals(0, $firstProductCategories->unwrap()->count()); + $this->assertEquals(0, $secondProductCategories->unwrap()->count()); + + $this->assertEquals(2, count($firstProductCategories)); // lazy-load + $this->assertTrue($firstProductCategories->isInitialized()); + $this->assertFalse($secondProductCategories->isInitialized()); + $this->assertEquals(2, count($secondProductCategories)); // lazy-load + $this->assertTrue($secondProductCategories->isInitialized()); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $firstProductCategories[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $firstProductCategories[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $secondProductCategories[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $secondProductCategories[1]); + + $this->assertCollectionEquals($firstProductCategories, $secondProductCategories); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyEventTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyEventTest.php new file mode 100644 index 0000000..47c96b1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyEventTest.php @@ -0,0 +1,76 @@ + + */ +class ManyToManyEventTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + /** + * @var PostUpdateListener + */ + private $listener; + + protected function setUp() + { + $this->useModelSet('cms'); + parent::setUp(); + $this->listener = new PostUpdateListener(); + $evm = $this->_em->getEventManager(); + $evm->addEventListener(Events::postUpdate, $this->listener); + } + + public function testListenerShouldBeNotifiedOnlyWhenUpdating() + { + $user = $this->createNewValidUser(); + $this->_em->persist($user); + $this->_em->flush(); + $this->assertFalse($this->listener->wasNotified); + + $group = new CmsGroup(); + $group->name = "admins"; + $user->addGroup($group); + $this->_em->persist($user); + $this->_em->flush(); + + $this->assertTrue($this->listener->wasNotified); + } + + /** + * @return CmsUser + */ + private function createNewValidUser() + { + $user = new CmsUser(); + $user->username = 'fran6co'; + $user->name = 'Francisco Facioni'; + $group = new CmsGroup(); + $group->name = "users"; + $user->addGroup($group); + return $user; + } +} + +class PostUpdateListener +{ + /** + * @var bool + */ + public $wasNotified = false; + + /** + * @param $args + */ + public function postUpdate($args) + { + $this->wasNotified = true; + } +} + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManySelfReferentialAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManySelfReferentialAssociationTest.php new file mode 100644 index 0000000..40518e0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManySelfReferentialAssociationTest.php @@ -0,0 +1,124 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->firstProduct = new ECommerceProduct(); + $this->secondProduct = new ECommerceProduct(); + $this->firstRelated = new ECommerceProduct(); + $this->firstRelated->setName("Business"); + $this->secondRelated = new ECommerceProduct(); + $this->secondRelated->setName("Home"); + } + + public function testSavesAManyToManyAssociationWithCascadeSaveSet() + { + $this->firstProduct->addRelated($this->firstRelated); + $this->firstProduct->addRelated($this->secondRelated); + $this->_em->persist($this->firstProduct); + $this->_em->flush(); + + $this->assertForeignKeysContain($this->firstProduct->getId(), + $this->firstRelated->getId()); + $this->assertForeignKeysContain($this->firstProduct->getId(), + $this->secondRelated->getId()); + } + + public function testRemovesAManyToManyAssociation() + { + $this->firstProduct->addRelated($this->firstRelated); + $this->firstProduct->addRelated($this->secondRelated); + $this->_em->persist($this->firstProduct); + $this->firstProduct->removeRelated($this->firstRelated); + + $this->_em->flush(); + + $this->assertForeignKeysNotContain($this->firstProduct->getId(), + $this->firstRelated->getId()); + $this->assertForeignKeysContain($this->firstProduct->getId(), + $this->secondRelated->getId()); + } + + public function testEagerLoadsOwningSide() + { + $this->_createLoadingFixture(); + $products = $this->_findProducts(); + $this->assertLoadingOfOwningSide($products); + } + + public function testLazyLoadsOwningSide() + { + $this->_createLoadingFixture(); + + $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct'); + $metadata->associationMappings['related']['fetch'] = ClassMetadata::FETCH_LAZY; + + $query = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p'); + $products = $query->getResult(); + $this->assertLoadingOfOwningSide($products); + } + + public function assertLoadingOfOwningSide($products) + { + list ($firstProduct, $secondProduct) = $products; + $this->assertEquals(2, count($firstProduct->getRelated())); + $this->assertEquals(2, count($secondProduct->getRelated())); + + $categories = $firstProduct->getRelated(); + $firstRelatedBy = $categories[0]->getRelated(); + $secondRelatedBy = $categories[1]->getRelated(); + + $this->assertEquals(2, count($firstRelatedBy)); + $this->assertEquals(2, count($secondRelatedBy)); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $firstRelatedBy[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $firstRelatedBy[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $secondRelatedBy[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $secondRelatedBy[1]); + + $this->assertCollectionEquals($firstRelatedBy, $secondRelatedBy); + } + + protected function _createLoadingFixture() + { + $this->firstProduct->addRelated($this->firstRelated); + $this->firstProduct->addRelated($this->secondRelated); + $this->secondProduct->addRelated($this->firstRelated); + $this->secondProduct->addRelated($this->secondRelated); + $this->_em->persist($this->firstProduct); + $this->_em->persist($this->secondProduct); + + $this->_em->flush(); + $this->_em->clear(); + } + + protected function _findProducts() + { + $query = $this->_em->createQuery('SELECT p, r FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p LEFT JOIN p.related r ORDER BY p.id, r.id'); + return $query->getResult(); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyUnidirectionalAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyUnidirectionalAssociationTest.php new file mode 100644 index 0000000..ba83d53 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ManyToManyUnidirectionalAssociationTest.php @@ -0,0 +1,108 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->firstProduct = new ECommerceProduct(); + $this->firstProduct->setName('Doctrine 1.x Manual'); + $this->secondProduct = new ECommerceProduct(); + $this->secondProduct->setName('Doctrine 2.x Manual'); + $this->firstCart = new ECommerceCart(); + $this->secondCart = new ECommerceCart(); + } + + public function testSavesAManyToManyAssociationWithCascadeSaveSet() + { + $this->firstCart->addProduct($this->firstProduct); + $this->firstCart->addProduct($this->secondProduct); + $this->_em->persist($this->firstCart); + $this->_em->flush(); + + $this->assertForeignKeysContain($this->firstCart->getId(), $this->firstProduct->getId()); + $this->assertForeignKeysContain($this->firstCart->getId(), $this->secondProduct->getId()); + } + + public function testRemovesAManyToManyAssociation() + { + $this->firstCart->addProduct($this->firstProduct); + $this->firstCart->addProduct($this->secondProduct); + $this->_em->persist($this->firstCart); + $this->firstCart->removeProduct($this->firstProduct); + + $this->_em->flush(); + + $this->assertForeignKeysNotContain($this->firstCart->getId(), $this->firstProduct->getId()); + $this->assertForeignKeysContain($this->firstCart->getId(), $this->secondProduct->getId()); + } + + public function testEagerLoad() + { + $this->_createFixture(); + + $query = $this->_em->createQuery('SELECT c, p FROM Doctrine\Tests\Models\ECommerce\ECommerceCart c LEFT JOIN c.products p ORDER BY c.id, p.id'); + $result = $query->getResult(); + $firstCart = $result[0]; + $products = $firstCart->getProducts(); + $secondCart = $result[1]; + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $products[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $products[1]); + $this->assertCollectionEquals($products, $secondCart->getProducts()); + //$this->assertEquals("Doctrine 1.x Manual", $products[0]->getName()); + //$this->assertEquals("Doctrine 2.x Manual", $products[1]->getName()); + } + + public function testLazyLoadsCollection() + { + $this->_createFixture(); + $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCart'); + $metadata->associationMappings['products']['fetch'] = ClassMetadata::FETCH_LAZY; + + $query = $this->_em->createQuery('SELECT c FROM Doctrine\Tests\Models\ECommerce\ECommerceCart c'); + $result = $query->getResult(); + $firstCart = $result[0]; + $products = $firstCart->getProducts(); + $secondCart = $result[1]; + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $products[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $products[1]); + $this->assertCollectionEquals($products, $secondCart->getProducts()); + } + + private function _createFixture() + { + $this->firstCart->addProduct($this->firstProduct); + $this->firstCart->addProduct($this->secondProduct); + $this->secondCart->addProduct($this->firstProduct); + $this->secondCart->addProduct($this->secondProduct); + $this->_em->persist($this->firstCart); + $this->_em->persist($this->secondCart); + + $this->_em->flush(); + $this->_em->clear(); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/MappedSuperclassTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/MappedSuperclassTest.php new file mode 100644 index 0000000..f4439b9 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/MappedSuperclassTest.php @@ -0,0 +1,47 @@ +useModelSet('directorytree'); + parent::setUp(); + } + + public function testCRUD() + { + $root = new \Doctrine\Tests\Models\DirectoryTree\Directory(); + $root->setName('Root'); + $root->setPath('/root'); + + $directory = new \Doctrine\Tests\Models\DirectoryTree\Directory($root); + $directory->setName('TestA'); + $directory->setPath('/root/dir'); + + $file = new \Doctrine\Tests\Models\DirectoryTree\File($directory); + $file->setName('test-b.html'); + + $this->_em->persist($root); + $this->_em->persist($directory); + $this->_em->persist($file); + + $this->_em->flush(); + $this->_em->clear(); + + $cleanFile = $this->_em->find(get_class($file), $file->getId()); + + $this->assertInstanceOf('Doctrine\Tests\Models\DirectoryTree\Directory', $cleanFile->getParent()); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $cleanFile->getParent()); + $this->assertEquals($directory->getId(), $cleanFile->getParent()->getId()); + $this->assertInstanceOf('Doctrine\Tests\Models\DirectoryTree\Directory', $cleanFile->getParent()->getParent()); + $this->assertEquals($root->getId(), $cleanFile->getParent()->getParent()->getId()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php new file mode 100644 index 0000000..3436a74 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php @@ -0,0 +1,712 @@ +useModelSet('cms'); + $this->useModelSet('company'); + parent::setUp(); + $this->platform = $this->_em->getConnection()->getDatabasePlatform(); + } + + public function testBasicNativeQuery() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'dev'; + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id'); + $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('name'), 'name'); + + $query = $this->_em->createNativeQuery('SELECT id, name FROM cms_users WHERE username = ?', $rsm); + $query->setParameter(1, 'romanb'); + + $users = $query->getResult(); + + $this->assertEquals(1, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); + $this->assertEquals('Roman', $users[0]->name); + } + + public function testBasicNativeQueryWithMetaResult() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'dev'; + + $addr = new CmsAddress; + $addr->country = 'germany'; + $addr->zip = 10827; + $addr->city = 'Berlin'; + + + $user->setAddress($addr); + + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsAddress', 'a'); + $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('id'), 'id'); + $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('country'), 'country'); + $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('zip'), 'zip'); + $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('city'), 'city'); + $rsm->addMetaResult('a', $this->platform->getSQLResultCasing('user_id'), 'user_id'); + + $query = $this->_em->createNativeQuery('SELECT a.id, a.country, a.zip, a.city, a.user_id FROM cms_addresses a WHERE a.id = ?', $rsm); + $query->setParameter(1, $addr->id); + + $addresses = $query->getResult(); + + $this->assertEquals(1, count($addresses)); + $this->assertTrue($addresses[0] instanceof CmsAddress); + $this->assertEquals($addr->country, $addresses[0]->country); + $this->assertEquals($addr->zip, $addresses[0]->zip); + $this->assertEquals($addr->city, $addresses[0]->city); + $this->assertEquals($addr->street, $addresses[0]->street); + $this->assertTrue($addresses[0]->user instanceof CmsUser); + } + + public function testJoinedOneToManyNativeQuery() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'dev'; + + $phone = new CmsPhonenumber; + $phone->phonenumber = 424242; + + $user->addPhonenumber($phone); + + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id'); + $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('name'), 'name'); + $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('status'), 'status'); + $rsm->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p', 'u', 'phonenumbers'); + $rsm->addFieldResult('p', $this->platform->getSQLResultCasing('phonenumber'), 'phonenumber'); + + $query = $this->_em->createNativeQuery('SELECT id, name, status, phonenumber FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?', $rsm); + $query->setParameter(1, 'romanb'); + + $users = $query->getResult(); + $this->assertEquals(1, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); + $this->assertEquals('Roman', $users[0]->name); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $users[0]->getPhonenumbers()); + $this->assertTrue($users[0]->getPhonenumbers()->isInitialized()); + $this->assertEquals(1, count($users[0]->getPhonenumbers())); + $phones = $users[0]->getPhonenumbers(); + $this->assertEquals(424242, $phones[0]->phonenumber); + $this->assertTrue($phones[0]->getUser() === $users[0]); + + } + + public function testJoinedOneToOneNativeQuery() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'dev'; + + $addr = new CmsAddress; + $addr->country = 'germany'; + $addr->zip = 10827; + $addr->city = 'Berlin'; + + + $user->setAddress($addr); + + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id'); + $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('name'), 'name'); + $rsm->addFieldResult('u', $this->platform->getSQLResultCasing('status'), 'status'); + $rsm->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsAddress', 'a', 'u', 'address'); + $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('a_id'), 'id'); + $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('country'), 'country'); + $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('zip'), 'zip'); + $rsm->addFieldResult('a', $this->platform->getSQLResultCasing('city'), 'city'); + + $query = $this->_em->createNativeQuery('SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm); + $query->setParameter(1, 'romanb'); + + $users = $query->getResult(); + + $this->assertEquals(1, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); + $this->assertEquals('Roman', $users[0]->name); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $users[0]->getPhonenumbers()); + $this->assertFalse($users[0]->getPhonenumbers()->isInitialized()); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $users[0]->getAddress()); + $this->assertTrue($users[0]->getAddress()->getUser() == $users[0]); + $this->assertEquals('germany', $users[0]->getAddress()->getCountry()); + $this->assertEquals(10827, $users[0]->getAddress()->getZipCode()); + $this->assertEquals('Berlin', $users[0]->getAddress()->getCity()); + } + + public function testFluentInterface() + { + $parameters = new ArrayCollection; + $parameters->add(new Parameter(1, 'foo')); + $parameters->add(new Parameter(2, 'bar')); + + $rsm = new ResultSetMapping; + + $q = $this->_em->createNativeQuery('SELECT id, name, status, phonenumber FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?', $rsm); + $q2 = $q->setSql('foo', $rsm) + ->setResultSetMapping($rsm) + ->expireResultCache(true) + ->setHint('foo', 'bar') + ->setParameter(1, 'foo') + ->setParameters($parameters) + ->setResultCacheDriver(null) + ->setResultCacheLifetime(3500); + + $this->assertSame($q, $q2); + } + + public function testJoinedOneToManyNativeQueryWithRSMBuilder() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'dev'; + + $phone = new CmsPhonenumber; + $phone->phonenumber = 424242; + + $user->addPhonenumber($phone); + + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + $rsm = new ResultSetMappingBuilder($this->_em); + $rsm->addRootEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p', 'u', 'phonenumbers'); + $query = $this->_em->createNativeQuery('SELECT u.*, p.* FROM cms_users u LEFT JOIN cms_phonenumbers p ON u.id = p.user_id WHERE username = ?', $rsm); + $query->setParameter(1, 'romanb'); + + $users = $query->getResult(); + $this->assertEquals(1, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); + $this->assertEquals('Roman', $users[0]->name); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $users[0]->getPhonenumbers()); + $this->assertTrue($users[0]->getPhonenumbers()->isInitialized()); + $this->assertEquals(1, count($users[0]->getPhonenumbers())); + $phones = $users[0]->getPhonenumbers(); + $this->assertEquals(424242, $phones[0]->phonenumber); + $this->assertTrue($phones[0]->getUser() === $users[0]); + + $this->_em->clear(); + + $rsm = new ResultSetMappingBuilder($this->_em); + $rsm->addRootEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p'); + $query = $this->_em->createNativeQuery('SELECT p.* FROM cms_phonenumbers p WHERE p.phonenumber = ?', $rsm); + $query->setParameter(1, $phone->phonenumber); + $phone = $query->getSingleResult(); + + $this->assertNotNull($phone->getUser()); + $this->assertEquals($user->name, $phone->getUser()->getName()); + } + + public function testJoinedOneToOneNativeQueryWithRSMBuilder() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'dev'; + + $addr = new CmsAddress; + $addr->country = 'germany'; + $addr->zip = 10827; + $addr->city = 'Berlin'; + + + $user->setAddress($addr); + + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + + $rsm = new ResultSetMappingBuilder($this->_em); + $rsm->addRootEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', 'a', 'u', 'address', array('id' => 'a_id')); + + $query = $this->_em->createNativeQuery('SELECT u.*, a.*, a.id AS a_id FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm); + $query->setParameter(1, 'romanb'); + + $users = $query->getResult(); + + $this->assertEquals(1, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); + $this->assertEquals('Roman', $users[0]->name); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $users[0]->getPhonenumbers()); + $this->assertFalse($users[0]->getPhonenumbers()->isInitialized()); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $users[0]->getAddress()); + $this->assertTrue($users[0]->getAddress()->getUser() == $users[0]); + $this->assertEquals('germany', $users[0]->getAddress()->getCountry()); + $this->assertEquals(10827, $users[0]->getAddress()->getZipCode()); + $this->assertEquals('Berlin', $users[0]->getAddress()->getCity()); + + $this->_em->clear(); + + $rsm = new ResultSetMappingBuilder($this->_em); + $rsm->addRootEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', 'a'); + $query = $this->_em->createNativeQuery('SELECT a.* FROM cms_addresses a WHERE a.id = ?', $rsm); + $query->setParameter(1, $addr->getId()); + $address = $query->getSingleResult(); + + $this->assertNotNull($address->getUser()); + $this->assertEquals($user->name, $address->getUser()->getName()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testRSMBuilderThrowsExceptionOnColumnConflict() + { + $rsm = new ResultSetMappingBuilder($this->_em); + $rsm->addRootEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', 'a', 'u', 'address'); + } + + /** + * @group PR-39 + */ + public function testUnknownParentAliasThrowsException() + { + $rsm = new ResultSetMappingBuilder($this->_em); + $rsm->addRootEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityFromClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', 'a', 'un', 'address', array('id' => 'a_id')); + + $query = $this->_em->createNativeQuery('SELECT u.*, a.*, a.id AS a_id FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm); + $query->setParameter(1, 'romanb'); + + $this->setExpectedException( + "Doctrine\ORM\Internal\Hydration\HydrationException", + "The parent object of entity result with alias 'a' was not found. The parent alias is 'un'." + ); + $users = $query->getResult(); + } + + + /** + * @group DDC-1663 + */ + public function testBasicNativeNamedQueryWithSqlResultSetMapping() + { + $user = new CmsUser; + $user->name = 'Fabio B. Silva'; + $user->username = 'FabioBatSilva'; + $user->status = 'dev'; + + $addr = new CmsAddress; + $addr->country = 'Brazil'; + $addr->zip = 10827; + $addr->city = 'São Paulo'; + + $user->setAddress($addr); + + $this->_em->clear(); + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $query = $repository->createNativeNamedQuery('find-all'); + $result = $query->getResult(); + + $this->assertCount(1, $result); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $result[0]); + $this->assertEquals($addr->id, $result[0]->id); + $this->assertEquals($addr->city, $result[0]->city); + $this->assertEquals($addr->country, $result[0]->country); + } + + /** + * @group DDC-1663 + */ + public function testBasicNativeNamedQueryWithResultClass() + { + $user = new CmsUser; + $user->name = 'Fabio B. Silva'; + $user->username = 'FabioBatSilva'; + $user->status = 'dev'; + + $email = new CmsEmail(); + $email->email = 'fabio.bat.silva@gmail.com'; + + $user->setEmail($email); + + $this->_em->clear(); + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + + $result = $repository->createNativeNamedQuery('fetchIdAndUsernameWithResultClass') + ->setParameter(1, 'FabioBatSilva')->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertNull($result[0]->name); + $this->assertNull($result[0]->email); + $this->assertEquals($user->id, $result[0]->id); + $this->assertEquals('FabioBatSilva', $result[0]->username); + + $this->_em->clear(); + + + $result = $repository->createNativeNamedQuery('fetchAllColumns') + ->setParameter(1, 'FabioBatSilva')->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertEquals($user->id, $result[0]->id); + $this->assertEquals('Fabio B. Silva', $result[0]->name); + $this->assertEquals('FabioBatSilva', $result[0]->username); + $this->assertEquals('dev', $result[0]->status); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsEmail', $result[0]->email); + } + + + /** + * @group DDC-1663 + */ + public function testJoinedOneToOneNativeNamedQueryWithResultSetMapping() + { + $user = new CmsUser; + $user->name = 'Fabio B. Silva'; + $user->username = 'FabioBatSilva'; + $user->status = 'dev'; + + $addr = new CmsAddress; + $addr->country = 'Brazil'; + $addr->zip = 10827; + $addr->city = 'São Paulo'; + + + $user->setAddress($addr); + + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + + $result = $repository->createNativeNamedQuery('fetchJoinedAddress') + ->setParameter(1, 'FabioBatSilva')->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertEquals('Fabio B. Silva', $result[0]->name); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0]->getPhonenumbers()); + $this->assertFalse($result[0]->getPhonenumbers()->isInitialized()); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $result[0]->getAddress()); + $this->assertTrue($result[0]->getAddress()->getUser() == $result[0]); + $this->assertEquals('Brazil', $result[0]->getAddress()->getCountry()); + $this->assertEquals(10827, $result[0]->getAddress()->getZipCode()); + $this->assertEquals('São Paulo', $result[0]->getAddress()->getCity()); + } + + /** + * @group DDC-1663 + */ + public function testJoinedOneToManyNativeNamedQueryWithResultSetMapping() + { + $user = new CmsUser; + $user->name = 'Fabio B. Silva'; + $user->username = 'FabioBatSilva'; + $user->status = 'dev'; + + $phone = new CmsPhonenumber; + $phone->phonenumber = 424242; + + $user->addPhonenumber($phone); + + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $result = $repository->createNativeNamedQuery('fetchJoinedPhonenumber') + ->setParameter(1, 'FabioBatSilva')->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertEquals('Fabio B. Silva', $result[0]->name); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0]->getPhonenumbers()); + $this->assertTrue($result[0]->getPhonenumbers()->isInitialized()); + $this->assertEquals(1, count($result[0]->getPhonenumbers())); + $phones = $result[0]->getPhonenumbers(); + $this->assertEquals(424242, $phones[0]->phonenumber); + $this->assertTrue($phones[0]->getUser() === $result[0]); + } + + /** + * @group DDC-1663 + */ + public function testMixedNativeNamedQueryNormalJoin() + { + $user1 = new CmsUser; + $user1->name = 'Fabio B. Silva'; + $user1->username = 'FabioBatSilva'; + $user1->status = 'dev'; + + $user2 = new CmsUser; + $user2->name = 'test tester'; + $user2->username = 'test'; + $user2->status = 'tester'; + + $phone1 = new CmsPhonenumber; + $phone2 = new CmsPhonenumber; + $phone3 = new CmsPhonenumber; + $phone1->phonenumber = 11111111; + $phone2->phonenumber = 22222222; + $phone3->phonenumber = 33333333; + + $user1->addPhonenumber($phone1); + $user1->addPhonenumber($phone2); + $user2->addPhonenumber($phone3); + + $this->_em->persist($user1); + $this->_em->persist($user2); + $this->_em->flush(); + + $this->_em->clear(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $result = $repository->createNativeNamedQuery('fetchUserPhonenumberCount') + ->setParameter(1, array('test','FabioBatSilva'))->getResult(); + + $this->assertEquals(2, count($result)); + $this->assertTrue(is_array($result[0])); + $this->assertTrue(is_array($result[1])); + + // first user => 2 phonenumbers + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][0]); + $this->assertEquals('Fabio B. Silva', $result[0][0]->name); + $this->assertEquals(2, $result[0]['numphones']); + + // second user => 1 phonenumbers + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1][0]); + $this->assertEquals('test tester', $result[1][0]->name); + $this->assertEquals(1, $result[1]['numphones']); + } + + /** + * @group DDC-1663 + */ + public function testNativeNamedQueryInheritance() + { + $person = new CompanyPerson; + $person->setName('Fabio B. Silva'); + + $employee = new CompanyEmployee; + $employee->setName('Fabio Silva'); + $employee->setSalary(100000); + $employee->setDepartment('IT'); + + $this->_em->persist($person); + $this->_em->persist($employee); + + $this->_em->flush(); + $this->_em->clear(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyPerson'); + + $result = $repository->createNativeNamedQuery('fetchAllWithSqlResultSetMapping') + ->getResult(); + + $this->assertEquals(2, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyPerson', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result[1]); + $this->assertTrue(is_numeric($result[0]->getId())); + $this->assertTrue(is_numeric($result[1]->getId())); + $this->assertEquals('Fabio B. Silva', $result[0]->getName()); + $this->assertEquals('Fabio Silva', $result[1]->getName()); + + + $this->_em->clear(); + + + $result = $repository->createNativeNamedQuery('fetchAllWithResultClass') + ->getResult(); + + $this->assertEquals(2, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyPerson', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result[1]); + $this->assertTrue(is_numeric($result[0]->getId())); + $this->assertTrue(is_numeric($result[1]->getId())); + $this->assertEquals('Fabio B. Silva', $result[0]->getName()); + $this->assertEquals('Fabio Silva', $result[1]->getName()); + } + + /** + * @group DDC-1663 + * DQL : SELECT u, a, COUNT(p) AS numphones FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.address a JOIN u.phonenumbers p + */ + public function testMultipleEntityResults() + { + + $user = new CmsUser; + $user->name = 'Fabio B. Silva'; + $user->username = 'FabioBatSilva'; + $user->status = 'dev'; + + $addr = new CmsAddress; + $addr->country = 'Brazil'; + $addr->zip = 10827; + $addr->city = 'São Paulo'; + + $phone = new CmsPhonenumber; + $phone->phonenumber = 424242; + + + $user->setAddress($addr); + $user->addPhonenumber($phone); + + + $this->_em->clear(); + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $query = $repository->createNativeNamedQuery('fetchMultipleJoinsEntityResults'); + $result = $query->getResult(); + + + $this->assertEquals(1, count($result)); + $this->assertTrue(is_array($result[0])); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][0]); + $this->assertEquals('Fabio B. Silva', $result[0][0]->name); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $result[0][0]->getAddress()); + $this->assertTrue($result[0][0]->getAddress()->getUser() == $result[0][0]); + $this->assertEquals('Brazil', $result[0][0]->getAddress()->getCountry()); + $this->assertEquals(10827, $result[0][0]->getAddress()->getZipCode()); + + $this->assertEquals(1, $result[0]['numphones']); + + } + + /** + * @group DDC-1663 + */ + public function testNamedNativeQueryInheritance() + { + $contractMetadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyContract'); + $flexMetadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyFlexContract'); + + $contractQueries = $contractMetadata->getNamedNativeQueries(); + $flexQueries = $flexMetadata->getNamedNativeQueries(); + + $contractMappings = $contractMetadata->getSqlResultSetMappings(); + $flexMappings = $flexMetadata->getSqlResultSetMappings(); + + + // contract queries + $this->assertEquals('all-contracts', $contractQueries['all-contracts']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyContract', $contractQueries['all-contracts']['resultClass']); + + $this->assertEquals('all', $contractQueries['all']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyContract', $contractQueries['all']['resultClass']); + + + // flex contract queries + $this->assertEquals('all-contracts', $flexQueries['all-contracts']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexQueries['all-contracts']['resultClass']); + + $this->assertEquals('all-flex', $flexQueries['all-flex']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexQueries['all-flex']['resultClass']); + + $this->assertEquals('all', $flexQueries['all']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexQueries['all']['resultClass']); + + + // contract result mapping + $this->assertEquals('mapping-all-contracts', $contractMappings['mapping-all-contracts']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyContract', $contractMappings['mapping-all-contracts']['entities'][0]['entityClass']); + + $this->assertEquals('mapping-all', $contractMappings['mapping-all']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyContract', $contractMappings['mapping-all-contracts']['entities'][0]['entityClass']); + + // flex contract result mapping + $this->assertEquals('mapping-all-contracts', $flexMappings['mapping-all-contracts']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexMappings['mapping-all-contracts']['entities'][0]['entityClass']); + + $this->assertEquals('mapping-all', $flexMappings['mapping-all']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexMappings['mapping-all']['entities'][0]['entityClass']); + + $this->assertEquals('mapping-all-flex', $flexMappings['mapping-all-flex']['name']); + $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexContract', $flexMappings['mapping-all-flex']['entities'][0]['entityClass']); + + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/NotifyPolicyTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/NotifyPolicyTest.php new file mode 100644 index 0000000..069e11c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/NotifyPolicyTest.php @@ -0,0 +1,173 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\NotifyUser'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\NotifyGroup') + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + + public function testChangeTracking() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $user = new NotifyUser(); + $group = new NotifyGroup(); + $user->setName('roman'); + $group->setName('dev'); + + $user->getGroups()->add($group); + $group->getUsers()->add($user); + + $this->_em->persist($user); + $this->_em->persist($group); + + $this->assertEquals(1, count($user->listeners)); + $this->assertEquals(1, count($group->listeners)); + + $this->_em->flush(); + $this->_em->clear(); + + $this->assertEquals(1, count($user->listeners)); + $this->assertEquals(1, count($group->listeners)); + + $userId = $user->getId(); + $groupId = $group->getId(); + unset($user, $group); + + $user = $this->_em->find(__NAMESPACE__.'\NotifyUser', $userId); + $this->assertEquals(1, $user->getGroups()->count()); + $group = $this->_em->find(__NAMESPACE__.'\NotifyGroup', $groupId); + $this->assertEquals(1, $group->getUsers()->count()); + + $this->assertEquals(1, count($user->listeners)); + $this->assertEquals(1, count($group->listeners)); + + $group2 = new NotifyGroup(); + $group2->setName('nerds'); + $this->_em->persist($group2); + $user->getGroups()->add($group2); + $group2->getUsers()->add($user); + + $group->setName('geeks'); + + $this->_em->flush(); + $this->_em->clear(); + + $this->assertEquals(1, count($user->listeners)); + $this->assertEquals(1, count($group->listeners)); + + $group2Id = $group2->getId(); + unset($group2, $user); + + $user = $this->_em->find(__NAMESPACE__.'\NotifyUser', $userId); + $this->assertEquals(2, $user->getGroups()->count()); + $group2 = $this->_em->find(__NAMESPACE__.'\NotifyGroup', $group2Id); + $this->assertEquals(1, $group2->getUsers()->count()); + $group = $this->_em->find(__NAMESPACE__.'\NotifyGroup', $groupId); + $this->assertEquals(1, $group->getUsers()->count()); + $this->assertEquals('geeks', $group->getName()); + } +} + +class NotifyBaseEntity implements NotifyPropertyChanged { + public $listeners = array(); + + public function addPropertyChangedListener(PropertyChangedListener $listener) { + $this->listeners[] = $listener; + } + + protected function onPropertyChanged($propName, $oldValue, $newValue) { + if ($this->listeners) { + foreach ($this->listeners as $listener) { + $listener->propertyChanged($this, $propName, $oldValue, $newValue); + } + } + } +} + +/** @Entity @ChangeTrackingPolicy("NOTIFY") */ +class NotifyUser extends NotifyBaseEntity { + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; + + /** @Column */ + private $name; + + /** @ManyToMany(targetEntity="NotifyGroup") */ + private $groups; + + function __construct() { + $this->groups = new ArrayCollection; + } + + function getId() { + return $this->id; + } + + function getName() { + return $this->name; + } + + function setName($name) { + $this->onPropertyChanged('name', $this->name, $name); + $this->name = $name; + } + + function getGroups() { + return $this->groups; + } +} + +/** @Entity */ +class NotifyGroup extends NotifyBaseEntity { + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; + + /** @Column */ + private $name; + + /** @ManyToMany(targetEntity="NotifyUser", mappedBy="groups") */ + private $users; + + function __construct() { + $this->users = new ArrayCollection; + } + + function getId() { + return $this->id; + } + + function getName() { + return $this->name; + } + + function setName($name) { + $this->onPropertyChanged('name', $this->name, $name); + $this->name = $name; + } + + function getUsers() { + return $this->users; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyBidirectionalAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyBidirectionalAssociationTest.php new file mode 100644 index 0000000..75d9d2a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyBidirectionalAssociationTest.php @@ -0,0 +1,218 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->product = new ECommerceProduct(); + $this->product->setName('Doctrine Cookbook'); + $this->firstFeature = new ECommerceFeature(); + $this->firstFeature->setDescription('Model writing tutorial'); + $this->secondFeature = new ECommerceFeature(); + $this->secondFeature->setDescription('Annotations examples'); + } + + public function testSavesAOneToManyAssociationWithCascadeSaveSet() { + $this->product->addFeature($this->firstFeature); + $this->product->addFeature($this->secondFeature); + $this->_em->persist($this->product); + $this->_em->flush(); + + $this->assertFeatureForeignKeyIs($this->product->getId(), $this->firstFeature); + $this->assertFeatureForeignKeyIs($this->product->getId(), $this->secondFeature); + } + + public function testSavesAnEmptyCollection() + { + $this->_em->persist($this->product); + $this->_em->flush(); + + $this->assertEquals(0, count($this->product->getFeatures())); + } + + public function testDoesNotSaveAnInverseSideSet() { + $this->product->brokenAddFeature($this->firstFeature); + $this->_em->persist($this->product); + $this->_em->flush(); + + $this->assertFeatureForeignKeyIs(null, $this->firstFeature); + } + + public function testRemovesOneToOneAssociation() + { + $this->product->addFeature($this->firstFeature); + $this->product->addFeature($this->secondFeature); + $this->_em->persist($this->product); + + $this->product->removeFeature($this->firstFeature); + $this->_em->flush(); + + $this->assertFeatureForeignKeyIs(null, $this->firstFeature); + $this->assertFeatureForeignKeyIs($this->product->getId(), $this->secondFeature); + } + + public function testEagerLoadsOneToManyAssociation() + { + $this->_createFixture(); + $query = $this->_em->createQuery('select p, f from Doctrine\Tests\Models\ECommerce\ECommerceProduct p join p.features f'); + $result = $query->getResult(); + $product = $result[0]; + + $features = $product->getFeatures(); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $features[0]); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $features[0]->getProduct()); + $this->assertSame($product, $features[0]->getProduct()); + $this->assertEquals('Model writing tutorial', $features[0]->getDescription()); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $features[1]); + $this->assertSame($product, $features[1]->getProduct()); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $features[1]->getProduct()); + $this->assertEquals('Annotations examples', $features[1]->getDescription()); + } + + public function testLazyLoadsObjectsOnTheOwningSide() + { + $this->_createFixture(); + + $query = $this->_em->createQuery('select p from Doctrine\Tests\Models\ECommerce\ECommerceProduct p'); + $result = $query->getResult(); + $product = $result[0]; + $features = $product->getFeatures(); + + $this->assertFalse($features->isInitialized()); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $features[0]); + $this->assertTrue($features->isInitialized()); + $this->assertSame($product, $features[0]->getProduct()); + $this->assertEquals('Model writing tutorial', $features[0]->getDescription()); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $features[1]); + $this->assertSame($product, $features[1]->getProduct()); + $this->assertEquals('Annotations examples', $features[1]->getDescription()); + } + + public function testLazyLoadsObjectsOnTheInverseSide() + { + $this->_createFixture(); + + $query = $this->_em->createQuery('select f from Doctrine\Tests\Models\ECommerce\ECommerceFeature f'); + $features = $query->getResult(); + + $product = $features[0]->getProduct(); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $product); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $product); + $this->assertFalse($product->__isInitialized__); + $this->assertSame('Doctrine Cookbook', $product->getName()); + $this->assertTrue($product->__isInitialized__); + } + + public function testLazyLoadsObjectsOnTheInverseSide2() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_createFixture(); + + $query = $this->_em->createQuery('select f,p from Doctrine\Tests\Models\ECommerce\ECommerceFeature f join f.product p'); + $features = $query->getResult(); + + $product = $features[0]->getProduct(); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $product); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $product); + $this->assertSame('Doctrine Cookbook', $product->getName()); + + $this->assertFalse($product->getFeatures()->isInitialized()); + + // This would trigger lazy-load + //$this->assertEquals(2, $product->getFeatures()->count()); + //$this->assertTrue($product->getFeatures()->contains($features[0])); + //$this->assertTrue($product->getFeatures()->contains($features[1])); + + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(null); + } + + public function testJoinFromOwningSide() + { + $query = $this->_em->createQuery('select f,p from Doctrine\Tests\Models\ECommerce\ECommerceFeature f join f.product p'); + $features = $query->getResult(); + $this->assertEquals(0, count($features)); + } + + /** + * @group DDC-1637 + */ + public function testMatching() + { + $this->_createFixture(); + + $product = $this->_em->find('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $this->product->getId()); + $features = $product->getFeatures(); + + $results = $features->matching(new Criteria( + Criteria::expr()->eq('description', 'Model writing tutorial') + )); + + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $results); + $this->assertEquals(1, count($results)); + + $results = $features->matching(new Criteria()); + + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $results); + $this->assertEquals(2, count($results)); + } + + public function testMatchingBis() + { + $this->_createFixture(); + + $product = $this->_em->find('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $this->product->getId()); + $features = $product->getFeatures(); + + $thirdFeature = new ECommerceFeature(); + $thirdFeature->setDescription('Third feature'); + $product->addFeature($thirdFeature); + + $results = $features->matching(new Criteria( + Criteria::expr()->eq('description', 'Third feature') + )); + + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $results); + $this->assertCount(1, $results); + + $results = $features->matching(new Criteria()); + + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $results); + $this->assertCount(3, $results); + } + + private function _createFixture() + { + $this->product->addFeature($this->firstFeature); + $this->product->addFeature($this->secondFeature); + $this->_em->persist($this->product); + + $this->_em->flush(); + $this->_em->clear(); + } + + public function assertFeatureForeignKeyIs($value, ECommerceFeature $feature) { + $foreignKey = $this->_em->getConnection()->executeQuery( + 'SELECT product_id FROM ecommerce_features WHERE id=?', + array($feature->getId()) + )->fetchColumn(); + $this->assertEquals($value, $foreignKey); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyOrphanRemovalTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyOrphanRemovalTest.php new file mode 100644 index 0000000..28101cc --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyOrphanRemovalTest.php @@ -0,0 +1,75 @@ +useModelSet('cms'); + + parent::setUp(); + + $user = new CmsUser; + $user->status = 'dev'; + $user->username = 'romanb'; + $user->name = 'Roman B.'; + + $phone = new CmsPhonenumber; + $phone->phonenumber = '123456'; + + $user->addPhonenumber($phone); + + $this->_em->persist($user); + $this->_em->flush(); + + $this->userId = $user->getId(); + $this->_em->clear(); + } + + public function testOrphanRemoval() + { + $userProxy = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + + $this->_em->remove($userProxy); + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u'); + $result = $query->getResult(); + + $this->assertEquals(0, count($result), 'CmsUser should be removed by EntityManager'); + + $query = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p'); + $result = $query->getResult(); + + $this->assertEquals(0, count($result), 'CmsPhonenumber should be removed by orphanRemoval'); + } + + /** + * @group DDC-1496 + */ + public function testOrphanRemovalUnitializedCollection() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + + $user->phonenumbers->clear(); + $this->_em->flush(); + + $query = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p'); + $result = $query->getResult(); + + $this->assertEquals(0, count($result), 'CmsPhonenumber should be removed by orphanRemoval'); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManySelfReferentialAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManySelfReferentialAssociationTest.php new file mode 100644 index 0000000..d162171 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManySelfReferentialAssociationTest.php @@ -0,0 +1,123 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->parent = new ECommerceCategory(); + $this->parent->setName('Programming languages books'); + $this->firstChild = new ECommerceCategory(); + $this->firstChild->setName('Java books'); + $this->secondChild = new ECommerceCategory(); + $this->secondChild->setName('Php books'); + } + + public function testSavesAOneToManyAssociationWithCascadeSaveSet() { + $this->parent->addChild($this->firstChild); + $this->parent->addChild($this->secondChild); + $this->_em->persist($this->parent); + + $this->_em->flush(); + + $this->assertForeignKeyIs($this->parent->getId(), $this->firstChild); + $this->assertForeignKeyIs($this->parent->getId(), $this->secondChild); + } + + public function testSavesAnEmptyCollection() + { + $this->_em->persist($this->parent); + $this->_em->flush(); + + $this->assertEquals(0, count($this->parent->getChildren())); + } + + public function testDoesNotSaveAnInverseSideSet() { + $this->parent->brokenAddChild($this->firstChild); + $this->_em->persist($this->parent); + $this->_em->flush(); + + $this->assertForeignKeyIs(null, $this->firstChild); + } + + public function testRemovesOneToManyAssociation() + { + $this->parent->addChild($this->firstChild); + $this->parent->addChild($this->secondChild); + $this->_em->persist($this->parent); + + $this->parent->removeChild($this->firstChild); + $this->_em->flush(); + + $this->assertForeignKeyIs(null, $this->firstChild); + $this->assertForeignKeyIs($this->parent->getId(), $this->secondChild); + } + + public function testEagerLoadsOneToManyAssociation() + { + $this->_createFixture(); + + $query = $this->_em->createQuery('select c1, c2 from Doctrine\Tests\Models\ECommerce\ECommerceCategory c1 join c1.children c2'); + $result = $query->getResult(); + $this->assertEquals(1, count($result)); + $parent = $result[0]; + $children = $parent->getChildren(); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $children[0]); + $this->assertSame($parent, $children[0]->getParent()); + $this->assertEquals(' books', strstr($children[0]->getName(), ' books')); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $children[1]); + $this->assertSame($parent, $children[1]->getParent()); + $this->assertEquals(' books', strstr($children[1]->getName(), ' books')); + } + + public function testLazyLoadsOneToManyAssociation() + { + $this->_createFixture(); + $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCategory'); + $metadata->associationMappings['children']['fetch'] = ClassMetadata::FETCH_LAZY; + + $query = $this->_em->createQuery('select c from Doctrine\Tests\Models\ECommerce\ECommerceCategory c order by c.id asc'); + $result = $query->getResult(); + $parent = $result[0]; + $children = $parent->getChildren(); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $children[0]); + $this->assertSame($parent, $children[0]->getParent()); + $this->assertEquals(' books', strstr($children[0]->getName(), ' books')); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCategory', $children[1]); + $this->assertSame($parent, $children[1]->getParent()); + $this->assertEquals(' books', strstr($children[1]->getName(), ' books')); + } + + private function _createFixture() + { + $this->parent->addChild($this->firstChild); + $this->parent->addChild($this->secondChild); + $this->_em->persist($this->parent); + + $this->_em->flush(); + $this->_em->clear(); + } + + public function assertForeignKeyIs($value, ECommerceCategory $child) { + $foreignKey = $this->_em->getConnection()->executeQuery('SELECT parent_id FROM ecommerce_categories WHERE id=?', array($child->getId()))->fetchColumn(); + $this->assertEquals($value, $foreignKey); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyUnidirectionalAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyUnidirectionalAssociationTest.php new file mode 100644 index 0000000..42fd292 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToManyUnidirectionalAssociationTest.php @@ -0,0 +1,86 @@ +useModelSet('routing'); + parent::setUp(); + + $locations = array("Berlin", "Bonn", "Brasilia", "Atlanta"); + + foreach ($locations AS $locationName) { + $location = new RoutingLocation(); + $location->name = $locationName; + $this->_em->persist($location); + $this->locations[$locationName] = $location; + } + $this->_em->flush(); + } + + public function testPersistOwning_InverseCascade() + { + $leg = new RoutingLeg(); + $leg->fromLocation = $this->locations['Berlin']; + $leg->toLocation = $this->locations['Bonn']; + $leg->departureDate = new \DateTime("now"); + $leg->arrivalDate = new \DateTime("now +5 hours"); + + $route = new RoutingRoute(); + $route->legs[] = $leg; + + $this->_em->persist($route); + $this->_em->flush(); + $this->_em->clear(); + + $routes = $this->_em->createQuery( + "SELECT r, l, f, t FROM Doctrine\Tests\Models\Routing\RoutingRoute r ". + "JOIN r.legs l JOIN l.fromLocation f JOIN l.toLocation t" + )->getSingleResult(); + + $this->assertEquals(1, count($routes->legs)); + $this->assertEquals("Berlin", $routes->legs[0]->fromLocation->name); + $this->assertEquals("Bonn", $routes->legs[0]->toLocation->name); + } + + public function testLegsAreUniqueToRoutes() + { + $leg = new RoutingLeg(); + $leg->fromLocation = $this->locations['Berlin']; + $leg->toLocation = $this->locations['Bonn']; + $leg->departureDate = new \DateTime("now"); + $leg->arrivalDate = new \DateTime("now +5 hours"); + + $routeA = new RoutingRoute(); + $routeA->legs[] = $leg; + + $routeB = new RoutingRoute(); + $routeB->legs[] = $leg; + + $this->_em->persist($routeA); + $this->_em->persist($routeB); + + $exceptionThrown = false; + try { + // exception depending on the underyling Database Driver + $this->_em->flush(); + } catch(\Exception $e) { + $exceptionThrown = true; + } + + $this->assertTrue($exceptionThrown, "The underlying database driver throws an exception."); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneBidirectionalAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneBidirectionalAssociationTest.php new file mode 100644 index 0000000..ced524c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneBidirectionalAssociationTest.php @@ -0,0 +1,151 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->customer = new ECommerceCustomer(); + $this->customer->setName('John Doe'); + $this->cart = new ECommerceCart(); + $this->cart->setPayment('Credit card'); + } + + public function testSavesAOneToOneAssociationWithCascadeSaveSet() { + $this->customer->setCart($this->cart); + $this->_em->persist($this->customer); + $this->_em->flush(); + + $this->assertCartForeignKeyIs($this->customer->getId()); + } + + public function testDoesNotSaveAnInverseSideSet() { + $this->customer->brokenSetCart($this->cart); + $this->_em->persist($this->customer); + $this->_em->flush(); + + $this->assertCartForeignKeyIs(null); + } + + public function testRemovesOneToOneAssociation() + { + $this->customer->setCart($this->cart); + $this->_em->persist($this->customer); + $this->customer->removeCart(); + + $this->_em->flush(); + + $this->assertCartForeignKeyIs(null); + } + + public function testEagerLoad() + { + $this->_createFixture(); + + $query = $this->_em->createQuery('select c, ca from Doctrine\Tests\Models\ECommerce\ECommerceCustomer c join c.cart ca'); + $result = $query->getResult(); + $customer = $result[0]; + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCart', $customer->getCart()); + $this->assertEquals('paypal', $customer->getCart()->getPayment()); + } + + public function testLazyLoadsObjectsOnTheOwningSide() { + $this->_createFixture(); + $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCart'); + $metadata->associationMappings['customer']['fetchMode'] = ClassMetadata::FETCH_LAZY; + + $query = $this->_em->createQuery('select c from Doctrine\Tests\Models\ECommerce\ECommerceCart c'); + $result = $query->getResult(); + $cart = $result[0]; + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCustomer', $cart->getCustomer()); + $this->assertEquals('Giorgio', $cart->getCustomer()->getName()); + } + + public function testInverseSideIsNeverLazy() + { + $this->_createFixture(); + $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCustomer'); + $metadata->associationMappings['mentor']['fetch'] = ClassMetadata::FETCH_EAGER; + + $query = $this->_em->createQuery('select c from Doctrine\Tests\Models\ECommerce\ECommerceCustomer c'); + $result = $query->getResult(); + $customer = $result[0]; + + $this->assertNull($customer->getMentor()); + $this->assertInstanceOF('Doctrine\Tests\Models\ECommerce\ECommerceCart', $customer->getCart()); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $customer->getCart()); + $this->assertEquals('paypal', $customer->getCart()->getPayment()); + } + + public function testUpdateWithProxyObject() + { + $cust = new ECommerceCustomer; + $cust->setName('Roman'); + $cart = new ECommerceCart; + $cart->setPayment('CARD'); + $cust->setCart($cart); + + $this->_em->persist($cust); + $this->_em->flush(); + $this->_em->clear(); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCart', $cust->getCart()); + $this->assertEquals('Roman', $cust->getName()); + $this->assertSame($cust, $cart->getCustomer()); + + $query = $this->_em->createQuery('select ca from Doctrine\Tests\Models\ECommerce\ECommerceCart ca where ca.id =?1'); + $query->setParameter(1, $cart->getId()); + + $cart2 = $query->getSingleResult(); + + $cart2->setPayment('CHEQUE'); + + $this->_em->flush(); + $this->_em->clear(); + + $query2 = $this->_em->createQuery('select ca, c from Doctrine\Tests\Models\ECommerce\ECommerceCart ca left join ca.customer c where ca.id =?1'); + $query2->setParameter(1, $cart->getId()); + + $cart3 = $query2->getSingleResult(); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCustomer', $cart3->getCustomer()); + $this->assertEquals('Roman', $cart3->getCustomer()->getName()); + } + + protected function _createFixture() + { + $customer = new ECommerceCustomer; + $customer->setName('Giorgio'); + $cart = new ECommerceCart; + $cart->setPayment('paypal'); + $customer->setCart($cart); + + $this->_em->persist($customer); + + $this->_em->flush(); + $this->_em->clear(); + } + + public function assertCartForeignKeyIs($value) { + $foreignKey = $this->_em->getConnection()->executeQuery('SELECT customer_id FROM ecommerce_carts WHERE id=?', array($this->cart->getId()))->fetchColumn(); + $this->assertEquals($value, $foreignKey); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneEagerLoadingTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneEagerLoadingTest.php new file mode 100644 index 0000000..7ad30ab --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneEagerLoadingTest.php @@ -0,0 +1,343 @@ +_em); + try { + $schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Train'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\TrainDriver'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\TrainOwner'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Waggon'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\TrainOrder'), + )); + } catch(\Exception $e) {} + } + + public function testEagerLoadOneToOneOwningSide() + { + $train = new Train(new TrainOwner("Alexander")); + $driver = new TrainDriver("Benjamin"); + $waggon = new Waggon(); + + $train->setDriver($driver); + $train->addWaggon($waggon); + + $this->_em->persist($train); // cascades + $this->_em->flush(); + $this->_em->clear(); + + $sqlCount = count($this->_sqlLoggerStack->queries); + + $train = $this->_em->find(get_class($train), $train->id); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $train->driver); + $this->assertEquals("Benjamin", $train->driver->name); + + $this->assertEquals($sqlCount + 1, count($this->_sqlLoggerStack->queries)); + } + + public function testEagerLoadOneToOneNullOwningSide() + { + $train = new Train(new TrainOwner("Alexander")); + + $this->_em->persist($train); // cascades + $this->_em->flush(); + $this->_em->clear(); + + $sqlCount = count($this->_sqlLoggerStack->queries); + + $train = $this->_em->find(get_class($train), $train->id); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $train->driver); + $this->assertNull($train->driver); + + $this->assertEquals($sqlCount + 1, count($this->_sqlLoggerStack->queries)); + } + + public function testEagerLoadOneToOneInverseSide() + { + $owner = new TrainOwner("Alexander"); + $train = new Train($owner); + + $this->_em->persist($train); // cascades + $this->_em->flush(); + $this->_em->clear(); + + $sqlCount = count($this->_sqlLoggerStack->queries); + + $driver = $this->_em->find(get_class($owner), $owner->id); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $owner->train); + $this->assertNotNull($owner->train); + + $this->assertEquals($sqlCount + 1, count($this->_sqlLoggerStack->queries)); + } + + public function testEagerLoadOneToOneNullInverseSide() + { + $driver = new TrainDriver("Dagny Taggert"); + + $this->_em->persist($driver); + $this->_em->flush(); + $this->_em->clear(); + + $this->assertNull($driver->train); + + $sqlCount = count($this->_sqlLoggerStack->queries); + + $driver = $this->_em->find(get_class($driver), $driver->id); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $driver->train); + $this->assertNull($driver->train); + + $this->assertEquals($sqlCount + 1, count($this->_sqlLoggerStack->queries)); + } + + public function testEagerLoadManyToOne() + { + $train = new Train(new TrainOwner("Alexander")); + $waggon = new Waggon(); + $train->addWaggon($waggon); + + $this->_em->persist($train); // cascades + $this->_em->flush(); + $this->_em->clear(); + + $waggon = $this->_em->find(get_class($waggon), $waggon->id); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $waggon->train); + $this->assertNotNull($waggon->train); + } + + public function testEagerLoadWithNullableColumnsGeneratesLeftJoinOnBothSides() + { + $train = new Train(new TrainOwner("Alexander")); + $driver = new TrainDriver("Benjamin"); + $train->setDriver($driver); + + $this->_em->persist($train); + $this->_em->flush(); + $this->_em->clear(); + + $train = $this->_em->find(get_class($train), $train->id); + $this->assertEquals( + "SELECT t0.id AS id1, t0.driver_id AS driver_id2, t3.id AS id4, t3.name AS name5, t0.owner_id AS owner_id6, t7.id AS id8, t7.name AS name9 FROM Train t0 LEFT JOIN TrainDriver t3 ON t0.driver_id = t3.id INNER JOIN TrainOwner t7 ON t0.owner_id = t7.id WHERE t0.id = ?", + $this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql'] + ); + + $this->_em->clear(); + $driver = $this->_em->find(get_class($driver), $driver->id); + $this->assertEquals( + "SELECT t0.id AS id1, t0.name AS name2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM TrainOwner t0 LEFT JOIN Train t3 ON t3.owner_id = t0.id WHERE t0.id IN (?)", + $this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql'] + ); + } + + public function testEagerLoadWithNonNullableColumnsGeneratesInnerJoinOnOwningSide() + { + $waggon = new Waggon(); + + // It should have a train + $train = new Train(new TrainOwner("Alexander")); + $train->addWaggon($waggon); + + $this->_em->persist($train); + $this->_em->flush(); + $this->_em->clear(); + + $waggon = $this->_em->find(get_class($waggon), $waggon->id); + + // The last query is the eager loading of the owner of the train + $this->assertEquals( + "SELECT t0.id AS id1, t0.name AS name2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM TrainOwner t0 LEFT JOIN Train t3 ON t3.owner_id = t0.id WHERE t0.id IN (?)", + $this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql'] + ); + + // The one before is the fetching of the waggon and train + $this->assertEquals( + "SELECT t0.id AS id1, t0.train_id AS train_id2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM Waggon t0 INNER JOIN Train t3 ON t0.train_id = t3.id WHERE t0.id = ?", + $this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery - 1]['sql'] + ); + } + + public function testEagerLoadWithNonNullableColumnsGeneratesLeftJoinOnNonOwningSide() + { + $owner = new TrainOwner('Alexander'); + $train = new Train($owner); + $this->_em->persist($train); + $this->_em->flush(); + $this->_em->clear(); + + $waggon = $this->_em->find(get_class($owner), $owner->id); + $this->assertEquals( + "SELECT t0.id AS id1, t0.name AS name2, t3.id AS id4, t3.driver_id AS driver_id5, t3.owner_id AS owner_id6 FROM TrainOwner t0 LEFT JOIN Train t3 ON t3.owner_id = t0.id WHERE t0.id = ?", + $this->_sqlLoggerStack->queries[$this->_sqlLoggerStack->currentQuery]['sql'] + ); + } + + /** + * @group DDC-1946 + */ + public function testEagerLoadingDoesNotBreakRefresh() + { + $train = new Train(new TrainOwner('Johannes')); + $order = new TrainOrder($train); + $this->_em->persist($train); + $this->_em->persist($order); + $this->_em->flush(); + + $this->_em->getConnection()->exec("UPDATE TrainOrder SET train_id = NULL"); + + $this->assertSame($train, $order->train); + $this->_em->refresh($order); + $this->assertTrue($order->train === null, "Train reference was not refreshed to NULL."); + } +} + +/** + * @Entity + */ +class Train +{ + /** + * @id @column(type="integer") @generatedValue + * @var int + */ + public $id; + /** + * Owning side + * @OneToOne(targetEntity="TrainDriver", inversedBy="train", fetch="EAGER", cascade={"persist"}) + * @JoinColumn(nullable=true) + */ + public $driver; + /** + * Owning side + * @OneToOne(targetEntity="TrainOwner", inversedBy="train", fetch="EAGER", cascade={"persist"}) + * @JoinColumn(nullable=false) + */ + public $owner; + /** + * @oneToMany(targetEntity="Waggon", mappedBy="train", cascade={"persist"}) + */ + public $waggons; + + public function __construct(TrainOwner $owner) + { + $this->waggons = new \Doctrine\Common\Collections\ArrayCollection(); + $this->setOwner($owner); + } + + public function setDriver(TrainDriver $driver) + { + $this->driver = $driver; + $driver->setTrain($this); + } + + public function setOwner(TrainOwner $owner) + { + $this->owner = $owner; + $owner->setTrain($this); + } + + public function addWaggon(Waggon $w) + { + $w->setTrain($this); + $this->waggons[] = $w; + } +} + +/** + * @Entity + */ +class TrainDriver +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @column(type="string") */ + public $name; + /** + * Inverse side + * @OneToOne(targetEntity="Train", mappedBy="driver", fetch="EAGER") + */ + public $train; + + public function __construct($name) + { + $this->name = $name; + } + + public function setTrain(Train $t) + { + $this->train = $t; + } +} + +/** + * @Entity + */ +class TrainOwner +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @column(type="string") */ + public $name; + /** + * Inverse side + * @OneToOne(targetEntity="Train", mappedBy="owner", fetch="EAGER") + */ + public $train; + + public function __construct($name) + { + $this->name = $name; + } + + public function setTrain(Train $t) + { + $this->train = $t; + } +} + +/** + * @Entity + */ +class Waggon +{ + /** @id @generatedValue @column(type="integer") */ + public $id; + /** + * @ManyToOne(targetEntity="Train", inversedBy="waggons", fetch="EAGER") + * @JoinColumn(nullable=false) + */ + public $train; + + public function setTrain($train) + { + $this->train = $train; + } +} + +/** + * @Entity + */ +class TrainOrder +{ + /** @id @generatedValue @column(type="integer") */ + public $id; + + /** @OneToOne(targetEntity = "Train", fetch = "EAGER") */ + public $train; + + public function __construct(Train $train) + { + $this->train = $train; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneOrphanRemovalTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneOrphanRemovalTest.php new file mode 100644 index 0000000..6b3d0a2 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneOrphanRemovalTest.php @@ -0,0 +1,94 @@ +useModelSet('cms'); + + parent::setUp(); + } + + public function testOrphanRemoval() + { + $user = new CmsUser; + $user->status = 'dev'; + $user->username = 'romanb'; + $user->name = 'Roman B.'; + + $address = new CmsAddress; + $address->country = 'de'; + $address->zip = 1234; + $address->city = 'Berlin'; + + $user->setAddress($address); + + $this->_em->persist($user); + $this->_em->flush(); + + $userId = $user->getId(); + + $this->_em->clear(); + + $userProxy = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $userId); + + $this->_em->remove($userProxy); + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u'); + $result = $query->getResult(); + + $this->assertEquals(0, count($result), 'CmsUser should be removed by EntityManager'); + + $query = $this->_em->createQuery('SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a'); + $result = $query->getResult(); + + $this->assertEquals(0, count($result), 'CmsAddress should be removed by orphanRemoval'); + } + + public function testOrphanRemovalWhenUnlink() + { + $user = new CmsUser; + $user->status = 'dev'; + $user->username = 'beberlei'; + $user->name = 'Bejamin Eberlei'; + + $email = new CmsEmail; + $email->email = 'beberlei@domain.com'; + + $user->setEmail($email); + + $this->_em->persist($user); + $this->_em->flush(); + + $userId = $user->getId(); + + $this->_em->clear(); + + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId); + + $user->setEmail(null); + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery('SELECT e FROM Doctrine\Tests\Models\CMS\CmsEmail e'); + $result = $query->getResult(); + + $this->assertEquals(0, count($result), 'CmsEmail should be removed by orphanRemoval'); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneSelfReferentialAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneSelfReferentialAssociationTest.php new file mode 100644 index 0000000..326e7ae --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneSelfReferentialAssociationTest.php @@ -0,0 +1,165 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->customer = new ECommerceCustomer(); + $this->customer->setName('Anakin Skywalker'); + $this->mentor = new ECommerceCustomer(); + $this->mentor->setName('Obi-wan Kenobi'); + } + + public function testSavesAOneToOneAssociationWithCascadeSaveSet() { + $this->customer->setMentor($this->mentor); + $this->_em->persist($this->customer); + $this->_em->flush(); + + $this->assertForeignKeyIs($this->mentor->getId()); + } + + public function testRemovesOneToOneAssociation() + { + $this->customer->setMentor($this->mentor); + $this->_em->persist($this->customer); + $this->customer->removeMentor(); + + $this->_em->flush(); + + $this->assertForeignKeyIs(null); + } + + public function testFind() + { + $id = $this->_createFixture(); + + $customer = $this->_em->find('Doctrine\Tests\Models\ECommerce\ECommerceCustomer', $id); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $customer->getMentor()); + } + + public function testEagerLoadsAssociation() + { + $this->_createFixture(); + + $query = $this->_em->createQuery('select c, m from Doctrine\Tests\Models\ECommerce\ECommerceCustomer c left join c.mentor m order by c.id asc'); + $result = $query->getResult(); + $customer = $result[0]; + $this->assertLoadingOfAssociation($customer); + } + + /** + * @group mine + * @return unknown_type + */ + public function testLazyLoadsAssociation() + { + $this->_createFixture(); + + $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCustomer'); + $metadata->associationMappings['mentor']['fetch'] = ClassMetadata::FETCH_LAZY; + + $query = $this->_em->createQuery("select c from Doctrine\Tests\Models\ECommerce\ECommerceCustomer c where c.name='Luke Skywalker'"); + $result = $query->getResult(); + $customer = $result[0]; + $this->assertLoadingOfAssociation($customer); + } + + public function testMultiSelfReference() + { + try { + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\MultiSelfReference') + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + + $entity1 = new MultiSelfReference(); + $this->_em->persist($entity1); + $entity1->setOther1($entity2 = new MultiSelfReference); + $entity1->setOther2($entity3 = new MultiSelfReference); + $this->_em->flush(); + + $this->_em->clear(); + + $entity2 = $this->_em->find(get_class($entity1), $entity1->getId()); + + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\MultiSelfReference', $entity2->getOther1()); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\MultiSelfReference', $entity2->getOther2()); + $this->assertNull($entity2->getOther1()->getOther1()); + $this->assertNull($entity2->getOther1()->getOther2()); + $this->assertNull($entity2->getOther2()->getOther1()); + $this->assertNull($entity2->getOther2()->getOther2()); + } + + public function assertLoadingOfAssociation($customer) + { + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCustomer', $customer->getMentor()); + $this->assertEquals('Obi-wan Kenobi', $customer->getMentor()->getName()); + } + + public function assertForeignKeyIs($value) { + $foreignKey = $this->_em->getConnection()->executeQuery('SELECT mentor_id FROM ecommerce_customers WHERE id=?', array($this->customer->getId()))->fetchColumn(); + $this->assertEquals($value, $foreignKey); + } + + private function _createFixture() + { + $customer = new ECommerceCustomer; + $customer->setName('Luke Skywalker'); + $mentor = new ECommerceCustomer; + $mentor->setName('Obi-wan Kenobi'); + $customer->setMentor($mentor); + + $this->_em->persist($customer); + + $this->_em->flush(); + $this->_em->clear(); + + return $customer->getId(); + } +} + +/** + * @Entity + */ +class MultiSelfReference { + /** @Id @GeneratedValue(strategy="AUTO") @Column(type="integer") */ + private $id; + /** + * @OneToOne(targetEntity="MultiSelfReference", cascade={"persist"}) + * @JoinColumn(name="other1", referencedColumnName="id") + */ + private $other1; + /** + * @OneToOne(targetEntity="MultiSelfReference", cascade={"persist"}) + * @JoinColumn(name="other2", referencedColumnName="id") + */ + private $other2; + + public function getId() {return $this->id;} + public function setOther1($other1) {$this->other1 = $other1;} + public function getOther1() {return $this->other1;} + public function setOther2($other2) {$this->other2 = $other2;} + public function getOther2() {return $this->other2;} +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneUnidirectionalAssociationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneUnidirectionalAssociationTest.php new file mode 100644 index 0000000..1ffae6b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OneToOneUnidirectionalAssociationTest.php @@ -0,0 +1,125 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->product = new ECommerceProduct(); + $this->product->setName('Doctrine 2 Manual'); + $this->shipping = new ECommerceShipping(); + $this->shipping->setDays('5'); + } + + public function testSavesAOneToOneAssociationWithCascadeSaveSet() { + $this->product->setShipping($this->shipping); + $this->_em->persist($this->product); + $this->_em->flush(); + + $this->assertForeignKeyIs($this->shipping->getId()); + } + + public function testRemovesOneToOneAssociation() + { + $this->product->setShipping($this->shipping); + $this->_em->persist($this->product); + $this->product->removeShipping(); + + $this->_em->flush(); + + $this->assertForeignKeyIs(null); + } + + public function _testEagerLoad() + { + $this->_createFixture(); + + $query = $this->_em->createQuery('select p, s from Doctrine\Tests\Models\ECommerce\ECommerceProduct p left join p.shipping s'); + $result = $query->getResult(); + $product = $result[0]; + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceShipping', $product->getShipping()); + $this->assertEquals(1, $product->getShipping()->getDays()); + } + + public function testLazyLoadsObjects() { + $this->_createFixture(); + $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct'); + $metadata->associationMappings['shipping']['fetch'] = ClassMetadata::FETCH_LAZY; + + $query = $this->_em->createQuery('select p from Doctrine\Tests\Models\ECommerce\ECommerceProduct p'); + $result = $query->getResult(); + $product = $result[0]; + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceShipping', $product->getShipping()); + $this->assertEquals(1, $product->getShipping()->getDays()); + } + + public function testDoesNotLazyLoadObjectsIfConfigurationDoesNotAllowIt() { + $this->_createFixture(); + + $query = $this->_em->createQuery('select p from Doctrine\Tests\Models\ECommerce\ECommerceProduct p'); + $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); + + $result = $query->getResult(); + $product = $result[0]; + + $this->assertNull($product->getShipping()); + } + + protected function _createFixture() + { + $product = new ECommerceProduct; + $product->setName('Php manual'); + $shipping = new ECommerceShipping; + $shipping->setDays('1'); + $product->setShipping($shipping); + + $this->_em->persist($product); + + $this->_em->flush(); + $this->_em->clear(); + } + + public function assertForeignKeyIs($value) { + $foreignKey = $this->_em->getConnection()->executeQuery( + 'SELECT shipping_id FROM ecommerce_products WHERE id=?', + array($this->product->getId()) + )->fetchColumn(); + $this->assertEquals($value, $foreignKey); + } + + /** + * @group DDC-762 + */ + public function testNullForeignKey() + { + $product = new ECommerceProduct(); + $product->setName('Doctrine 2 Manual'); + + $this->_em->persist($product); + $this->_em->flush(); + + $product = $this->_em->find(get_class($product), $product->getId()); + + $this->assertNull($product->getShipping()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php new file mode 100644 index 0000000..c2e131c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php @@ -0,0 +1,113 @@ +useModelSet('routing'); + parent::setUp(); + + $locations = array("Berlin", "Bonn", "Brasilia", "Atlanta"); + + foreach ($locations AS $locationName) { + $location = new RoutingLocation(); + $location->name = $locationName; + $this->_em->persist($location); + $this->locations[$locationName] = $location; + } + $this->_em->flush(); + } + + public function createPersistedRouteWithLegs() + { + $route = new RoutingRoute(); + + $leg1 = new RoutingLeg(); + $leg1->fromLocation = $this->locations['Berlin']; + $leg1->toLocation = $this->locations['Bonn']; + $leg1->departureDate = new \DateTime("now"); + $leg1->arrivalDate = new \DateTime("now +5 hours"); + + $leg2 = new RoutingLeg(); + $leg2->fromLocation = $this->locations['Bonn']; + $leg2->toLocation = $this->locations['Brasilia']; + $leg2->departureDate = new \DateTime("now +6 hours"); + $leg2->arrivalDate = new \DateTime("now +24 hours"); + + $route->legs[] = $leg2; + $route->legs[] = $leg1; + + $this->_em->persist($route); + $this->_em->flush(); + $routeId = $route->id; + $this->_em->clear(); + + return $routeId; + } + + public function testLazyManyToManyCollection_IsRetrievedWithOrderByClause() + { + $routeId = $this->createPersistedRouteWithLegs(); + + $route = $this->_em->find('Doctrine\Tests\Models\Routing\RoutingRoute', $routeId); + + $this->assertEquals(2, count($route->legs)); + $this->assertEquals("Berlin", $route->legs[0]->fromLocation->getName()); + $this->assertEquals("Bonn", $route->legs[1]->fromLocation->getName()); + } + + public function testLazyOneToManyCollection_IsRetrievedWithOrderByClause() + { + $route = new RoutingRoute(); + + $this->_em->persist($route); + $this->_em->flush(); + $routeId = $route->id; + + $booking1 = new RoutingRouteBooking(); + $booking1->passengerName = "Guilherme"; + $booking2 = new RoutingRouteBooking(); + $booking2->passengerName = "Benjamin"; + + $route->bookings[] = $booking1; + $booking1->route = $route; + $route->bookings[] = $booking2; + $booking2->route = $route; + + $this->_em->persist($booking1); + $this->_em->persist($booking2); + + $this->_em->flush(); + $this->_em->clear(); + + $route = $this->_em->find('Doctrine\Tests\Models\Routing\RoutingRoute', $routeId); + + $this->assertEquals(2, count($route->bookings)); + $this->assertEquals('Benjamin', $route->bookings[0]->getPassengerName()); + $this->assertEquals('Guilherme', $route->bookings[1]->getPassengerName()); + } + + public function testOrderedResultFromDqlQuery() + { + $routeId = $this->createPersistedRouteWithLegs(); + + $route = $this->_em->createQuery("SELECT r, l FROM Doctrine\Tests\Models\Routing\RoutingRoute r JOIN r.legs l WHERE r.id = ?1") + ->setParameter(1, $routeId) + ->getSingleResult(); + + $this->assertEquals(2, count($route->legs)); + $this->assertEquals("Berlin", $route->legs[0]->fromLocation->getName()); + $this->assertEquals("Bonn", $route->legs[1]->fromLocation->getName()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OrderedJoinedTableInheritanceCollectionTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OrderedJoinedTableInheritanceCollectionTest.php new file mode 100644 index 0000000..8c0d37b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/OrderedJoinedTableInheritanceCollectionTest.php @@ -0,0 +1,133 @@ + + */ +class OrderedJoinedTableInheritanceCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + protected function setUp() { + parent::setUp(); + try { + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\OJTIC_Pet'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\OJTIC_Cat'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\OJTIC_Dog'), + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + + $dog = new OJTIC_Dog(); + $dog->name = "Poofy"; + + $dog1 = new OJTIC_Dog(); + $dog1->name = "Zampa"; + $dog2 = new OJTIC_Dog(); + $dog2->name = "Aari"; + + $dog1->mother = $dog; + $dog2->mother = $dog; + + $dog->children[] = $dog1; + $dog->children[] = $dog2; + + $this->_em->persist($dog); + $this->_em->persist($dog1); + $this->_em->persist($dog2); + $this->_em->flush(); + $this->_em->clear(); + } + + public function testOrderdOneToManyCollection() + { + $poofy = $this->_em->createQuery("SELECT p FROM Doctrine\Tests\ORM\Functional\OJTIC_Pet p WHERE p.name = 'Poofy'")->getSingleResult(); + + $this->assertEquals('Aari', $poofy->children[0]->getName()); + $this->assertEquals('Zampa', $poofy->children[1]->getName()); + + $this->_em->clear(); + + $result = $this->_em->createQuery( + "SELECT p, c FROM Doctrine\Tests\ORM\Functional\OJTIC_Pet p JOIN p.children c WHERE p.name = 'Poofy'") + ->getResult(); + + $this->assertEquals(1, count($result)); + $poofy = $result[0]; + + $this->assertEquals('Aari', $poofy->children[0]->getName()); + $this->assertEquals('Zampa', $poofy->children[1]->getName()); + } +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({ + * "cat" = "OJTIC_Cat", + * "dog" = "OJTIC_Dog"}) + */ +abstract class OJTIC_Pet +{ + /** + * @Id + * @column(type="integer") + * @generatedValue(strategy="AUTO") + */ + public $id; + + /** + * + * @Column + */ + public $name; + + /** + * @ManyToOne(targetEntity="OJTIC_PET") + */ + public $mother; + + /** + * @OneToMany(targetEntity="OJTIC_Pet", mappedBy="mother") + * @OrderBy({"name" = "ASC"}) + */ + public $children; + + /** + * @ManyToMany(targetEntity="OJTIC_Pet") + * @JoinTable(name="OTJIC_Pet_Friends", + * joinColumns={@JoinColumn(name="pet_id", referencedColumnName="id")}, + * inverseJoinColumns={@JoinColumn(name="friend_id", referencedColumnName="id")}) + * @OrderBy({"name" = "ASC"}) + */ + public $friends; + + public function getName() + { + return $this->name; + } +} + +/** + * @Entity + */ +class OJTIC_Cat extends OJTIC_Pet +{ + +} + +/** + * @Entity + */ +class OJTIC_Dog extends OJTIC_Pet +{ + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php new file mode 100644 index 0000000..0a28455 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php @@ -0,0 +1,168 @@ +useModelSet('cms'); + parent::setUp(); + $this->populate(); + } + + /** + * @dataProvider useOutputWalkers + */ + public function testCountSimpleWithoutJoin($useOutputWalkers) + { + $dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u"; + $query = $this->_em->createQuery($dql); + + $paginator = new Paginator($query); + $paginator->setUseOutputWalkers($useOutputWalkers); + $this->assertCount(3, $paginator); + } + + /** + * @dataProvider useOutputWalkers + */ + public function testCountWithFetchJoin($useOutputWalkers) + { + $dql = "SELECT u,g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g"; + $query = $this->_em->createQuery($dql); + + $paginator = new Paginator($query); + $paginator->setUseOutputWalkers($useOutputWalkers); + $this->assertCount(3, $paginator); + } + + public function testCountComplexWithOutputWalker() + { + $dql = "SELECT g, COUNT(u.id) AS userCount FROM Doctrine\Tests\Models\CMS\CmsGroup g LEFT JOIN g.users u GROUP BY g HAVING COUNT(u.id) > 0"; + $query = $this->_em->createQuery($dql); + + $paginator = new Paginator($query); + $paginator->setUseOutputWalkers(true); + $this->assertCount(9, $paginator); + } + + /** + * @dataProvider useOutputWalkers + */ + public function testIterateSimpleWithoutJoinFetchJoinHandlingOff($useOutputWalkers) + { + $dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u"; + $query = $this->_em->createQuery($dql); + + $paginator = new Paginator($query, false); + $paginator->setUseOutputWalkers($useOutputWalkers); + $this->assertCount(3, $paginator->getIterator()); + } + + /** + * @dataProvider useOutputWalkers + */ + public function testIterateSimpleWithoutJoinFetchJoinHandlingOn($useOutputWalkers) + { + $dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u"; + $query = $this->_em->createQuery($dql); + + $paginator = new Paginator($query, true); + $paginator->setUseOutputWalkers($useOutputWalkers); + $this->assertCount(3, $paginator->getIterator()); + } + + /** + * @dataProvider useOutputWalkers + */ + public function testIterateWithFetchJoin($useOutputWalkers) + { + $dql = "SELECT u,g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g"; + $query = $this->_em->createQuery($dql); + + $paginator = new Paginator($query, true); + $paginator->setUseOutputWalkers($useOutputWalkers); + $this->assertCount(3, $paginator->getIterator()); + } + + public function testIterateComplexWithOutputWalker() + { + $dql = "SELECT g, COUNT(u.id) AS userCount FROM Doctrine\Tests\Models\CMS\CmsGroup g LEFT JOIN g.users u GROUP BY g HAVING COUNT(u.id) > 0"; + $query = $this->_em->createQuery($dql); + + $paginator = new Paginator($query); + $paginator->setUseOutputWalkers(true); + $this->assertCount(9, $paginator->getIterator()); + } + + public function testDetectOutputWalker() + { + // This query works using the output walkers but causes an exception using the TreeWalker + $dql = "SELECT g, COUNT(u.id) AS userCount FROM Doctrine\Tests\Models\CMS\CmsGroup g LEFT JOIN g.users u GROUP BY g HAVING COUNT(u.id) > 0"; + $query = $this->_em->createQuery($dql); + + // If the Paginator detects the custom output walker it should fall back to using the + // Tree walkers for pagination, which leads to an exception. If the query works, the output walkers were used + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Query\SqlWalker'); + $paginator = new Paginator($query); + + $this->setExpectedException( + 'RuntimeException', + 'Cannot count query that uses a HAVING clause. Use the output walkers for pagination' + ); + + count($paginator); + } + + public function testCloneQuery() + { + $dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u"; + $query = $this->_em->createQuery($dql); + + $paginator = new Paginator($query); + $paginator->getIterator(); + + $this->assertTrue($query->getParameters()->isEmpty()); + } + + public function populate() + { + for ($i = 0; $i < 3; $i++) { + $user = new CmsUser(); + $user->name = "Name$i"; + $user->username = "username$i"; + $user->status = "active"; + $this->_em->persist($user); + + for ($j = 0; $j < 3; $j++) {; + $group = new CmsGroup(); + $group->name = "group$j"; + $user->addGroup($group); + $this->_em->persist($group); + } + } + $this->_em->flush(); + } + + public function useOutputWalkers() + { + return array( + array(true), + array(false), + ); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PersistentCollectionTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PersistentCollectionTest.php new file mode 100644 index 0000000..2125966 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PersistentCollectionTest.php @@ -0,0 +1,98 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\PersistentCollectionHolder'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\PersistentCollectionContent'), + )); + } catch (\Exception $e) { + + } + PersistentObject::setObjectManager($this->_em); + } + + public function testPersist() + { + $collectionHolder = new PersistentCollectionHolder(); + $content = new PersistentCollectionContent('first element'); + $collectionHolder->addElement($content); + + $this->_em->persist($collectionHolder); + $this->_em->flush(); + $this->_em->clear(); + + $collectionHolder = $this->_em->find(__NAMESPACE__ . '\PersistentCollectionHolder', $collectionHolder->getId()); + $collectionHolder->getCollection(); + + $content = new PersistentCollectionContent('second element'); + $collectionHolder->addElement($content); + + $this->assertEquals(2, $collectionHolder->getCollection()->count()); + } + +} + +/** + * @Entity + */ +class PersistentCollectionHolder extends PersistentObject +{ + /** + * @Id @Column(type="integer") @GeneratedValue + * @var int + */ + protected $id; + + /** + * @var \Doctrine\Common\Collections\Collection + * @ManyToMany(targetEntity="PersistentCollectionContent", cascade={"all"}) + */ + protected $collection; + + public function __construct() + { + $this->collection = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * @param PersistentCollectionContent $element + */ + public function addElement(PersistentCollectionContent $element) + { + $this->collection->add($element); + } + + /** + * @return \Doctrine\Common\Collections\Collection + */ + public function getCollection() + { + return clone $this->collection; + } + +} + +/** + * @Entity + */ +class PersistentCollectionContent extends PersistentObject +{ + + /** + * @Id @Column(type="integer") @GeneratedValue + * @var int + */ + protected $id; + +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PersistentObjectTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PersistentObjectTest.php new file mode 100644 index 0000000..88e54ae --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PersistentObjectTest.php @@ -0,0 +1,105 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\PersistentEntity'), + )); + } catch (\Exception $e) { + + } + PersistentObject::setObjectManager($this->_em); + } + + public function testPersist() + { + $entity = new PersistentEntity(); + $entity->setName("test"); + + $this->_em->persist($entity); + $this->_em->flush(); + } + + public function testFind() + { + $entity = new PersistentEntity(); + $entity->setName("test"); + + $this->_em->persist($entity); + $this->_em->flush(); + $this->_em->clear(); + + $entity = $this->_em->find(__NAMESPACE__ . '\PersistentEntity', $entity->getId()); + + $this->assertEquals('test', $entity->getName()); + $entity->setName('foobar'); + + $this->_em->flush(); + } + + public function testGetReference() + { + $entity = new PersistentEntity(); + $entity->setName("test"); + + $this->_em->persist($entity); + $this->_em->flush(); + $this->_em->clear(); + + $entity = $this->_em->getReference(__NAMESPACE__ . '\PersistentEntity', $entity->getId()); + + $this->assertEquals('test', $entity->getName()); + } + + public function testSetAssociation() + { + $entity = new PersistentEntity(); + $entity->setName("test"); + $entity->setParent($entity); + + $this->_em->persist($entity); + $this->_em->flush(); + $this->_em->clear(); + + $entity = $this->_em->getReference(__NAMESPACE__ . '\PersistentEntity', $entity->getId()); + $this->assertSame($entity, $entity->getParent()); + } +} + +/** + * @Entity + */ +class PersistentEntity extends PersistentObject +{ + /** + * @Id @Column(type="integer") @GeneratedValue + * @var int + */ + protected $id; + + /** + * @Column(type="string") + * @var string + */ + protected $name; + + /** + * @ManyToOne(targetEntity="PersistentEntity") + * @var PersistentEntity + */ + protected $parent; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PostFlushEventTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PostFlushEventTest.php new file mode 100644 index 0000000..8198871 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PostFlushEventTest.php @@ -0,0 +1,95 @@ + + */ +class PostFlushEventTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + /** + * @var PostFlushListener + */ + private $listener; + + protected function setUp() + { + $this->useModelSet('cms'); + parent::setUp(); + $this->listener = new PostFlushListener(); + $evm = $this->_em->getEventManager(); + $evm->addEventListener(Events::postFlush, $this->listener); + } + + public function testListenerShouldBeNotified() + { + $this->_em->persist($this->createNewValidUser()); + $this->_em->flush(); + $this->assertTrue($this->listener->wasNotified); + } + + public function testListenerShouldNotBeNotifiedWhenFlushThrowsException() + { + $user = new CmsUser(); + $user->username = 'dfreudenberger'; + $this->_em->persist($user); + $exceptionRaised = false; + + try { + $this->_em->flush(); + } catch (\Exception $ex) { + $exceptionRaised = true; + } + + $this->assertTrue($exceptionRaised); + $this->assertFalse($this->listener->wasNotified); + } + + public function testListenerShouldReceiveEntityManagerThroughArgs() + { + $this->_em->persist($this->createNewValidUser()); + $this->_em->flush(); + $receivedEm = $this->listener->receivedArgs->getEntityManager(); + $this->assertSame($this->_em, $receivedEm); + } + + /** + * @return CmsUser + */ + private function createNewValidUser() + { + $user = new CmsUser(); + $user->username = 'dfreudenberger'; + $user->name = 'Daniel Freudenberger'; + return $user; + } +} + +class PostFlushListener +{ + /** + * @var bool + */ + public $wasNotified = false; + + /** + * @var PostFlushEventArgs + */ + public $receivedArgs; + + /** + * @param PostFlushEventArgs $args + */ + public function postFlush(PostFlushEventArgs $args) + { + $this->wasNotified = true; + $this->receivedArgs = $args; + } +} + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php new file mode 100644 index 0000000..4ee7b7c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php @@ -0,0 +1,53 @@ +_em->getConnection()->getDatabasePlatform()->getName() != 'postgresql') { + $this->markTestSkipped('This test is special to the PostgreSQL IDENTITY key generation strategy.'); + } else { + try { + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\PostgreSQLIdentityEntity'), + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + } + + protected function tearDown() { + parent::tearDown(); + // drop sequence manually due to dependency + $this->_em->getConnection()->exec('DROP SEQUENCE postgresqlidentityentity_id_seq CASCADE'); + } + + public function testPreSavePostSaveCallbacksAreInvoked() + { + $entity = new PostgreSQLIdentityEntity(); + $entity->setValue('hello'); + $this->_em->persist($entity); + $this->_em->flush(); + $this->assertTrue(is_numeric($entity->getId())); + $this->assertTrue($entity->getId() > 0); + $this->assertTrue($this->_em->contains($entity)); + } +} + +/** @Entity */ +class PostgreSQLIdentityEntity { + /** @Id @Column(type="integer") @GeneratedValue(strategy="IDENTITY") */ + private $id; + /** @Column(type="string") */ + private $value; + public function getId() {return $this->id;} + public function getValue() {return $this->value;} + public function setValue($value) {$this->value = $value;} +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php new file mode 100644 index 0000000..52ac8f5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php @@ -0,0 +1,133 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), + )); + } catch (\Exception $e) { + } + $this->user = new CmsUser(); + $this->user->username = 'ocramius'; + $this->user->name = 'Marco'; + $this->_em->persist($this->user); + $this->_em->flush(); + $this->_em->clear(); + } + + /** + * Verifies that a proxy can be successfully persisted and updated + */ + public function testPersistUpdate() + { + // Considering case (a) + $persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\CMS\CmsUser'); + $proxy = new Proxy($persister, array()); + $proxy->__isInitialized__ = true; + $proxy->username = 'ocra'; + $proxy->name = 'Marco'; + $this->_em->persist($proxy); + $this->_em->flush(); + $this->assertNotNull($proxy->getId()); + $proxy->name = 'Marco Pivetta'; + $this + ->_em + ->getUnitOfWork() + ->computeChangeSet($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), $proxy); + $this->assertNotEmpty($this->_em->getUnitOfWork()->getEntityChangeSet($proxy)); + $this->assertEquals('Marco Pivetta', $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $proxy->getId())->name); + $this->_em->remove($proxy); + $this->_em->flush(); + } + + public function testEntityWithIdentifier() + { + // Considering case (b) + $persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\CMS\CmsUser'); + $uninitializedProxy = new Proxy($persister, array('id' => $this->user->getId())); + $uninitializedProxy->id = $this->user->getId(); + $uninitializedProxy->username = 'ocra'; + $uninitializedProxy->name = 'Marco Pivetta'; + $this->_em->persist($uninitializedProxy); + $this->_em->flush(); + $this->assertEquals($this->user->getId(), $uninitializedProxy->getId()); + $this->_em->remove($uninitializedProxy); + $this->_em->flush(); + } + + /** + * Verifying that proxies can be used without problems as query parameters + */ + public function testProxyAsDqlParameterPersist() + { + $persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\CMS\CmsUser'); + $proxy = new Proxy($persister, array('id' => $this->user->getId())); + $proxy->id = $this->user->getId(); + $result = $this + ->_em + ->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u = ?1') + ->setParameter(1, $proxy) + ->getSingleResult(); + $this->assertSame($this->user->getId(), $result->getId()); + $this->_em->remove($proxy); + $this->_em->flush(); + } + + /** + * Verifying that proxies can be used without problems as query parameters + */ + public function testFindWithProxyName() + { + $result = $this + ->_em + ->find('Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\CMS\CmsUser', $this->user->getId()); + $this->assertSame($this->user->getId(), $result->getId()); + $this->_em->clear(); + $result = $this + ->_em + ->getReference('Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\CMS\CmsUser', $this->user->getId()); + $this->assertSame($this->user->getId(), $result->getId()); + $this->_em->clear(); + $result = $this + ->_em + ->getRepository('Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\CMS\CmsUser') + ->findOneBy(array('username' => $this->user->username)); + $this->assertSame($this->user->getId(), $result->getId()); + $this->_em->clear(); + $result = $this + ->_em + ->createQuery('SELECT u FROM Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1') + ->setParameter(1, $this->user->getId()) + ->getSingleResult(); + $this->assertSame($this->user->getId(), $result->getId()); + $this->_em->clear(); + } + + protected function tearDown() + { + $this->_em->createQuery('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser u')->execute(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryCacheTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryCacheTest.php new file mode 100644 index 0000000..faffdd7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryCacheTest.php @@ -0,0 +1,153 @@ +cacheDataReflection = new \ReflectionProperty("Doctrine\Common\Cache\ArrayCache", "data"); + $this->cacheDataReflection->setAccessible(true); + + $this->useModelSet('cms'); + + parent::setUp(); + } + + /** + * @param ArrayCache $cache + * @return integer + */ + private function getCacheSize(ArrayCache $cache) + { + return sizeof($this->cacheDataReflection->getValue($cache)); + } + + + public function testQueryCache_DependsOnHints() + { + $query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux'); + + $cache = new ArrayCache(); + $query->setQueryCacheDriver($cache); + + $query->getResult(); + $this->assertEquals(2, $this->getCacheSize($cache)); + + $query->setHint('foo', 'bar'); + + $query->getResult(); + $this->assertEquals(3, $this->getCacheSize($cache)); + + return $query; + } + + /** + * @param $query + * @depends testQueryCache_DependsOnHints + */ + public function testQueryCache_DependsOnFirstResult($query) + { + $cache = $query->getQueryCacheDriver(); + $cacheCount = $this->getCacheSize($cache); + + $query->setFirstResult(10); + $query->setMaxResults(9999); + + $query->getResult(); + $this->assertEquals($cacheCount + 1, $this->getCacheSize($cache)); + } + + /** + * @param $query + * @depends testQueryCache_DependsOnHints + */ + public function testQueryCache_DependsOnMaxResults($query) + { + $cache = $query->getQueryCacheDriver(); + $cacheCount = $this->getCacheSize($cache); + + $query->setMaxResults(10); + + $query->getResult(); + $this->assertEquals($cacheCount + 1, $this->getCacheSize($cache)); + } + + /** + * @param $query + * @depends testQueryCache_DependsOnHints + */ + public function testQueryCache_DependsOnHydrationMode($query) + { + $cache = $query->getQueryCacheDriver(); + $cacheCount = $this->getCacheSize($cache); + + $query->getArrayResult(); + $this->assertEquals($cacheCount + 1, $this->getCacheSize($cache)); + } + + public function testQueryCache_NoHitSaveParserResult() + { + $this->_em->getConfiguration()->setQueryCacheImpl(new ArrayCache()); + + $query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux'); + + $cache = new \Doctrine\Common\Cache\ArrayCache(); + + $query->setQueryCacheDriver($cache); + + $users = $query->getResult(); + + $data = $this->cacheDataReflection->getValue($cache); + $this->assertEquals(2, count($data)); + + $this->assertInstanceOf('Doctrine\ORM\Query\ParserResult', array_pop($data)); + } + + public function testQueryCache_HitDoesNotSaveParserResult() + { + $this->_em->getConfiguration()->setQueryCacheImpl(new ArrayCache()); + + $query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux'); + + $sqlExecMock = $this->getMock('Doctrine\ORM\Query\Exec\AbstractSqlExecutor', array('execute')); + $sqlExecMock->expects($this->once()) + ->method('execute') + ->will($this->returnValue( 10 )); + + $parserResultMock = $this->getMock('Doctrine\ORM\Query\ParserResult'); + $parserResultMock->expects($this->once()) + ->method('getSqlExecutor') + ->will($this->returnValue($sqlExecMock)); + + $cache = $this->getMock('Doctrine\Common\Cache\CacheProvider', + array('doFetch', 'doContains', 'doSave', 'doDelete', 'doFlush', 'doGetStats')); + $cache->expects($this->at(0))->method('doFetch')->will($this->returnValue(1)); + $cache->expects($this->at(1)) + ->method('doFetch') + ->with($this->isType('string')) + ->will($this->returnValue($parserResultMock)); + $cache->expects($this->never()) + ->method('doSave'); + + $query->setQueryCacheDriver($cache); + + $users = $query->getResult(); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php new file mode 100644 index 0000000..7f3180a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php @@ -0,0 +1,402 @@ +useModelSet('company'); + parent::setUp(); + + $this->generateFixture(); + } + + public function testAggregateSum() + { + $salarySum = $this->_em->createQuery('SELECT SUM(m.salary) AS salary FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(1500000, $salarySum['salary']); + } + + public function testAggregateAvg() + { + $salaryAvg = $this->_em->createQuery('SELECT AVG(m.salary) AS salary FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(375000, round($salaryAvg['salary'], 0)); + } + + public function testAggregateMin() + { + $salary = $this->_em->createQuery('SELECT MIN(m.salary) AS salary FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(100000, $salary['salary']); + } + + public function testAggregateMax() + { + $salary = $this->_em->createQuery('SELECT MAX(m.salary) AS salary FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(800000, $salary['salary']); + } + + public function testAggregateCount() + { + $managerCount = $this->_em->createQuery('SELECT COUNT(m.id) AS managers FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(4, $managerCount['managers']); + } + + public function testFunctionAbs() + { + $result = $this->_em->createQuery('SELECT m, ABS(m.salary * -1) AS abs FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(100000, $result[0]['abs']); + $this->assertEquals(200000, $result[1]['abs']); + $this->assertEquals(400000, $result[2]['abs']); + $this->assertEquals(800000, $result[3]['abs']); + } + + public function testFunctionConcat() + { + $arg = $this->_em->createQuery('SELECT m, CONCAT(m.name, m.department) AS namedep FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getArrayResult(); + + $this->assertEquals(4, count($arg)); + $this->assertEquals('Roman B.IT', $arg[0]['namedep']); + $this->assertEquals('Benjamin E.HR', $arg[1]['namedep']); + $this->assertEquals('Guilherme B.Complaint Department', $arg[2]['namedep']); + $this->assertEquals('Jonathan W.Administration', $arg[3]['namedep']); + } + + public function testFunctionLength() + { + $result = $this->_em->createQuery('SELECT m, LENGTH(CONCAT(m.name, m.department)) AS namedeplength FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(10, $result[0]['namedeplength']); + $this->assertEquals(13, $result[1]['namedeplength']); + $this->assertEquals(32, $result[2]['namedeplength']); + $this->assertEquals(25, $result[3]['namedeplength']); + } + + public function testFunctionLocate() + { + $dql = "SELECT m, LOCATE('e', LOWER(m.name)) AS loc, LOCATE('e', LOWER(m.name), 7) AS loc2 ". + "FROM Doctrine\Tests\Models\Company\CompanyManager m"; + + $result = $this->_em->createQuery($dql) + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(0, $result[0]['loc']); + $this->assertEquals(2, $result[1]['loc']); + $this->assertEquals(6, $result[2]['loc']); + $this->assertEquals(0, $result[3]['loc']); + $this->assertEquals(0, $result[0]['loc2']); + $this->assertEquals(10, $result[1]['loc2']); + $this->assertEquals(9, $result[2]['loc2']); + $this->assertEquals(0, $result[3]['loc2']); + } + + public function testFunctionLower() + { + $result = $this->_em->createQuery("SELECT m, LOWER(m.name) AS lowername FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals('roman b.', $result[0]['lowername']); + $this->assertEquals('benjamin e.', $result[1]['lowername']); + $this->assertEquals('guilherme b.', $result[2]['lowername']); + $this->assertEquals('jonathan w.', $result[3]['lowername']); + } + + public function testFunctionMod() + { + $result = $this->_em->createQuery("SELECT m, MOD(m.salary, 3500) AS amod FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(2000, $result[0]['amod']); + $this->assertEquals(500, $result[1]['amod']); + $this->assertEquals(1000, $result[2]['amod']); + $this->assertEquals(2000, $result[3]['amod']); + } + + public function testFunctionSqrt() + { + $result = $this->_em->createQuery("SELECT m, SQRT(m.salary) AS sqrtsalary FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(316, round($result[0]['sqrtsalary'])); + $this->assertEquals(447, round($result[1]['sqrtsalary'])); + $this->assertEquals(632, round($result[2]['sqrtsalary'])); + $this->assertEquals(894, round($result[3]['sqrtsalary'])); + } + + public function testFunctionUpper() + { + $result = $this->_em->createQuery("SELECT m, UPPER(m.name) AS uppername FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals('ROMAN B.', $result[0]['uppername']); + $this->assertEquals('BENJAMIN E.', $result[1]['uppername']); + $this->assertEquals('GUILHERME B.', $result[2]['uppername']); + $this->assertEquals('JONATHAN W.', $result[3]['uppername']); + } + + public function testFunctionSubstring() + { + $dql = "SELECT m, SUBSTRING(m.name, 1, 3) AS str1, SUBSTRING(m.name, 5) AS str2 ". + "FROM Doctrine\Tests\Models\Company\CompanyManager m ORDER BY m.name"; + + $result = $this->_em->createQuery($dql) + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals('Ben', $result[0]['str1']); + $this->assertEquals('Gui', $result[1]['str1']); + $this->assertEquals('Jon', $result[2]['str1']); + $this->assertEquals('Rom', $result[3]['str1']); + + $this->assertEquals('amin E.', $result[0]['str2']); + $this->assertEquals('herme B.', $result[1]['str2']); + $this->assertEquals('than W.', $result[2]['str2']); + $this->assertEquals('n B.', $result[3]['str2']); + } + + public function testFunctionTrim() + { + $dql = "SELECT m, TRIM(TRAILING '.' FROM m.name) AS str1, ". + " TRIM(LEADING '.' FROM m.name) AS str2, TRIM(CONCAT(' ', CONCAT(m.name, ' '))) AS str3 ". + "FROM Doctrine\Tests\Models\Company\CompanyManager m"; + + $result = $this->_em->createQuery($dql)->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals('Roman B', $result[0]['str1']); + $this->assertEquals('Benjamin E', $result[1]['str1']); + $this->assertEquals('Guilherme B', $result[2]['str1']); + $this->assertEquals('Jonathan W', $result[3]['str1']); + $this->assertEquals('Roman B.', $result[0]['str2']); + $this->assertEquals('Benjamin E.', $result[1]['str2']); + $this->assertEquals('Guilherme B.', $result[2]['str2']); + $this->assertEquals('Jonathan W.', $result[3]['str2']); + $this->assertEquals('Roman B.', $result[0]['str3']); + $this->assertEquals('Benjamin E.', $result[1]['str3']); + $this->assertEquals('Guilherme B.', $result[2]['str3']); + $this->assertEquals('Jonathan W.', $result[3]['str3']); + } + + public function testOperatorAdd() + { + $result = $this->_em->createQuery('SELECT m, m.salary+2500 AS add FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(102500, $result[0]['add']); + $this->assertEquals(202500, $result[1]['add']); + $this->assertEquals(402500, $result[2]['add']); + $this->assertEquals(802500, $result[3]['add']); + } + + public function testOperatorSub() + { + $result = $this->_em->createQuery('SELECT m, m.salary-2500 AS sub FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(97500, $result[0]['sub']); + $this->assertEquals(197500, $result[1]['sub']); + $this->assertEquals(397500, $result[2]['sub']); + $this->assertEquals(797500, $result[3]['sub']); + } + + public function testOperatorMultiply() + { + $result = $this->_em->createQuery('SELECT m, m.salary*2 AS op FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(200000, $result[0]['op']); + $this->assertEquals(400000, $result[1]['op']); + $this->assertEquals(800000, $result[2]['op']); + $this->assertEquals(1600000, $result[3]['op']); + } + + /** + * @group test + */ + public function testOperatorDiv() + { + $result = $this->_em->createQuery('SELECT m, (m.salary/0.5) AS op FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(200000, $result[0]['op']); + $this->assertEquals(400000, $result[1]['op']); + $this->assertEquals(800000, $result[2]['op']); + $this->assertEquals(1600000, $result[3]['op']); + } + + public function testConcatFunction() + { + $arg = $this->_em->createQuery('SELECT CONCAT(m.name, m.department) AS namedep FROM Doctrine\Tests\Models\Company\CompanyManager m order by namedep desc') + ->getArrayResult(); + + $this->assertEquals(4, count($arg)); + $this->assertEquals('Roman B.IT', $arg[0]['namedep']); + $this->assertEquals('Jonathan W.Administration', $arg[1]['namedep']); + $this->assertEquals('Guilherme B.Complaint Department', $arg[2]['namedep']); + $this->assertEquals('Benjamin E.HR', $arg[3]['namedep']); + } + + /** + * @group DDC-1014 + */ + public function testDateDiff() + { + $query = $this->_em->createQuery("SELECT DATE_DIFF(CURRENT_TIMESTAMP(), DATE_ADD(CURRENT_TIMESTAMP(), 10, 'day')) AS diff FROM Doctrine\Tests\Models\Company\CompanyManager m"); + $arg = $query->getArrayResult(); + + $this->assertEquals(-10, $arg[0]['diff'], "Should be roughly -10 (or -9)", 1); + + $query = $this->_em->createQuery("SELECT DATE_DIFF(DATE_ADD(CURRENT_TIMESTAMP(), 10, 'day'), CURRENT_TIMESTAMP()) AS diff FROM Doctrine\Tests\Models\Company\CompanyManager m"); + $arg = $query->getArrayResult(); + + $this->assertEquals(10, $arg[0]['diff'], "Should be roughly 10 (or 9)", 1); + } + + /** + * @group DDC-1014 + */ + public function testDateAdd() + { + $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'day') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertTrue(strtotime($arg[0]['add']) > 0); + + $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'month') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertTrue(strtotime($arg[0]['add']) > 0); + } + + /** + * @group DDC-1014 + */ + public function testDateSub() + { + $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'day') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertTrue(strtotime($arg[0]['add']) > 0); + + $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'month') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertTrue(strtotime($arg[0]['add']) > 0); + } + + /** + * @group DDC-1213 + */ + public function testBitOrComparison() + { + $dql = 'SELECT m, ' . + 'BIT_OR(4, 2) AS bit_or,' . + 'BIT_OR( (m.salary/100000) , 2 ) AS salary_bit_or ' . + 'FROM Doctrine\Tests\Models\Company\CompanyManager m ' . + 'ORDER BY ' . + 'm.id ' ; + $result = $this->_em->createQuery($dql)->getArrayResult(); + + $this->assertEquals(4 | 2, $result[0]['bit_or']); + $this->assertEquals(4 | 2, $result[1]['bit_or']); + $this->assertEquals(4 | 2, $result[2]['bit_or']); + $this->assertEquals(4 | 2, $result[3]['bit_or']); + + $this->assertEquals(($result[0][0]['salary']/100000) | 2, $result[0]['salary_bit_or']); + $this->assertEquals(($result[1][0]['salary']/100000) | 2, $result[1]['salary_bit_or']); + $this->assertEquals(($result[2][0]['salary']/100000) | 2, $result[2]['salary_bit_or']); + $this->assertEquals(($result[3][0]['salary']/100000) | 2, $result[3]['salary_bit_or']); + } + + /** + * @group DDC-1213 + */ + public function testBitAndComparison() + { + $dql = 'SELECT m, ' . + 'BIT_AND(4, 2) AS bit_and,' . + 'BIT_AND( (m.salary/100000) , 2 ) AS salary_bit_and ' . + 'FROM Doctrine\Tests\Models\Company\CompanyManager m ' . + 'ORDER BY ' . + 'm.id ' ; + $result = $this->_em->createQuery($dql)->getArrayResult(); + + $this->assertEquals(4 & 2, $result[0]['bit_and']); + $this->assertEquals(4 & 2, $result[1]['bit_and']); + $this->assertEquals(4 & 2, $result[2]['bit_and']); + $this->assertEquals(4 & 2, $result[3]['bit_and']); + + $this->assertEquals(($result[0][0]['salary']/100000) & 2, $result[0]['salary_bit_and']); + $this->assertEquals(($result[1][0]['salary']/100000) & 2, $result[1]['salary_bit_and']); + $this->assertEquals(($result[2][0]['salary']/100000) & 2, $result[2]['salary_bit_and']); + $this->assertEquals(($result[3][0]['salary']/100000) & 2, $result[3]['salary_bit_and']); + } + + protected function generateFixture() + { + $manager1 = new CompanyManager(); + $manager1->setName('Roman B.'); + $manager1->setTitle('Foo'); + $manager1->setDepartment('IT'); + $manager1->setSalary(100000); + + $manager2 = new CompanyManager(); + $manager2->setName('Benjamin E.'); + $manager2->setTitle('Foo'); + $manager2->setDepartment('HR'); + $manager2->setSalary(200000); + + $manager3 = new CompanyManager(); + $manager3->setName('Guilherme B.'); + $manager3->setTitle('Foo'); + $manager3->setDepartment('Complaint Department'); + $manager3->setSalary(400000); + + $manager4 = new CompanyManager(); + $manager4->setName('Jonathan W.'); + $manager4->setTitle('Foo'); + $manager4->setDepartment('Administration'); + $manager4->setSalary(800000); + + $this->_em->persist($manager1); + $this->_em->persist($manager2); + $this->_em->persist($manager3); + $this->_em->persist($manager4); + $this->_em->flush(); + $this->_em->clear(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryTest.php new file mode 100644 index 0000000..906b5e6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/QueryTest.php @@ -0,0 +1,783 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testSimpleQueries() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select u, upper(u.name) from Doctrine\Tests\Models\CMS\CmsUser u where u.username = 'gblanco'"); + + $result = $query->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][0]); + $this->assertEquals('Guilherme', $result[0][0]->name); + $this->assertEquals('gblanco', $result[0][0]->username); + $this->assertEquals('developer', $result[0][0]->status); + $this->assertEquals('GUILHERME', $result[0][1]); + + $resultArray = $query->getArrayResult(); + $this->assertEquals(1, count($resultArray)); + $this->assertTrue(is_array($resultArray[0][0])); + $this->assertEquals('Guilherme', $resultArray[0][0]['name']); + $this->assertEquals('gblanco', $resultArray[0][0]['username']); + $this->assertEquals('developer', $resultArray[0][0]['status']); + $this->assertEquals('GUILHERME', $resultArray[0][1]); + + $scalarResult = $query->getScalarResult(); + $this->assertEquals(1, count($scalarResult)); + $this->assertEquals('Guilherme', $scalarResult[0]['u_name']); + $this->assertEquals('gblanco', $scalarResult[0]['u_username']); + $this->assertEquals('developer', $scalarResult[0]['u_status']); + $this->assertEquals('GUILHERME', $scalarResult[0][1]); + + $query = $this->_em->createQuery("select upper(u.name) from Doctrine\Tests\Models\CMS\CmsUser u where u.username = 'gblanco'"); + $this->assertEquals('GUILHERME', $query->getSingleScalarResult()); + } + + public function testJoinQueries() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $article1 = new CmsArticle; + $article1->topic = "Doctrine 2"; + $article1->text = "This is an introduction to Doctrine 2."; + $user->addArticle($article1); + + $article2 = new CmsArticle; + $article2->topic = "Symfony 2"; + $article2->text = "This is an introduction to Symfony 2."; + $user->addArticle($article2); + + $this->_em->persist($user); + $this->_em->persist($article1); + $this->_em->persist($article2); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select u, a from Doctrine\Tests\Models\CMS\CmsUser u join u.articles a ORDER BY a.topic"); + $users = $query->getResult(); + $this->assertEquals(1, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); + $this->assertEquals(2, count($users[0]->articles)); + $this->assertEquals('Doctrine 2', $users[0]->articles[0]->topic); + $this->assertEquals('Symfony 2', $users[0]->articles[1]->topic); + } + + public function testUsingZeroBasedQueryParameterShouldWork() + { + $user = new CmsUser; + $user->name = 'Jonathan'; + $user->username = 'jwage'; + $user->status = 'developer'; + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ?0'); + $q->setParameter(0, 'jwage'); + $user = $q->getSingleResult(); + + $this->assertNotNull($user); + } + + public function testUsingUnknownQueryParameterShouldThrowException() + { + $this->setExpectedException( + "Doctrine\ORM\Query\QueryException", + "Invalid parameter: token 2 is not defined in the query." + ); + + $q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = ?1'); + $q->setParameter(2, 'jwage'); + $user = $q->getSingleResult(); + } + + public function testMismatchingParamExpectedParamCount() + { + $this->setExpectedException( + "Doctrine\ORM\Query\QueryException", + "Invalid parameter number: number of bound variables does not match number of tokens" + ); + + $q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = ?1'); + $q->setParameter(1, 'jwage'); + $q->setParameter(2, 'jwage'); + + $user = $q->getSingleResult(); + } + + public function testInvalidInputParameterThrowsException() + { + $this->setExpectedException("Doctrine\ORM\Query\QueryException"); + + $q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = ?'); + $q->setParameter(1, 'jwage'); + $user = $q->getSingleResult(); + } + + public function testSetParameters() + { + $q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = ?1 AND u.status = ?2'); + + $parameters = new ArrayCollection(); + $parameters->add(new Parameter(1, 'jwage')); + $parameters->add(new Parameter(2, 'active')); + + $q->setParameters($parameters); + $users = $q->getResult(); + } + + public function testSetParametersBackwardsCompatible() + { + $q = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = ?1 AND u.status = ?2'); + $q->setParameters(array(1 => 'jwage', 2 => 'active')); + + $users = $q->getResult(); + } + + /** + * @group DDC-1070 + */ + public function testIterateResultAsArrayAndParams() + { + $article1 = new CmsArticle; + $article1->topic = "Doctrine 2"; + $article1->text = "This is an introduction to Doctrine 2."; + + $article2 = new CmsArticle; + $article2->topic = "Symfony 2"; + $article2->text = "This is an introduction to Symfony 2."; + + $this->_em->persist($article1); + $this->_em->persist($article2); + + $this->_em->flush(); + $this->_em->clear(); + $articleId = $article1->id; + + $query = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = ?1"); + $articles = $query->iterate(new ArrayCollection(array(new Parameter(1, 'Doctrine 2'))), Query::HYDRATE_ARRAY); + + $found = array(); + foreach ($articles AS $article) { + $found[] = $article; + } + $this->assertEquals(1, count($found)); + $this->assertEquals(array( + array(array('id' => $articleId, 'topic' => 'Doctrine 2', 'text' => 'This is an introduction to Doctrine 2.', 'version' => 1)) + ), $found); + } + + public function testIterateResult_IterativelyBuildUpUnitOfWork() + { + $article1 = new CmsArticle; + $article1->topic = "Doctrine 2"; + $article1->text = "This is an introduction to Doctrine 2."; + + $article2 = new CmsArticle; + $article2->topic = "Symfony 2"; + $article2->text = "This is an introduction to Symfony 2."; + + $this->_em->persist($article1); + $this->_em->persist($article2); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a"); + $articles = $query->iterate(); + + $iteratedCount = 0; + $topics = array(); + foreach($articles AS $row) { + $article = $row[0]; + $topics[] = $article->topic; + + $identityMap = $this->_em->getUnitOfWork()->getIdentityMap(); + $identityMapCount = count($identityMap['Doctrine\Tests\Models\CMS\CmsArticle']); + $this->assertTrue($identityMapCount>$iteratedCount); + + $iteratedCount++; + } + + $this->assertEquals(array("Doctrine 2", "Symfony 2"), $topics); + $this->assertEquals(2, $iteratedCount); + + $this->_em->flush(); + $this->_em->clear(); + } + + public function testIterateResultClearEveryCycle() + { + $article1 = new CmsArticle; + $article1->topic = "Doctrine 2"; + $article1->text = "This is an introduction to Doctrine 2."; + + $article2 = new CmsArticle; + $article2->topic = "Symfony 2"; + $article2->text = "This is an introduction to Symfony 2."; + + $this->_em->persist($article1); + $this->_em->persist($article2); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a"); + $articles = $query->iterate(); + + $iteratedCount = 0; + $topics = array(); + foreach($articles AS $row) { + $article = $row[0]; + $topics[] = $article->topic; + + $this->_em->clear(); + + $iteratedCount++; + } + + $this->assertEquals(array("Doctrine 2", "Symfony 2"), $topics); + $this->assertEquals(2, $iteratedCount); + + $this->_em->flush(); + } + + /** + * @expectedException \Doctrine\ORM\Query\QueryException + */ + public function testIterateResult_FetchJoinedCollection_ThrowsException() + { + $query = $this->_em->createQuery("SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles a"); + $articles = $query->iterate(); + } + + /** + * @expectedException Doctrine\ORM\NoResultException + */ + public function testGetSingleResultThrowsExceptionOnNoResult() + { + $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a") + ->getSingleResult(); + } + + /** + * @expectedException Doctrine\ORM\NoResultException + */ + public function testGetSingleScalarResultThrowsExceptionOnNoResult() + { + $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a") + ->getSingleScalarResult(); + } + + /** + * @expectedException Doctrine\ORM\NonUniqueResultException + */ + public function testGetSingleScalarResultThrowsExceptionOnNonUniqueResult() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + + $article1 = new CmsArticle; + $article1->topic = "Doctrine 2"; + $article1->text = "This is an introduction to Doctrine 2."; + $user->addArticle($article1); + + $article2 = new CmsArticle; + $article2->topic = "Symfony 2"; + $article2->text = "This is an introduction to Symfony 2."; + $user->addArticle($article2); + + $this->_em->persist($user); + $this->_em->persist($article1); + $this->_em->persist($article2); + + $this->_em->flush(); + $this->_em->clear(); + + $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a") + ->getSingleScalarResult(); + } + + public function testModifiedLimitQuery() + { + for ($i = 0; $i < 5; $i++) { + $user = new CmsUser; + $user->name = 'Guilherme' . $i; + $user->username = 'gblanco' . $i; + $user->status = 'developer'; + $this->_em->persist($user); + } + + $this->_em->flush(); + $this->_em->clear(); + + $data = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u') + ->setFirstResult(1) + ->setMaxResults(2) + ->getResult(); + + $this->assertEquals(2, count($data)); + $this->assertEquals('gblanco1', $data[0]->username); + $this->assertEquals('gblanco2', $data[1]->username); + + $data = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u') + ->setFirstResult(3) + ->setMaxResults(2) + ->getResult(); + + $this->assertEquals(2, count($data)); + $this->assertEquals('gblanco3', $data[0]->username); + $this->assertEquals('gblanco4', $data[1]->username); + + $data = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u') + ->setFirstResult(3) + ->setMaxResults(2) + ->getScalarResult(); + } + + public function testSupportsQueriesWithEntityNamespaces() + { + $this->_em->getConfiguration()->addEntityNamespace('CMS', 'Doctrine\Tests\Models\CMS'); + + try { + $query = $this->_em->createQuery('UPDATE CMS:CmsUser u SET u.name = ?1'); + $this->assertEquals('UPDATE cms_users SET name = ?', $query->getSql()); + $query->free(); + } catch (\Exception $e) { + $this->fail($e->getMessage()); + } + + $this->_em->getConfiguration()->setEntityNamespaces(array()); + } + + /** + * @group DDC-604 + */ + public function testEntityParameters() + { + $article = new CmsArticle; + $article->topic = "dr. dolittle"; + $article->text = "Once upon a time ..."; + $author = new CmsUser; + $author->name = "anonymous"; + $author->username = "anon"; + $author->status = "here"; + $article->user = $author; + $this->_em->persist($author); + $this->_em->persist($article); + $this->_em->flush(); + $this->_em->clear(); + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $q = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a where a.topic = :topic and a.user = :user") + ->setParameter("user", $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsUser', $author->id)) + ->setParameter("topic", "dr. dolittle"); + + $result = $q->getResult(); + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[0]); + $this->assertEquals("dr. dolittle", $result[0]->topic); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $result[0]->user); + $this->assertFalse($result[0]->user->__isInitialized__); + } + + /** + * @group DDC-952 + */ + public function testEnableFetchEagerMode() + { + for ($i = 0; $i < 10; $i++) { + $article = new CmsArticle; + $article->topic = "dr. dolittle"; + $article->text = "Once upon a time ..."; + $author = new CmsUser; + $author->name = "anonymous"; + $author->username = "anon".$i; + $author->status = "here"; + $article->user = $author; + $this->_em->persist($author); + $this->_em->persist($article); + } + $this->_em->flush(); + $this->_em->clear(); + + $articles = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a') + ->setFetchMode('Doctrine\Tests\Models\CMS\CmsArticle', 'user', ClassMetadata::FETCH_EAGER) + ->getResult(); + + $this->assertEquals(10, count($articles)); + foreach ($articles AS $article) { + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $article); + } + } + + /** + * @group DDC-991 + */ + public function testgetOneOrNullResult() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = 'gblanco'"); + + $fetchedUser = $query->getOneOrNullResult(); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $fetchedUser); + $this->assertEquals('gblanco', $fetchedUser->username); + + $query = $this->_em->createQuery("select u.username from Doctrine\Tests\Models\CMS\CmsUser u where u.username = 'gblanco'"); + $fetchedUsername = $query->getOneOrNullResult(Query::HYDRATE_SINGLE_SCALAR); + $this->assertEquals('gblanco', $fetchedUsername); + } + + /** + * @group DDC-991 + */ + public function testgetOneOrNullResultSeveralRows() + { + $user = new CmsUser; + $user->name = 'Guilherme'; + $user->username = 'gblanco'; + $user->status = 'developer'; + $this->_em->persist($user); + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'developer'; + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u"); + + $this->setExpectedException('Doctrine\ORM\NonUniqueResultException'); + $fetchedUser = $query->getOneOrNullResult(); + } + + /** + * @group DDC-991 + */ + public function testgetOneOrNullResultNoRows() + { + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u"); + $this->assertNull($query->getOneOrNullResult()); + + $query = $this->_em->createQuery("select u.username from Doctrine\Tests\Models\CMS\CmsUser u where u.username = 'gblanco'"); + $this->assertNull($query->getOneOrNullResult(Query::HYDRATE_SCALAR)); + } + + /** + * @group DBAL-171 + */ + public function testParameterOrder() + { + $user1 = new CmsUser; + $user1->name = 'Benjamin'; + $user1->username = 'beberlei'; + $user1->status = 'developer'; + $this->_em->persist($user1); + + $user2 = new CmsUser; + $user2->name = 'Roman'; + $user2->username = 'romanb'; + $user2->status = 'developer'; + $this->_em->persist($user2); + + $user3 = new CmsUser; + $user3->name = 'Jonathan'; + $user3->username = 'jwage'; + $user3->status = 'developer'; + $this->_em->persist($user3); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.status = :a AND u.id IN (:b)"); + $query->setParameters(new ArrayCollection(array( + new Parameter('b', array($user1->id, $user2->id, $user3->id)), + new Parameter('a', 'developer') + ))); + $result = $query->getResult(); + + $this->assertEquals(3, count($result)); + } + + public function testDqlWithAutoInferOfParameters() + { + $user = new CmsUser; + $user->name = 'Benjamin'; + $user->username = 'beberlei'; + $user->status = 'developer'; + $this->_em->persist($user); + + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'developer'; + $this->_em->persist($user); + + $user = new CmsUser; + $user->name = 'Jonathan'; + $user->username = 'jwage'; + $user->status = 'developer'; + $this->_em->persist($user); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username IN (?0)"); + $query->setParameter(0, array('beberlei', 'jwage')); + + $users = $query->execute(); + + $this->assertEquals(2, count($users)); + } + + public function testQueryBuilderWithStringWhereClauseContainingOrAndConditionalPrimary() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->innerJoin('u.articles', 'a') + ->where('(u.id = 0) OR (u.id IS NULL)'); + + $query = $qb->getQuery(); + $users = $query->execute(); + + $this->assertEquals(0, count($users)); + } + + public function testQueryWithArrayOfEntitiesAsParameter() + { + $userA = new CmsUser; + $userA->name = 'Benjamin'; + $userA->username = 'beberlei'; + $userA->status = 'developer'; + $this->_em->persist($userA); + + $userB = new CmsUser; + $userB->name = 'Roman'; + $userB->username = 'romanb'; + $userB->status = 'developer'; + $this->_em->persist($userB); + + $userC = new CmsUser; + $userC->name = 'Jonathan'; + $userC->username = 'jwage'; + $userC->status = 'developer'; + $this->_em->persist($userC); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u IN (?0) OR u.username = ?1"); + $query->setParameter(0, array($userA, $userC)); + $query->setParameter(1, 'beberlei'); + + $users = $query->execute(); + + $this->assertEquals(2, count($users)); + } + + public function testQueryWithHiddenAsSelectExpression() + { + $userA = new CmsUser; + $userA->name = 'Benjamin'; + $userA->username = 'beberlei'; + $userA->status = 'developer'; + $this->_em->persist($userA); + + $userB = new CmsUser; + $userB->name = 'Roman'; + $userB->username = 'romanb'; + $userB->status = 'developer'; + $this->_em->persist($userB); + + $userC = new CmsUser; + $userC->name = 'Jonathan'; + $userC->username = 'jwage'; + $userC->status = 'developer'; + $this->_em->persist($userC); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery("SELECT u, (SELECT COUNT(u2.id) FROM Doctrine\Tests\Models\CMS\CmsUser u2) AS HIDDEN total FROM Doctrine\Tests\Models\CMS\CmsUser u"); + $users = $query->execute(); + + $this->assertEquals(3, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); + } + + /** + * @group DDC-1651 + */ + public function testSetParameterBindingSingleIdentifierObject() + { + $userC = new CmsUser; + $userC->name = 'Jonathan'; + $userC->username = 'jwage'; + $userC->status = 'developer'; + $this->_em->persist($userC); + + $this->_em->flush(); + $this->_em->clear(); + + $q = $this->_em->createQuery("SELECT DISTINCT u from Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1"); + $q->setParameter(1, $userC); + + $this->assertEquals($userC, $q->getParameter(1)->getValue()); + + // Parameter is not converted before, but it should be converted during execution. Test should not fail here + $q->getResult(); + } + + + /** + * @group DDC-1822 + */ + public function testUnexpectedResultException() + { + $dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u"; + $u1 = new CmsUser; + $u2 = new CmsUser; + $u1->name = 'Fabio B. Silva'; + $u1->username = 'FabioBatSilva'; + $u1->status = 'developer'; + $u2->name = 'Test'; + $u2->username = 'test'; + $u2->status = 'tester'; + + try { + $this->_em->createQuery($dql)->getSingleResult(); + $this->fail('Expected exception "\Doctrine\ORM\NoResultException".'); + } catch (\Doctrine\ORM\UnexpectedResultException $exc) { + $this->assertInstanceOf('\Doctrine\ORM\NoResultException', $exc); + } + + + $this->_em->persist($u1); + $this->_em->persist($u2); + $this->_em->flush(); + $this->_em->clear(); + + try { + $this->_em->createQuery($dql)->getSingleResult(); + $this->fail('Expected exception "\Doctrine\ORM\NonUniqueResultException".'); + } catch (\Doctrine\ORM\UnexpectedResultException $exc) { + $this->assertInstanceOf('\Doctrine\ORM\NonUniqueResultException', $exc); + } + } + + public function testMultipleJoinComponentsUsingInnerJoin() + { + $userA = new CmsUser; + $userA->name = 'Benjamin'; + $userA->username = 'beberlei'; + $userA->status = 'developer'; + + $phonenumberA = new CmsPhonenumber; + $phonenumberA->phonenumber = '111111'; + $userA->addPhonenumber($phonenumberA); + + $userB = new CmsUser; + $userB->name = 'Alexander'; + $userB->username = 'asm89'; + $userB->status = 'developer'; + + $this->_em->persist($userA); + $this->_em->persist($userB); + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery(" + SELECT u, p + FROM Doctrine\Tests\Models\CMS\CmsUser u + INNER JOIN Doctrine\Tests\Models\CMS\CmsPhonenumber p WITH u = p.user + "); + $users = $query->execute(); + + $this->assertEquals(2, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $users[1]); + } + + public function testMultipleJoinComponentsUsingLeftJoin() + { + $userA = new CmsUser; + $userA->name = 'Benjamin'; + $userA->username = 'beberlei'; + $userA->status = 'developer'; + + $phonenumberA = new CmsPhonenumber; + $phonenumberA->phonenumber = '111111'; + $userA->addPhonenumber($phonenumberA); + + $userB = new CmsUser; + $userB->name = 'Alexander'; + $userB->username = 'asm89'; + $userB->status = 'developer'; + + $this->_em->persist($userA); + $this->_em->persist($userB); + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery(" + SELECT u, p + FROM Doctrine\Tests\Models\CMS\CmsUser u + LEFT JOIN Doctrine\Tests\Models\CMS\CmsPhonenumber p WITH u = p.user + "); + $users = $query->execute(); + + $this->assertEquals(4, count($users)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $users[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[2]); + $this->assertNull($users[3]); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ReadOnlyTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ReadOnlyTest.php new file mode 100644 index 0000000..2519a9c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ReadOnlyTest.php @@ -0,0 +1,94 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\ReadOnlyEntity'), + )); + } catch(\Exception $e) { + } + } + + public function testReadOnlyEntityNeverChangeTracked() + { + $readOnly = new ReadOnlyEntity("Test1", 1234); + $this->_em->persist($readOnly); + $this->_em->flush(); + + $readOnly->name = "Test2"; + $readOnly->numericValue = 4321; + + $this->_em->flush(); + $this->_em->clear(); + + $dbReadOnly = $this->_em->find('Doctrine\Tests\ORM\Functional\ReadOnlyEntity', $readOnly->id); + $this->assertEquals("Test1", $dbReadOnly->name); + $this->assertEquals(1234, $dbReadOnly->numericValue); + } + + /** + * @group DDC-1659 + */ + public function testClearReadOnly() + { + $readOnly = new ReadOnlyEntity("Test1", 1234); + $this->_em->persist($readOnly); + $this->_em->flush(); + $this->_em->getUnitOfWork()->markReadOnly($readOnly); + + $this->_em->clear(); + + $this->assertFalse($this->_em->getUnitOfWork()->isReadOnly($readOnly)); + } + + /** + * @group DDC-1659 + */ + public function testClearEntitiesReadOnly() + { + $readOnly = new ReadOnlyEntity("Test1", 1234); + $this->_em->persist($readOnly); + $this->_em->flush(); + $this->_em->getUnitOfWork()->markReadOnly($readOnly); + + $this->_em->clear(get_class($readOnly)); + + $this->assertFalse($this->_em->getUnitOfWork()->isReadOnly($readOnly)); + } +} + +/** + * @Entity(readOnly=true) + */ +class ReadOnlyEntity +{ + /** + * @Id @GeneratedValue @Column(type="integer") + * @var int + */ + public $id; + /** @column(type="string") */ + public $name; + /** @Column(type="integer") */ + public $numericValue; + + public function __construct($name, $number) + { + $this->name = $name; + $this->numericValue = $number; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php new file mode 100644 index 0000000..3ce24e7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php @@ -0,0 +1,250 @@ + + * @author Benjamin Eberlei + */ +class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + protected function setUp() + { + $this->useModelSet('ecommerce'); + parent::setUp(); + $this->_factory = new ProxyFactory( + $this->_em, + __DIR__ . '/../../Proxies', + 'Doctrine\Tests\Proxies', + true); + } + + public function createProduct() + { + $product = new ECommerceProduct(); + $product->setName('Doctrine Cookbook'); + $this->_em->persist($product); + + $this->_em->flush(); + $this->_em->clear(); + + return $product->getId(); + } + + public function createAuction() + { + $event = new CompanyAuction(); + $event->setData('Doctrine Cookbook'); + $this->_em->persist($event); + + $this->_em->flush(); + $this->_em->clear(); + + return $event->getId(); + } + + public function testLazyLoadsFieldValuesFromDatabase() + { + $id = $this->createProduct(); + + $productProxy = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct', array('id' => $id)); + $this->assertEquals('Doctrine Cookbook', $productProxy->getName()); + } + + /** + * @group DDC-727 + */ + public function testAccessMetatadaForProxy() + { + $id = $this->createProduct(); + + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + $class = $this->_em->getClassMetadata(get_class($entity)); + + $this->assertEquals('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $class->name); + } + + /** + * @group DDC-1033 + */ + public function testReferenceFind() + { + $id = $this->createProduct(); + + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + $entity2 = $this->_em->find('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + + $this->assertSame($entity, $entity2); + $this->assertEquals('Doctrine Cookbook', $entity2->getName()); + } + + /** + * @group DDC-1033 + */ + public function testCloneProxy() + { + $id = $this->createProduct(); + + /* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */ + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + + /* @var $clone Doctrine\Tests\Models\ECommerce\ECommerceProduct */ + $clone = clone $entity; + + $this->assertEquals($id, $entity->getId()); + $this->assertEquals('Doctrine Cookbook', $entity->getName()); + + $this->assertFalse($this->_em->contains($clone), "Cloning a reference proxy should return an unmanaged/detached entity."); + $this->assertEquals($id, $clone->getId(), "Cloning a reference proxy should return same id."); + $this->assertEquals('Doctrine Cookbook', $clone->getName(), "Cloning a reference proxy should return same product name."); + + // domain logic, Product::__clone sets isCloned public property + $this->assertTrue($clone->isCloned); + $this->assertFalse($entity->isCloned); + } + + /** + * @group DDC-733 + */ + public function testInitializeProxy() + { + $id = $this->createProduct(); + + /* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */ + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + + $this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy."); + $this->_em->getUnitOfWork()->initializeObject($entity); + $this->assertTrue($entity->__isInitialized__, "Should be initialized after called UnitOfWork::initializeObject()"); + } + + /** + * @group DDC-1163 + */ + public function testInitializeChangeAndFlushProxy() + { + $id = $this->createProduct(); + + /* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */ + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + $entity->setName('Doctrine 2 Cookbook'); + + $this->_em->flush(); + $this->_em->clear(); + + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + $this->assertEquals('Doctrine 2 Cookbook', $entity->getName()); + } + + /** + * @group DDC-1022 + */ + public function testWakeupCalledOnProxy() + { + $id = $this->createProduct(); + + /* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */ + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + + $this->assertFalse($entity->wakeUp); + + $entity->setName('Doctrine 2 Cookbook'); + + $this->assertTrue($entity->wakeUp, "Loading the proxy should call __wakeup()."); + } + + public function testDoNotInitializeProxyOnGettingTheIdentifier() + { + $id = $this->createProduct(); + + /* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */ + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + + $this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy."); + $this->assertEquals($id, $entity->getId()); + $this->assertFalse($entity->__isInitialized__, "Getting the identifier doesn't initialize the proxy."); + } + + /** + * @group DDC-1625 + */ + public function testDoNotInitializeProxyOnGettingTheIdentifier_DDC_1625() + { + $id = $this->createAuction(); + + /* @var $entity Doctrine\Tests\Models\Company\CompanyAuction */ + $entity = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyAuction' , $id); + + $this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy."); + $this->assertEquals($id, $entity->getId()); + $this->assertFalse($entity->__isInitialized__, "Getting the identifier doesn't initialize the proxy when extending."); + } + + public function testDoNotInitializeProxyOnGettingTheIdentifierAndReturnTheRightType() + { + $product = new ECommerceProduct(); + $product->setName('Doctrine Cookbook'); + + $shipping = new ECommerceShipping(); + $shipping->setDays(1); + $product->setShipping($shipping); + $this->_em->persist($product); + $this->_em->flush(); + $this->_em->clear(); + + $id = $shipping->getId(); + + $product = $this->_em->getRepository('Doctrine\Tests\Models\ECommerce\ECommerceProduct')->find($product->getId()); + + $entity = $product->getShipping(); + $this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy."); + $this->assertEquals($id, $entity->getId()); + $this->assertSame($id, $entity->getId(), "Check that the id's are the same value, and type."); + $this->assertFalse($entity->__isInitialized__, "Getting the identifier doesn't initialize the proxy."); + } + + public function testInitializeProxyOnGettingSomethingOtherThanTheIdentifier() + { + $id = $this->createProduct(); + + /* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */ + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + + $this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy."); + $this->assertEquals('Doctrine Cookbook', $entity->getName()); + $this->assertTrue($entity->__isInitialized__, "Getting something other than the identifier initializes the proxy."); + } + + /** + * @group DDC-1604 + */ + public function testCommonPersistenceProxy() + { + $id = $this->createProduct(); + + /* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */ + $entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id); + $className = \Doctrine\Common\Util\ClassUtils::getClass($entity); + + $this->assertInstanceOf('Doctrine\Common\Persistence\Proxy', $entity); + $this->assertFalse($entity->__isInitialized()); + $this->assertEquals('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $className); + + $restName = str_replace($this->_em->getConfiguration()->getProxyNamespace(), "", get_class($entity)); + $restName = substr(get_class($entity), strlen($this->_em->getConfiguration()->getProxyNamespace()) +1); + $proxyFileName = $this->_em->getConfiguration()->getProxyDir() . DIRECTORY_SEPARATOR . str_replace("\\", "", $restName) . ".php"; + $this->assertTrue(file_exists($proxyFileName), "Proxy file name cannot be found generically."); + + $entity->__load(); + $this->assertTrue($entity->__isInitialized()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ResultCacheTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ResultCacheTest.php new file mode 100644 index 0000000..5846d92 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/ResultCacheTest.php @@ -0,0 +1,254 @@ +cacheDataReflection = new \ReflectionProperty("Doctrine\Common\Cache\ArrayCache", "data"); + $this->cacheDataReflection->setAccessible(true); + $this->useModelSet('cms'); + parent::setUp(); + } + + /** + * @param ArrayCache $cache + * @return integer + */ + private function getCacheSize(ArrayCache $cache) + { + return sizeof($this->cacheDataReflection->getValue($cache)); + } + + public function testResultCache() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'dev'; + $this->_em->persist($user); + $this->_em->flush(); + + + $query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux'); + + $cache = new ArrayCache(); + + $query->setResultCacheDriver($cache)->setResultCacheId('my_cache_id'); + + $this->assertFalse($cache->contains('my_cache_id')); + + $users = $query->getResult(); + + $this->assertTrue($cache->contains('my_cache_id')); + $this->assertEquals(1, count($users)); + $this->assertEquals('Roman', $users[0]->name); + + $this->_em->clear(); + + $query2 = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux'); + $query2->setResultCacheDriver($cache)->setResultCacheId('my_cache_id'); + + $users = $query2->getResult(); + + $this->assertTrue($cache->contains('my_cache_id')); + $this->assertEquals(1, count($users)); + $this->assertEquals('Roman', $users[0]->name); + } + + public function testSetResultCacheId() + { + $cache = new ArrayCache; + + $query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux'); + $query->setResultCacheDriver($cache); + $query->setResultCacheId('testing_result_cache_id'); + + $this->assertFalse($cache->contains('testing_result_cache_id')); + + $users = $query->getResult(); + + $this->assertTrue($cache->contains('testing_result_cache_id')); + } + + public function testUseResultCache() + { + $cache = new \Doctrine\Common\Cache\ArrayCache(); + + $query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux'); + $query->useResultCache(true); + $query->setResultCacheDriver($cache); + $query->setResultCacheId('testing_result_cache_id'); + $users = $query->getResult(); + + $this->assertTrue($cache->contains('testing_result_cache_id')); + + $this->_em->getConfiguration()->setResultCacheImpl(new ArrayCache()); + } + + /** + * @group DDC-1026 + */ + public function testUseResultCacheParams() + { + $cache = new \Doctrine\Common\Cache\ArrayCache(); + + $sqlCount = count($this->_sqlLoggerStack->queries); + $query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux WHERE ux.id = ?1'); + $query->setParameter(1, 1); + $query->setResultCacheDriver($cache); + $query->useResultCache(true); + $query->getResult(); + + $query->setParameter(1, 2); + $query->getResult(); + + $this->assertEquals($sqlCount + 2, count($this->_sqlLoggerStack->queries), "Two non-cached queries."); + + $query->setParameter(1, 1); + $query->useResultCache(true); + $query->getResult(); + + $query->setParameter(1, 2); + $query->getResult(); + + $this->assertEquals($sqlCount + 2, count($this->_sqlLoggerStack->queries), "The next two sql should have been cached, but were not."); + } + + public function testNativeQueryResultCaching() + { + $rsm = new \Doctrine\ORM\Query\ResultSetMapping(); + $rsm->addScalarResult('id', 'u'); + $query = $this->_em->createNativeQuery('select u.id FROM cms_users u WHERE u.id = ?', $rsm); + $query->setParameter(1, 10); + + $cache = new ArrayCache(); + $query->setResultCacheDriver($cache)->useResultCache(true); + + $this->assertEquals(0, $this->getCacheSize($cache)); + $query->getResult(); + $this->assertEquals(2, $this->getCacheSize($cache)); + + return $query; + } + + /** + * @param string $query + * @depends testNativeQueryResultCaching + */ + public function testResultCacheNotDependsOnQueryHints($query) + { + $cache = $query->getResultCacheDriver(); + $cacheCount = $this->getCacheSize($cache); + + $query->setHint('foo', 'bar'); + $query->getResult(); + + $this->assertEquals($cacheCount, $this->getCacheSize($cache)); + } + + /** + * @param $query + * @depends testNativeQueryResultCaching + */ + public function testResultCacheDependsOnParameters($query) + { + $cache = $query->getResultCacheDriver(); + $cacheCount = $this->getCacheSize($cache); + + $query->setParameter(1, 50); + $query->getResult(); + + $this->assertEquals($cacheCount + 1, $this->getCacheSize($cache)); + } + + /** + * @param $query + * @depends testNativeQueryResultCaching + */ + public function testResultCacheNotDependsOnHydrationMode($query) + { + $cache = $query->getResultCacheDriver(); + $cacheCount = $this->getCacheSize($cache); + + $this->assertNotEquals(\Doctrine\ORM\Query::HYDRATE_ARRAY, $query->getHydrationMode()); + $query->getArrayResult(); + + $this->assertEquals($cacheCount, $this->getCacheSize($cache)); + } + + /** + * @group DDC-909 + */ + public function testResultCacheWithObjectParameter() + { + $user1 = new CmsUser; + $user1->name = 'Roman'; + $user1->username = 'romanb'; + $user1->status = 'dev'; + + $user2 = new CmsUser; + $user2->name = 'Benjamin'; + $user2->username = 'beberlei'; + $user2->status = 'dev'; + + $article = new CmsArticle(); + $article->text = "foo"; + $article->topic = "baz"; + $article->user = $user1; + + $this->_em->persist($article); + $this->_em->persist($user1); + $this->_em->persist($user2); + $this->_em->flush(); + + $query = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.user = ?1'); + $query->setParameter(1, $user1); + + $cache = new ArrayCache(); + + $query->setResultCacheDriver($cache)->useResultCache(true); + + $articles = $query->getResult(); + + $this->assertEquals(1, count($articles)); + $this->assertEquals('baz', $articles[0]->topic); + + $this->_em->clear(); + + $query2 = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.user = ?1'); + $query2->setParameter(1, $user1); + + $query2->setResultCacheDriver($cache)->useResultCache(true); + + $articles = $query2->getResult(); + + $this->assertEquals(1, count($articles)); + $this->assertEquals('baz', $articles[0]->topic); + + $query3 = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.user = ?1'); + $query3->setParameter(1, $user2); + + $query3->setResultCacheDriver($cache)->useResultCache(true); + + $articles = $query3->getResult(); + + $this->assertEquals(0, count($articles)); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php new file mode 100644 index 0000000..82c2409 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php @@ -0,0 +1,1121 @@ + + */ +class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + private $userId, $userId2, $articleId, $articleId2; + private $groupId, $groupId2; + private $managerId, $managerId2, $contractId1, $contractId2; + private $organizationId, $eventId1, $eventId2; + + public function setUp() + { + $this->useModelSet('cms'); + $this->useModelSet('company'); + parent::setUp(); + } + + public function tearDown() + { + parent::tearDown(); + + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + } + + public function testConfigureFilter() + { + $config = new \Doctrine\ORM\Configuration(); + + $config->addFilter("locale", "\Doctrine\Tests\ORM\Functional\MyLocaleFilter"); + + $this->assertEquals("\Doctrine\Tests\ORM\Functional\MyLocaleFilter", $config->getFilterClassName("locale")); + $this->assertNull($config->getFilterClassName("foo")); + } + + public function testEntityManagerEnableFilter() + { + $em = $this->_getEntityManager(); + $this->configureFilters($em); + + // Enable an existing filter + $filter = $em->getFilters()->enable("locale"); + $this->assertTrue($filter instanceof \Doctrine\Tests\ORM\Functional\MyLocaleFilter); + + // Enable the filter again + $filter2 = $em->getFilters()->enable("locale"); + $this->assertEquals($filter, $filter2); + + // Enable a non-existing filter + $exceptionThrown = false; + try { + $filter = $em->getFilters()->enable("foo"); + } catch (\InvalidArgumentException $e) { + $exceptionThrown = true; + } + $this->assertTrue($exceptionThrown); + } + + public function testEntityManagerEnabledFilters() + { + $em = $this->_getEntityManager(); + + // No enabled filters + $this->assertEquals(array(), $em->getFilters()->getEnabledFilters()); + + $this->configureFilters($em); + $filter = $em->getFilters()->enable("locale"); + $filter = $em->getFilters()->enable("soft_delete"); + + // Two enabled filters + $this->assertEquals(2, count($em->getFilters()->getEnabledFilters())); + + } + + public function testEntityManagerDisableFilter() + { + $em = $this->_getEntityManager(); + $this->configureFilters($em); + + // Enable the filter + $filter = $em->getFilters()->enable("locale"); + + // Disable it + $this->assertEquals($filter, $em->getFilters()->disable("locale")); + $this->assertEquals(0, count($em->getFilters()->getEnabledFilters())); + + // Disable a non-existing filter + $exceptionThrown = false; + try { + $filter = $em->getFilters()->disable("foo"); + } catch (\InvalidArgumentException $e) { + $exceptionThrown = true; + } + $this->assertTrue($exceptionThrown); + + // Disable a non-enabled filter + $exceptionThrown = false; + try { + $filter = $em->getFilters()->disable("locale"); + } catch (\InvalidArgumentException $e) { + $exceptionThrown = true; + } + $this->assertTrue($exceptionThrown); + } + + public function testEntityManagerGetFilter() + { + $em = $this->_getEntityManager(); + $this->configureFilters($em); + + // Enable the filter + $filter = $em->getFilters()->enable("locale"); + + // Get the filter + $this->assertEquals($filter, $em->getFilters()->getFilter("locale")); + + // Get a non-enabled filter + $exceptionThrown = false; + try { + $filter = $em->getFilters()->getFilter("soft_delete"); + } catch (\InvalidArgumentException $e) { + $exceptionThrown = true; + } + $this->assertTrue($exceptionThrown); + } + + protected function configureFilters($em) + { + // Add filters to the configuration of the EM + $config = $em->getConfiguration(); + $config->addFilter("locale", "\Doctrine\Tests\ORM\Functional\MyLocaleFilter"); + $config->addFilter("soft_delete", "\Doctrine\Tests\ORM\Functional\MySoftDeleteFilter"); + } + + protected function getMockConnection() + { + // Setup connection mock + $conn = $this->getMockBuilder('Doctrine\DBAL\Connection') + ->disableOriginalConstructor() + ->getMock(); + + return $conn; + } + + protected function getMockEntityManager() + { + // Setup connection mock + $em = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->getMock(); + + return $em; + } + + protected function addMockFilterCollection($em) + { + $filterCollection = $this->getMockBuilder('Doctrine\ORM\Query\FilterCollection') + ->disableOriginalConstructor() + ->getMock(); + + $em->expects($this->any()) + ->method('getFilters') + ->will($this->returnValue($filterCollection)); + + return $filterCollection; + } + + public function testSQLFilterGetSetParameter() + { + // Setup mock connection + $conn = $this->getMockConnection(); + $conn->expects($this->once()) + ->method('quote') + ->with($this->equalTo('en')) + ->will($this->returnValue("'en'")); + + $em = $this->getMockEntityManager($conn); + $em->expects($this->once()) + ->method('getConnection') + ->will($this->returnValue($conn)); + + $filterCollection = $this->addMockFilterCollection($em); + $filterCollection + ->expects($this->once()) + ->method('setFiltersStateDirty'); + + $filter = new MyLocaleFilter($em); + + $filter->setParameter('locale', 'en', DBALType::STRING); + + $this->assertEquals("'en'", $filter->getParameter('locale')); + } + + public function testSQLFilterSetParameterInfersType() + { + // Setup mock connection + $conn = $this->getMockConnection(); + $conn->expects($this->once()) + ->method('quote') + ->with($this->equalTo('en')) + ->will($this->returnValue("'en'")); + + $em = $this->getMockEntityManager($conn); + $em->expects($this->once()) + ->method('getConnection') + ->will($this->returnValue($conn)); + + $filterCollection = $this->addMockFilterCollection($em); + $filterCollection + ->expects($this->once()) + ->method('setFiltersStateDirty'); + + $filter = new MyLocaleFilter($em); + + $filter->setParameter('locale', 'en'); + + $this->assertEquals("'en'", $filter->getParameter('locale')); + } + + public function testSQLFilterAddConstraint() + { + // Set up metadata mock + $targetEntity = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata') + ->disableOriginalConstructor() + ->getMock(); + + $filter = new MySoftDeleteFilter($this->getMockEntityManager()); + + // Test for an entity that gets extra filter data + $targetEntity->name = 'MyEntity\SoftDeleteNewsItem'; + $this->assertEquals('t1_.deleted = 0', $filter->addFilterConstraint($targetEntity, 't1_')); + + // Test for an entity that doesn't get extra filter data + $targetEntity->name = 'MyEntity\NoSoftDeleteNewsItem'; + $this->assertEquals('', $filter->addFilterConstraint($targetEntity, 't1_')); + + } + + public function testSQLFilterToString() + { + $em = $this->getMockEntityManager(); + $filterCollection = $this->addMockFilterCollection($em); + + $filter = new MyLocaleFilter($em); + $filter->setParameter('locale', 'en', DBALType::STRING); + $filter->setParameter('foo', 'bar', DBALType::STRING); + + $filter2 = new MyLocaleFilter($em); + $filter2->setParameter('foo', 'bar', DBALType::STRING); + $filter2->setParameter('locale', 'en', DBALType::STRING); + + $parameters = array( + 'foo' => array('value' => 'bar', 'type' => DBALType::STRING), + 'locale' => array('value' => 'en', 'type' => DBALType::STRING), + ); + + $this->assertEquals(serialize($parameters), ''.$filter); + $this->assertEquals(''.$filter, ''.$filter2); + } + + public function testQueryCache_DependsOnFilters() + { + $cacheDataReflection = new \ReflectionProperty("Doctrine\Common\Cache\ArrayCache", "data"); + $cacheDataReflection->setAccessible(true); + + $query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux'); + + $cache = new ArrayCache(); + $query->setQueryCacheDriver($cache); + + $query->getResult(); + $this->assertEquals(2, sizeof($cacheDataReflection->getValue($cache))); + + $conf = $this->_em->getConfiguration(); + $conf->addFilter("locale", "\Doctrine\Tests\ORM\Functional\MyLocaleFilter"); + $this->_em->getFilters()->enable("locale"); + + $query->getResult(); + $this->assertEquals(3, sizeof($cacheDataReflection->getValue($cache))); + + // Another time doesn't add another cache entry + $query->getResult(); + $this->assertEquals(3, sizeof($cacheDataReflection->getValue($cache))); + } + + public function testQueryGeneration_DependsOnFilters() + { + $query = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsAddress a'); + $firstSQLQuery = $query->getSQL(); + + $conf = $this->_em->getConfiguration(); + $conf->addFilter("country", "\Doctrine\Tests\ORM\Functional\CMSCountryFilter"); + $this->_em->getFilters()->enable("country") + ->setParameter("country", "en", DBALType::STRING); + + $this->assertNotEquals($firstSQLQuery, $query->getSQL()); + } + + public function testRepositoryFind() + { + $this->loadFixtureData(); + + $this->assertNotNull($this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->find($this->groupId)); + $this->assertNotNull($this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->find($this->groupId2)); + + $this->useCMSGroupPrefixFilter(); + $this->_em->clear(); + + $this->assertNotNull($this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->find($this->groupId)); + $this->assertNull($this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->find($this->groupId2)); + } + + public function testRepositoryFindAll() + { + $this->loadFixtureData(); + + $this->assertCount(2, $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll()); + + $this->useCMSGroupPrefixFilter(); + $this->_em->clear(); + + $this->assertCount(1, $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll()); + } + + public function testRepositoryFindBy() + { + $this->loadFixtureData(); + + $this->assertCount(1, $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findBy(array('id' => $this->groupId2))); + + $this->useCMSGroupPrefixFilter(); + $this->_em->clear(); + + $this->assertCount(0, $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findBy(array('id' => $this->groupId2))); + } + + public function testRepositoryFindByX() + { + $this->loadFixtureData(); + + $this->assertCount(1, $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findById($this->groupId2)); + + $this->useCMSGroupPrefixFilter(); + $this->_em->clear(); + + $this->assertCount(0, $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findById($this->groupId2)); + } + + public function testRepositoryFindOneBy() + { + $this->loadFixtureData(); + + $this->assertNotNull($this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findOneBy(array('id' => $this->groupId2))); + + $this->useCMSGroupPrefixFilter(); + $this->_em->clear(); + + $this->assertNull($this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findOneBy(array('id' => $this->groupId2))); + } + + public function testRepositoryFindOneByX() + { + $this->loadFixtureData(); + + $this->assertNotNull($this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findOneById($this->groupId2)); + + $this->useCMSGroupPrefixFilter(); + $this->_em->clear(); + + $this->assertNull($this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findOneById($this->groupId2)); + } + + public function testToOneFilter() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->loadFixtureData(); + + $query = $this->_em->createQuery('select ux, ua from Doctrine\Tests\Models\CMS\CmsUser ux JOIN ux.address ua'); + + // We get two users before enabling the filter + $this->assertEquals(2, count($query->getResult())); + + $conf = $this->_em->getConfiguration(); + $conf->addFilter("country", "\Doctrine\Tests\ORM\Functional\CMSCountryFilter"); + $this->_em->getFilters()->enable("country")->setParameter("country", "Germany", DBALType::STRING); + + // We get one user after enabling the filter + $this->assertEquals(1, count($query->getResult())); + } + + public function testManyToManyFilter() + { + $this->loadFixtureData(); + $query = $this->_em->createQuery('select ux, ug from Doctrine\Tests\Models\CMS\CmsUser ux JOIN ux.groups ug'); + + // We get two users before enabling the filter + $this->assertEquals(2, count($query->getResult())); + + $conf = $this->_em->getConfiguration(); + $conf->addFilter("group_prefix", "\Doctrine\Tests\ORM\Functional\CMSGroupPrefixFilter"); + $this->_em->getFilters()->enable("group_prefix")->setParameter("prefix", "bar_%", DBALType::STRING); + + // We get one user after enabling the filter + $this->assertEquals(1, count($query->getResult())); + + } + + public function testWhereFilter() + { + $this->loadFixtureData(); + $query = $this->_em->createQuery('select ug from Doctrine\Tests\Models\CMS\CmsGroup ug WHERE 1=1'); + + // We get two users before enabling the filter + $this->assertEquals(2, count($query->getResult())); + + $conf = $this->_em->getConfiguration(); + $conf->addFilter("group_prefix", "\Doctrine\Tests\ORM\Functional\CMSGroupPrefixFilter"); + $this->_em->getFilters()->enable("group_prefix")->setParameter("prefix", "bar_%", DBALType::STRING); + + // We get one user after enabling the filter + $this->assertEquals(1, count($query->getResult())); + } + + + private function loadLazyFixtureData() + { + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $this->loadFixtureData(); + } + + private function useCMSArticleTopicFilter() + { + $conf = $this->_em->getConfiguration(); + $conf->addFilter("article_topic", "\Doctrine\Tests\ORM\Functional\CMSArticleTopicFilter"); + $this->_em->getFilters()->enable("article_topic")->setParameter("topic", "Test1", DBALType::STRING); + } + + public function testOneToMany_ExtraLazyCountWithFilter() + { + $this->loadLazyFixtureData(); + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + + $this->assertFalse($user->articles->isInitialized()); + $this->assertEquals(2, count($user->articles)); + + $this->useCMSArticleTopicFilter(); + + $this->assertEquals(1, count($user->articles)); + } + + public function testOneToMany_ExtraLazyContainsWithFilter() + { + $this->loadLazyFixtureData(); + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + $filteredArticle = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId2); + + $this->assertFalse($user->articles->isInitialized()); + $this->assertTrue($user->articles->contains($filteredArticle)); + + $this->useCMSArticleTopicFilter(); + + $this->assertFalse($user->articles->contains($filteredArticle)); + } + + public function testOneToMany_ExtraLazySliceWithFilter() + { + $this->loadLazyFixtureData(); + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + + $this->assertFalse($user->articles->isInitialized()); + $this->assertEquals(2, count($user->articles->slice(0,10))); + + $this->useCMSArticleTopicFilter(); + + $this->assertEquals(1, count($user->articles->slice(0,10))); + } + + private function useCMSGroupPrefixFilter() + { + $conf = $this->_em->getConfiguration(); + $conf->addFilter("group_prefix", "\Doctrine\Tests\ORM\Functional\CMSGroupPrefixFilter"); + $this->_em->getFilters()->enable("group_prefix")->setParameter("prefix", "foo%", DBALType::STRING); + } + + public function testManyToMany_ExtraLazyCountWithFilter() + { + $this->loadLazyFixtureData(); + + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId2); + + $this->assertFalse($user->groups->isInitialized()); + $this->assertEquals(2, count($user->groups)); + + $this->useCMSGroupPrefixFilter(); + + $this->assertEquals(1, count($user->groups)); + } + + public function testManyToMany_ExtraLazyContainsWithFilter() + { + $this->loadLazyFixtureData(); + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId2); + $filteredArticle = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId2); + + $this->assertFalse($user->groups->isInitialized()); + $this->assertTrue($user->groups->contains($filteredArticle)); + + $this->useCMSGroupPrefixFilter(); + + $this->assertFalse($user->groups->contains($filteredArticle)); + } + + public function testManyToMany_ExtraLazySliceWithFilter() + { + $this->loadLazyFixtureData(); + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId2); + + $this->assertFalse($user->groups->isInitialized()); + $this->assertEquals(2, count($user->groups->slice(0,10))); + + $this->useCMSGroupPrefixFilter(); + + $this->assertEquals(1, count($user->groups->slice(0,10))); + } + + private function loadFixtureData() + { + $user = new CmsUser; + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'developer'; + + $address = new CmsAddress; + $address->country = 'Germany'; + $address->city = 'Berlin'; + $address->zip = '12345'; + + $user->address = $address; // inverse side + $address->user = $user; // owning side! + + $group = new CmsGroup; + $group->name = 'foo_group'; + $user->addGroup($group); + + $article1 = new CmsArticle; + $article1->topic = "Test1"; + $article1->text = "Test"; + $article1->setAuthor($user); + + $article2 = new CmsArticle; + $article2->topic = "Test2"; + $article2->text = "Test"; + $article2->setAuthor($user); + + $this->_em->persist($article1); + $this->_em->persist($article2); + + $this->_em->persist($user); + + $user2 = new CmsUser; + $user2->name = 'Guilherme'; + $user2->username = 'gblanco'; + $user2->status = 'developer'; + + $address2 = new CmsAddress; + $address2->country = 'France'; + $address2->city = 'Paris'; + $address2->zip = '12345'; + + $user->address = $address2; // inverse side + $address2->user = $user2; // owning side! + + $user2->addGroup($group); + $group2 = new CmsGroup; + $group2->name = 'bar_group'; + $user2->addGroup($group2); + + $this->_em->persist($user2); + $this->_em->flush(); + $this->_em->clear(); + + $this->userId = $user->getId(); + $this->userId2 = $user2->getId(); + $this->articleId = $article1->id; + $this->articleId2 = $article2->id; + $this->groupId = $group->id; + $this->groupId2 = $group2->id; + } + + public function testJoinSubclassPersister_FilterOnlyOnRootTableWhenFetchingSubEntity() + { + $this->loadCompanyJoinedSubclassFixtureData(); + // Persister + $this->assertEquals(2, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager')->findAll())); + // SQLWalker + $this->assertEquals(2, count($this->_em->createQuery("SELECT cm FROM Doctrine\Tests\Models\Company\CompanyManager cm")->getResult())); + + // Enable the filter + $this->usePersonNameFilter('Guilh%'); + + $managers = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager')->findAll(); + $this->assertEquals(1, count($managers)); + $this->assertEquals("Guilherme", $managers[0]->getName()); + + $this->assertEquals(1, count($this->_em->createQuery("SELECT cm FROM Doctrine\Tests\Models\Company\CompanyManager cm")->getResult())); + } + + public function testJoinSubclassPersister_FilterOnlyOnRootTableWhenFetchingRootEntity() + { + $this->loadCompanyJoinedSubclassFixtureData(); + $this->assertEquals(3, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyPerson')->findAll())); + $this->assertEquals(3, count($this->_em->createQuery("SELECT cp FROM Doctrine\Tests\Models\Company\CompanyPerson cp")->getResult())); + + // Enable the filter + $this->usePersonNameFilter('Guilh%'); + + $persons = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyPerson')->findAll(); + $this->assertEquals(1, count($persons)); + $this->assertEquals("Guilherme", $persons[0]->getName()); + + $this->assertEquals(1, count($this->_em->createQuery("SELECT cp FROM Doctrine\Tests\Models\Company\CompanyPerson cp")->getResult())); + } + + private function loadCompanyJoinedSubclassFixtureData() + { + $manager = new CompanyManager; + $manager->setName('Roman'); + $manager->setTitle('testlead'); + $manager->setSalary(42); + $manager->setDepartment('persisters'); + + $manager2 = new CompanyManager; + $manager2->setName('Guilherme'); + $manager2->setTitle('devlead'); + $manager2->setSalary(42); + $manager2->setDepartment('parsers'); + + $person = new CompanyPerson; + $person->setName('Benjamin'); + + $this->_em->persist($manager); + $this->_em->persist($manager2); + $this->_em->persist($person); + $this->_em->flush(); + $this->_em->clear(); + } + + public function testSingleTableInheritance_FilterOnlyOnRootTableWhenFetchingSubEntity() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + // Persister + $this->assertEquals(2, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyFlexUltraContract')->findAll())); + // SQLWalker + $this->assertEquals(2, count($this->_em->createQuery("SELECT cfc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract cfc")->getResult())); + + // Enable the filter + $conf = $this->_em->getConfiguration(); + $conf->addFilter("completed_contract", "\Doctrine\Tests\ORM\Functional\CompletedContractFilter"); + $this->_em->getFilters() + ->enable("completed_contract") + ->setParameter("completed", true, DBALType::BOOLEAN); + + $this->assertEquals(1, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyFlexUltraContract')->findAll())); + $this->assertEquals(1, count($this->_em->createQuery("SELECT cfc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract cfc")->getResult())); + } + + public function testSingleTableInheritance_FilterOnlyOnRootTableWhenFetchingRootEntity() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + $this->assertEquals(4, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyFlexContract')->findAll())); + $this->assertEquals(4, count($this->_em->createQuery("SELECT cfc FROM Doctrine\Tests\Models\Company\CompanyFlexContract cfc")->getResult())); + + // Enable the filter + $conf = $this->_em->getConfiguration(); + $conf->addFilter("completed_contract", "\Doctrine\Tests\ORM\Functional\CompletedContractFilter"); + $this->_em->getFilters() + ->enable("completed_contract") + ->setParameter("completed", true, DBALType::BOOLEAN); + + $this->assertEquals(2, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyFlexContract')->findAll())); + $this->assertEquals(2, count($this->_em->createQuery("SELECT cfc FROM Doctrine\Tests\Models\Company\CompanyFlexContract cfc")->getResult())); + } + + private function loadCompanySingleTableInheritanceFixtureData() + { + $contract1 = new CompanyFlexUltraContract; + $contract2 = new CompanyFlexUltraContract; + $contract2->markCompleted(); + + $contract3 = new CompanyFlexContract; + $contract4 = new CompanyFlexContract; + $contract4->markCompleted(); + + $manager = new CompanyManager; + $manager->setName('Alexander'); + $manager->setSalary(42); + $manager->setDepartment('Doctrine'); + $manager->setTitle('Filterer'); + + $manager2 = new CompanyManager; + $manager2->setName('Benjamin'); + $manager2->setSalary(1337); + $manager2->setDepartment('Doctrine'); + $manager2->setTitle('Maintainer'); + + $contract1->addManager($manager); + $contract2->addManager($manager); + $contract3->addManager($manager); + $contract4->addManager($manager); + + $contract1->addManager($manager2); + + $contract1->setSalesPerson($manager); + $contract2->setSalesPerson($manager); + + $this->_em->persist($manager); + $this->_em->persist($manager2); + $this->_em->persist($contract1); + $this->_em->persist($contract2); + $this->_em->persist($contract3); + $this->_em->persist($contract4); + $this->_em->flush(); + $this->_em->clear(); + + $this->managerId = $manager->getId(); + $this->managerId2 = $manager2->getId(); + $this->contractId1 = $contract1->getId(); + $this->contractId2 = $contract2->getId(); + } + + private function useCompletedContractFilter() + { + $conf = $this->_em->getConfiguration(); + $conf->addFilter("completed_contract", "\Doctrine\Tests\ORM\Functional\CompletedContractFilter"); + $this->_em->getFilters() + ->enable("completed_contract") + ->setParameter("completed", true, DBALType::BOOLEAN); + } + + public function testManyToMany_ExtraLazyCountWithFilterOnSTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertEquals(4, count($manager->managedContracts)); + + // Enable the filter + $this->useCompletedContractFilter(); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertEquals(2, count($manager->managedContracts)); + } + + public function testManyToMany_ExtraLazyContainsWithFilterOnSTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + $contract1 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId1); + $contract2 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId2); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertTrue($manager->managedContracts->contains($contract1)); + $this->assertTrue($manager->managedContracts->contains($contract2)); + + // Enable the filter + $this->useCompletedContractFilter(); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertFalse($manager->managedContracts->contains($contract1)); + $this->assertTrue($manager->managedContracts->contains($contract2)); + } + + public function testManyToMany_ExtraLazySliceWithFilterOnSTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertEquals(4, count($manager->managedContracts->slice(0, 10))); + + // Enable the filter + $this->useCompletedContractFilter(); + + $this->assertFalse($manager->managedContracts->isInitialized()); + $this->assertEquals(2, count($manager->managedContracts->slice(0, 10))); + } + + private function usePersonNameFilter($name) + { + // Enable the filter + $conf = $this->_em->getConfiguration(); + $conf->addFilter("person_name", "\Doctrine\Tests\ORM\Functional\CompanyPersonNameFilter"); + $this->_em->getFilters() + ->enable("person_name") + ->setParameter("name", $name, DBALType::STRING); + } + + public function testManyToMany_ExtraLazyCountWithFilterOnCTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $contract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyFlexUltraContract', $this->contractId1); + + $this->assertFalse($contract->managers->isInitialized()); + $this->assertEquals(2, count($contract->managers)); + + // Enable the filter + $this->usePersonNameFilter('Benjamin'); + + $this->assertFalse($contract->managers->isInitialized()); + $this->assertEquals(1, count($contract->managers)); + } + + public function testManyToMany_ExtraLazyContainsWithFilterOnCTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $contract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyFlexUltraContract', $this->contractId1); + $manager1 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + $manager2 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId2); + + $this->assertFalse($contract->managers->isInitialized()); + $this->assertTrue($contract->managers->contains($manager1)); + $this->assertTrue($contract->managers->contains($manager2)); + + // Enable the filter + $this->usePersonNameFilter('Benjamin'); + + $this->assertFalse($contract->managers->isInitialized()); + $this->assertFalse($contract->managers->contains($manager1)); + $this->assertTrue($contract->managers->contains($manager2)); + } + + public function testManyToMany_ExtraLazySliceWithFilterOnCTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $contract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyFlexUltraContract', $this->contractId1); + + $this->assertFalse($contract->managers->isInitialized()); + $this->assertEquals(2, count($contract->managers->slice(0, 10))); + + // Enable the filter + $this->usePersonNameFilter('Benjamin'); + + $this->assertFalse($contract->managers->isInitialized()); + $this->assertEquals(1, count($contract->managers->slice(0, 10))); + } + + public function testOneToMany_ExtraLazyCountWithFilterOnSTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + + $this->assertFalse($manager->soldContracts->isInitialized()); + $this->assertEquals(2, count($manager->soldContracts)); + + // Enable the filter + $this->useCompletedContractFilter(); + + $this->assertFalse($manager->soldContracts->isInitialized()); + $this->assertEquals(1, count($manager->soldContracts)); + } + + public function testOneToMany_ExtraLazyContainsWithFilterOnSTI() + { + $this->loadCompanySingleTableInheritanceFixtureData(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + $contract1 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId1); + $contract2 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId2); + + $this->assertFalse($manager->soldContracts->isInitialized()); + $this->assertTrue($manager->soldContracts->contains($contract1)); + $this->assertTrue($manager->soldContracts->contains($contract2)); + + // Enable the filter + $this->useCompletedContractFilter(); + + $this->assertFalse($manager->soldContracts->isInitialized()); + $this->assertFalse($manager->soldContracts->contains($contract1)); + $this->assertTrue($manager->soldContracts->contains($contract2)); + } + + public function testOneToMany_ExtraLazySliceWithFilterOnSTI() + { + + $this->loadCompanySingleTableInheritanceFixtureData(); + + $manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId); + + $this->assertFalse($manager->soldContracts->isInitialized()); + $this->assertEquals(2, count($manager->soldContracts->slice(0, 10))); + + // Enable the filter + $this->useCompletedContractFilter(); + + $this->assertFalse($manager->soldContracts->isInitialized()); + $this->assertEquals(1, count($manager->soldContracts->slice(0, 10))); + } + private function loadCompanyOrganizationEventJoinedSubclassFixtureData() + { + $organization = new CompanyOrganization; + + $event1 = new CompanyAuction; + $event1->setData('foo'); + + $event2 = new CompanyAuction; + $event2->setData('bar'); + + $organization->addEvent($event1); + $organization->addEvent($event2); + + $this->_em->persist($organization); + $this->_em->flush(); + $this->_em->clear(); + + $this->organizationId = $organization->getId(); + $this->eventId1 = $event1->getId(); + $this->eventId2 = $event2->getId(); + } + + private function useCompanyEventIdFilter() + { + // Enable the filter + $conf = $this->_em->getConfiguration(); + $conf->addFilter("event_id", "\Doctrine\Tests\ORM\Functional\CompanyEventFilter"); + $this->_em->getFilters() + ->enable("event_id") + ->setParameter("id", $this->eventId2); + } + + + public function testOneToMany_ExtraLazyCountWithFilterOnCTI() + { + $this->loadCompanyOrganizationEventJoinedSubclassFixtureData(); + + $organization = $this->_em->find('Doctrine\Tests\Models\Company\CompanyOrganization', $this->organizationId); + + $this->assertFalse($organization->events->isInitialized()); + $this->assertEquals(2, count($organization->events)); + + // Enable the filter + $this->useCompanyEventIdFilter(); + + $this->assertFalse($organization->events->isInitialized()); + $this->assertEquals(1, count($organization->events)); + } + + public function testOneToMany_ExtraLazyContainsWithFilterOnCTI() + { + $this->loadCompanyOrganizationEventJoinedSubclassFixtureData(); + + $organization = $this->_em->find('Doctrine\Tests\Models\Company\CompanyOrganization', $this->organizationId); + + $event1 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyEvent', $this->eventId1); + $event2 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyEvent', $this->eventId2); + + $this->assertFalse($organization->events->isInitialized()); + $this->assertTrue($organization->events->contains($event1)); + $this->assertTrue($organization->events->contains($event2)); + + // Enable the filter + $this->useCompanyEventIdFilter(); + + $this->assertFalse($organization->events->isInitialized()); + $this->assertFalse($organization->events->contains($event1)); + $this->assertTrue($organization->events->contains($event2)); + } + + public function testOneToMany_ExtraLazySliceWithFilterOnCTI() + { + $this->loadCompanyOrganizationEventJoinedSubclassFixtureData(); + + $organization = $this->_em->find('Doctrine\Tests\Models\Company\CompanyOrganization', $this->organizationId); + + $this->assertFalse($organization->events->isInitialized()); + $this->assertEquals(2, count($organization->events->slice(0, 10))); + + // Enable the filter + $this->useCompanyEventIdFilter(); + + $this->assertFalse($organization->events->isInitialized()); + $this->assertEquals(1, count($organization->events->slice(0, 10))); + } +} + +class MySoftDeleteFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + { + if ($targetEntity->name != "MyEntity\SoftDeleteNewsItem") { + return ""; + } + + return $targetTableAlias.'.deleted = 0'; + } +} + +class MyLocaleFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + { + if (!in_array("LocaleAware", $targetEntity->reflClass->getInterfaceNames())) { + return ""; + } + + return $targetTableAlias.'.locale = ' . $this->getParameter('locale'); // getParam uses connection to quote the value. + } +} + +class CMSCountryFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + { + if ($targetEntity->name != "Doctrine\Tests\Models\CMS\CmsAddress") { + return ""; + } + + return $targetTableAlias.'.country = ' . $this->getParameter('country'); // getParam uses connection to quote the value. + } +} + +class CMSGroupPrefixFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + { + if ($targetEntity->name != "Doctrine\Tests\Models\CMS\CmsGroup") { + return ""; + } + + return $targetTableAlias.'.name LIKE ' . $this->getParameter('prefix'); // getParam uses connection to quote the value. + } +} + +class CMSArticleTopicFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + { + if ($targetEntity->name != "Doctrine\Tests\Models\CMS\CmsArticle") { + return ""; + } + + return $targetTableAlias.'.topic = ' . $this->getParameter('topic'); // getParam uses connection to quote the value. + } +} + +class CompanyPersonNameFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') + { + if ($targetEntity->name != "Doctrine\Tests\Models\Company\CompanyPerson") { + return ""; + } + + return $targetTableAlias.'.name LIKE ' . $this->getParameter('name'); + } +} + +class CompletedContractFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') + { + if ($targetEntity->name != "Doctrine\Tests\Models\Company\CompanyContract") { + return ""; + } + + return $targetTableAlias.'.completed = ' . $this->getParameter('completed'); + } +} + +class CompanyEventFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') + { + if ($targetEntity->name != "Doctrine\Tests\Models\Company\CompanyEvent") { + return ""; + } + + return $targetTableAlias.'.id = ' . $this->getParameter('id'); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/CompanySchemaTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/CompanySchemaTest.php new file mode 100644 index 0000000..a1e6dac --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/CompanySchemaTest.php @@ -0,0 +1,68 @@ +useModelSet('company'); + parent::setUp(); + } + + /** + * @group DDC-966 + * @return Schema + */ + public function testGeneratedSchema() + { + $schema = $this->_em->getConnection()->getSchemaManager()->createSchema(); + + $this->assertTrue($schema->hasTable('company_contracts')); + + return $schema; + } + + /** + * @group DDC-966 + * @depends testGeneratedSchema + */ + public function testSingleTableInheritance(Schema $schema) + { + $table = $schema->getTable('company_contracts'); + + // Check nullability constraints + $this->assertTrue($table->getColumn('id')->getNotnull()); + $this->assertTrue($table->getColumn('completed')->getNotnull()); + $this->assertFalse($table->getColumn('salesPerson_id')->getNotnull()); + $this->assertTrue($table->getColumn('discr')->getNotnull()); + $this->assertFalse($table->getColumn('fixPrice')->getNotnull()); + $this->assertFalse($table->getColumn('hoursWorked')->getNotnull()); + $this->assertFalse($table->getColumn('pricePerHour')->getNotnull()); + $this->assertFalse($table->getColumn('maxPrice')->getNotnull()); + } + + /** + * @group DBAL-115 + */ + public function testDropPartSchemaWithForeignKeys() + { + if (!$this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) { + $this->markTestSkipped("Foreign Key test"); + } + + $sql = $this->_schemaTool->getDropSchemaSQL(array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyManager'), + )); + $this->assertEquals(4, count($sql)); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/DDC214Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/DDC214Test.php new file mode 100644 index 0000000..9b428c7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/DDC214Test.php @@ -0,0 +1,91 @@ +_em->getConnection(); + + if (strpos($conn->getDriver()->getName(), "sqlite") !== false) { + $this->markTestSkipped('SQLite does not support ALTER TABLE statements.'); + } + $this->schemaTool = new Tools\SchemaTool($this->_em); + } + + /** + * @group DDC-214 + */ + public function testCmsAddressModel() + { + $this->classes = array( + 'Doctrine\Tests\Models\CMS\CmsUser', + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'Doctrine\Tests\Models\CMS\CmsAddress', + 'Doctrine\Tests\Models\CMS\CmsGroup', + 'Doctrine\Tests\Models\CMS\CmsArticle', + 'Doctrine\Tests\Models\CMS\CmsEmail', + ); + + $this->assertCreatedSchemaNeedsNoUpdates($this->classes); + } + + /** + * @group DDC-214 + */ + public function testCompanyModel() + { + $this->classes = array( + 'Doctrine\Tests\Models\Company\CompanyPerson', + 'Doctrine\Tests\Models\Company\CompanyEmployee', + 'Doctrine\Tests\Models\Company\CompanyManager', + 'Doctrine\Tests\Models\Company\CompanyOrganization', + 'Doctrine\Tests\Models\Company\CompanyEvent', + 'Doctrine\Tests\Models\Company\CompanyAuction', + 'Doctrine\Tests\Models\Company\CompanyRaffle', + 'Doctrine\Tests\Models\Company\CompanyCar' + ); + + $this->assertCreatedSchemaNeedsNoUpdates($this->classes); + } + + public function assertCreatedSchemaNeedsNoUpdates($classes) + { + $classMetadata = array(); + foreach ($classes AS $class) { + $classMetadata[] = $this->_em->getClassMetadata($class); + } + + try { + $this->schemaTool->createSchema($classMetadata); + } catch(\Exception $e) { + // was already created + } + + $sm = $this->_em->getConnection()->getSchemaManager(); + + $fromSchema = $sm->createSchema(); + $toSchema = $this->schemaTool->getSchemaFromMetadata($classMetadata); + + $comparator = new \Doctrine\DBAL\Schema\Comparator(); + $schemaDiff = $comparator->compare($fromSchema, $toSchema); + + $sql = $schemaDiff->toSql($this->_em->getConnection()->getDatabasePlatform()); + $sql = array_filter($sql, function($sql) { return strpos($sql, 'DROP') === false; }); + + $this->assertEquals(0, count($sql), "SQL: " . implode(PHP_EOL, $sql)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/MySqlSchemaToolTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/MySqlSchemaToolTest.php new file mode 100644 index 0000000..4ac97c8 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/MySqlSchemaToolTest.php @@ -0,0 +1,99 @@ +_em->getConnection()->getDatabasePlatform()->getName() !== 'mysql') { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of mysql.'); + } + } + + public function testGetCreateSchemaSql() + { + $classes = array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsEmail'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + ); + + $tool = new SchemaTool($this->_em); + $sql = $tool->getCreateSchemaSql($classes); + + $this->assertEquals("CREATE TABLE cms_groups (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[0]); + $this->assertEquals("CREATE TABLE cms_users (id INT AUTO_INCREMENT NOT NULL, email_id INT DEFAULT NULL, status VARCHAR(50) DEFAULT NULL, username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_3AF03EC5F85E0677 (username), UNIQUE INDEX UNIQ_3AF03EC5A832C1C9 (email_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[1]); + $this->assertEquals("CREATE TABLE cms_users_groups (user_id INT NOT NULL, group_id INT NOT NULL, INDEX IDX_7EA9409AA76ED395 (user_id), INDEX IDX_7EA9409AFE54D947 (group_id), PRIMARY KEY(user_id, group_id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[2]); + $this->assertEquals("CREATE TABLE cms_addresses (id INT AUTO_INCREMENT NOT NULL, user_id INT DEFAULT NULL, country VARCHAR(50) NOT NULL, zip VARCHAR(50) NOT NULL, city VARCHAR(50) NOT NULL, UNIQUE INDEX UNIQ_ACAC157BA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[3]); + $this->assertEquals("CREATE TABLE cms_emails (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(250) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[4]); + $this->assertEquals("CREATE TABLE cms_phonenumbers (phonenumber VARCHAR(50) NOT NULL, user_id INT DEFAULT NULL, INDEX IDX_F21F790FA76ED395 (user_id), PRIMARY KEY(phonenumber)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[5]); + $this->assertEquals("ALTER TABLE cms_users ADD CONSTRAINT FK_3AF03EC5A832C1C9 FOREIGN KEY (email_id) REFERENCES cms_emails (id)", $sql[6]); + $this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id)", $sql[7]); + $this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AFE54D947 FOREIGN KEY (group_id) REFERENCES cms_groups (id)", $sql[8]); + $this->assertEquals("ALTER TABLE cms_addresses ADD CONSTRAINT FK_ACAC157BA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id)", $sql[9]); + $this->assertEquals("ALTER TABLE cms_phonenumbers ADD CONSTRAINT FK_F21F790FA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id)", $sql[10]); + + $this->assertEquals(11, count($sql)); + } + + public function testGetCreateSchemaSql2() + { + $classes = array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Generic\DecimalModel') + ); + + $tool = new SchemaTool($this->_em); + $sql = $tool->getCreateSchemaSql($classes); + + $this->assertEquals(1, count($sql)); + $this->assertEquals("CREATE TABLE decimal_model (id INT AUTO_INCREMENT NOT NULL, `decimal` NUMERIC(5, 2) NOT NULL, `high_scale` NUMERIC(14, 4) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[0]); + } + + public function testGetCreateSchemaSql3() + { + $classes = array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Generic\BooleanModel') + ); + + $tool = new SchemaTool($this->_em); + $sql = $tool->getCreateSchemaSql($classes); + + $this->assertEquals(1, count($sql)); + $this->assertEquals("CREATE TABLE boolean_model (id INT AUTO_INCREMENT NOT NULL, booleanField TINYINT(1) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[0]); + } + + /** + * @group DBAL-204 + */ + public function testGetCreateSchemaSql4() + { + $classes = array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\MysqlSchemaNamespacedEntity') + ); + + $tool = new SchemaTool($this->_em); + $sql = $tool->getCreateSchemaSql($classes); + + $this->assertEquals(0, count($sql)); + } + +} + +/** + * @Entity + * @Table("namespace.entity") + */ +class MysqlSchemaNamespacedEntity +{ + /** @Column(type="integer") @Id @GeneratedValue */ + public $id; +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/PostgreSqlSchemaToolTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/PostgreSqlSchemaToolTest.php new file mode 100644 index 0000000..6326fc3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaTool/PostgreSqlSchemaToolTest.php @@ -0,0 +1,198 @@ +_em->getConnection()->getDatabasePlatform()->getName() !== 'postgresql') { + $this->markTestSkipped('The ' . __CLASS__ .' requires the use of postgresql.'); + } + } + + public function testPostgresMetadataSequenceIncrementedBy10() + { + $address = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + $this->assertEquals(1, $address->sequenceGeneratorDefinition['allocationSize']); + } + + public function testGetCreateSchemaSql() + { + $classes = array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + ); + + $tool = new SchemaTool($this->_em); + $sql = $tool->getCreateSchemaSql($classes); + $sqlCount = count($sql); + + $this->assertEquals("CREATE TABLE cms_addresses (id INT NOT NULL, user_id INT DEFAULT NULL, country VARCHAR(50) NOT NULL, zip VARCHAR(50) NOT NULL, city VARCHAR(50) NOT NULL, PRIMARY KEY(id))", array_shift($sql)); + $this->assertEquals("CREATE UNIQUE INDEX UNIQ_ACAC157BA76ED395 ON cms_addresses (user_id)", array_shift($sql)); + $this->assertEquals("CREATE TABLE cms_users (id INT NOT NULL, email_id INT DEFAULT NULL, status VARCHAR(50) DEFAULT NULL, username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))", array_shift($sql)); + $this->assertEquals("CREATE UNIQUE INDEX UNIQ_3AF03EC5F85E0677 ON cms_users (username)", array_shift($sql)); + $this->assertEquals("CREATE UNIQUE INDEX UNIQ_3AF03EC5A832C1C9 ON cms_users (email_id)", array_shift($sql)); + $this->assertEquals("CREATE TABLE cms_users_groups (user_id INT NOT NULL, group_id INT NOT NULL, PRIMARY KEY(user_id, group_id))", array_shift($sql)); + $this->assertEquals("CREATE INDEX IDX_7EA9409AA76ED395 ON cms_users_groups (user_id)", array_shift($sql)); + $this->assertEquals("CREATE INDEX IDX_7EA9409AFE54D947 ON cms_users_groups (group_id)", array_shift($sql)); + $this->assertEquals("CREATE TABLE cms_phonenumbers (phonenumber VARCHAR(50) NOT NULL, user_id INT DEFAULT NULL, PRIMARY KEY(phonenumber))", array_shift($sql)); + $this->assertEquals("CREATE INDEX IDX_F21F790FA76ED395 ON cms_phonenumbers (user_id)", array_shift($sql)); + $this->assertEquals("CREATE SEQUENCE cms_addresses_id_seq INCREMENT BY 1 MINVALUE 1 START 1", array_shift($sql)); + $this->assertEquals("CREATE SEQUENCE cms_users_id_seq INCREMENT BY 1 MINVALUE 1 START 1", array_shift($sql)); + $this->assertEquals("ALTER TABLE cms_addresses ADD CONSTRAINT FK_ACAC157BA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); + $this->assertEquals("ALTER TABLE cms_users ADD CONSTRAINT FK_3AF03EC5A832C1C9 FOREIGN KEY (email_id) REFERENCES cms_emails (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); + $this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); + $this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AFE54D947 FOREIGN KEY (group_id) REFERENCES cms_groups (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); + $this->assertEquals("ALTER TABLE cms_phonenumbers ADD CONSTRAINT FK_F21F790FA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id) NOT DEFERRABLE INITIALLY IMMEDIATE", array_shift($sql)); + + $this->assertEquals(array(), $sql, "SQL Array should be empty now."); + $this->assertEquals(17, $sqlCount, "Total of 17 queries should be executed"); + } + + public function testGetCreateSchemaSql2() + { + $classes = array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Generic\DecimalModel') + ); + + $tool = new SchemaTool($this->_em); + $sql = $tool->getCreateSchemaSql($classes); + + $this->assertEquals(2, count($sql)); + + $this->assertEquals('CREATE TABLE decimal_model (id INT NOT NULL, "decimal" NUMERIC(5, 2) NOT NULL, "high_scale" NUMERIC(14, 4) NOT NULL, PRIMARY KEY(id))', $sql[0]); + $this->assertEquals("CREATE SEQUENCE decimal_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]); + } + + public function testGetCreateSchemaSql3() + { + $classes = array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Generic\BooleanModel') + ); + + $tool = new SchemaTool($this->_em); + $sql = $tool->getCreateSchemaSql($classes); + + $this->assertEquals(2, count($sql)); + $this->assertEquals("CREATE TABLE boolean_model (id INT NOT NULL, booleanField BOOLEAN NOT NULL, PRIMARY KEY(id))", $sql[0]); + $this->assertEquals("CREATE SEQUENCE boolean_model_id_seq INCREMENT BY 1 MINVALUE 1 START 1", $sql[1]); + } + + public function testGetDropSchemaSql() + { + $classes = array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + ); + + $tool = new SchemaTool($this->_em); + $sql = $tool->getDropSchemaSQL($classes); + + $this->assertEquals(14, count($sql)); + $dropSequenceSQLs = 0; + foreach ($sql AS $stmt) { + if (strpos($stmt, "DROP SEQUENCE") === 0) { + $dropSequenceSQLs++; + } + } + $this->assertEquals(4, $dropSequenceSQLs, "Expect 4 sequences to be dropped."); + } + + /** + * @group DDC-1657 + */ + public function testUpdateSchemaWithPostgreSQLSchema() + { + $classes = array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1657Screen'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1657Avatar'), + ); + try { + $this->_em->getConnection()->exec("CREATE SCHEMA stonewood"); + } catch(\Exception $e) { + } + + $tool = new SchemaTool($this->_em); + $tool->createSchema($classes); + + $sql = $tool->getUpdateSchemaSql($classes); + $sql = array_filter($sql, function($sql) { return (strpos($sql, "DROP SEQUENCE stonewood.") === 0); }); + + $this->assertCount(0, $sql, implode("\n", $sql)); + } +} + +/** + * @Entity + * @Table(name="stonewood.screen") + */ +class DDC1657Screen +{ + /** + * Identifier + * @var integer + * + * @Id + * @GeneratedValue(strategy="IDENTITY") + * @Column(name="pk", type="integer", nullable=false) + */ + private $pk; + + /** + * Title + * @var string + * + * @Column(name="title", type="string", length=255, nullable=false) + */ + private $title; + + /** + * Path + * @var string + * + * @Column(name="path", type="string", length=255, nullable=false) + */ + private $path; + + /** + * Register date + * @var Date + * + * @Column(name="ddate", type="date", nullable=false) + */ + private $ddate; + + /** + * Avatar + * @var Stonewood\Model\Entity\Avatar + * + * @ManyToOne(targetEntity="DDC1657Avatar") + * @JoinColumn(name="pk_avatar", referencedColumnName="pk", nullable=true, onDelete="CASCADE") + */ + private $avatar; +} + +/** + * @Entity + * @Table(name="stonewood.avatar") + */ +class DDC1657Avatar +{ + /** + * Identifier + * @var integer + * + * @Id + * @GeneratedValue(strategy="IDENTITY") + * @Column(name="pk", type="integer", nullable=false) + */ + private $pk; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php new file mode 100644 index 0000000..a575db0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php @@ -0,0 +1,50 @@ + $classes) { + if ($modelSet == "customtype") { + continue; + } + $modelSets[] = array($modelSet); + } + return $modelSets; + } + + /** + * @dataProvider dataValidateModelSets + */ + public function testValidateModelSets($modelSet) + { + $validator = new SchemaValidator($this->_em); + + $classes = array(); + foreach (self::$_modelSets[$modelSet] as $className) { + $classes[] = $this->_em->getClassMetadata($className); + } + + foreach ($classes as $class) { + $ce = $validator->validateClass($class); + + foreach ($ce as $key => $error) { + if (strpos($error, "must be private or protected. Public fields may break lazy-loading.") !== false) { + unset($ce[$key]); + } + } + + $this->assertEquals(0, count($ce), "Invalid Modelset: " . $modelSet . " class " . $class->name . ": ". implode("\n", $ce)); + } + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SequenceGeneratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SequenceGeneratorTest.php new file mode 100644 index 0000000..8a71cc1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SequenceGeneratorTest.php @@ -0,0 +1,53 @@ +_em->getConnection()->getDatabasePlatform()->supportsSequences()) { + $this->markTestSkipped('Only working for Databases that support sequences.'); + } + + try { + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\SequenceEntity'), + )); + } catch(\Exception $e) { + + } + } + + public function testHighAllocationSizeSequence() + { + for ($i = 0; $i < 11; $i++) { + $e = new SequenceEntity(); + $this->_em->persist($e); + } + $this->_em->flush(); + } +} + +/** + * @Entity + */ +class SequenceEntity +{ + /** + * @Id + * @column(type="integer") + * @GeneratedValue(strategy="SEQUENCE") + * @SequenceGenerator(allocationSize=5,sequenceName="person_id_seq") + */ + public $id; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php new file mode 100644 index 0000000..1c1dbdc --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php @@ -0,0 +1,389 @@ +useModelSet('company'); + parent::setUp(); + } + + public function persistRelatedEmployees() + { + $this->salesPerson = new \Doctrine\Tests\Models\Company\CompanyEmployee(); + $this->salesPerson->setName('Poor Sales Guy'); + $this->salesPerson->setDepartment('Sales'); + $this->salesPerson->setSalary(100); + + $engineer1 = new \Doctrine\Tests\Models\Company\CompanyEmployee(); + $engineer1->setName('Roman B.'); + $engineer1->setDepartment('IT'); + $engineer1->setSalary(100); + $this->engineers[] = $engineer1; + + $engineer2 = new \Doctrine\Tests\Models\Company\CompanyEmployee(); + $engineer2->setName('Jonathan W.'); + $engineer2->setDepartment('IT'); + $engineer2->setSalary(100); + $this->engineers[] = $engineer2; + + $engineer3 = new \Doctrine\Tests\Models\Company\CompanyEmployee(); + $engineer3->setName('Benjamin E.'); + $engineer3->setDepartment('IT'); + $engineer3->setSalary(100); + $this->engineers[] = $engineer3; + + $engineer4 = new \Doctrine\Tests\Models\Company\CompanyEmployee(); + $engineer4->setName('Guilherme B.'); + $engineer4->setDepartment('IT'); + $engineer4->setSalary(100); + $this->engineers[] = $engineer4; + + $this->_em->persist($this->salesPerson); + $this->_em->persist($engineer1); + $this->_em->persist($engineer2); + $this->_em->persist($engineer3); + $this->_em->persist($engineer4); + } + + public function loadFullFixture() + { + $this->persistRelatedEmployees(); + + $this->fix = new \Doctrine\Tests\Models\Company\CompanyFixContract(); + $this->fix->setFixPrice(1000); + $this->fix->setSalesPerson($this->salesPerson); + $this->fix->addEngineer($this->engineers[0]); + $this->fix->addEngineer($this->engineers[1]); + $this->fix->markCompleted(); + + $this->flex = new \Doctrine\Tests\Models\Company\CompanyFlexContract(); + $this->flex->setSalesPerson($this->salesPerson); + $this->flex->setHoursWorked(100); + $this->flex->setPricePerHour(100); + $this->flex->addEngineer($this->engineers[2]); + $this->flex->addEngineer($this->engineers[1]); + $this->flex->addEngineer($this->engineers[3]); + $this->flex->markCompleted(); + + $this->ultra = new \Doctrine\Tests\Models\Company\CompanyFlexUltraContract(); + $this->ultra->setSalesPerson($this->salesPerson); + $this->ultra->setHoursWorked(150); + $this->ultra->setPricePerHour(150); + $this->ultra->setMaxPrice(7000); + $this->ultra->addEngineer($this->engineers[3]); + $this->ultra->addEngineer($this->engineers[0]); + + $this->_em->persist($this->fix); + $this->_em->persist($this->flex); + $this->_em->persist($this->ultra); + $this->_em->flush(); + $this->_em->clear(); + } + + public function testPersistChildOfBaseClass() + { + $this->persistRelatedEmployees(); + + $fixContract = new \Doctrine\Tests\Models\Company\CompanyFixContract(); + $fixContract->setFixPrice(1000); + $fixContract->setSalesPerson($this->salesPerson); + + $this->_em->persist($fixContract); + $this->_em->flush(); + $this->_em->clear(); + + $contract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyFixContract', $fixContract->getId()); + + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyFixContract', $contract); + $this->assertEquals(1000, $contract->getFixPrice()); + $this->assertEquals($this->salesPerson->getId(), $contract->getSalesPerson()->getId()); + } + + public function testPersistDeepChildOfBaseClass() + { + $this->persistRelatedEmployees(); + + $ultraContract = new \Doctrine\Tests\Models\Company\CompanyFlexUltraContract(); + $ultraContract->setSalesPerson($this->salesPerson); + $ultraContract->setHoursWorked(100); + $ultraContract->setPricePerHour(50); + $ultraContract->setMaxPrice(7000); + + $this->_em->persist($ultraContract); + $this->_em->flush(); + $this->_em->clear(); + + $contract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyFlexUltraContract', $ultraContract->getId()); + + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyFlexUltraContract', $contract); + $this->assertEquals(7000, $contract->getMaxPrice()); + $this->assertEquals(100, $contract->getHoursWorked()); + $this->assertEquals(50, $contract->getPricePerHour()); + } + + public function testChildClassLifecycleUpdate() + { + $this->loadFullFixture(); + + $fix = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->fix->getId()); + $fix->setFixPrice(2500); + + $this->_em->flush(); + $this->_em->clear(); + + $newFix = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->fix->getId()); + $this->assertEquals(2500, $newFix->getFixPrice()); + } + + public function testChildClassLifecycleRemove() + { + $this->loadFullFixture(); + + $fix = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->fix->getId()); + $this->_em->remove($fix); + $this->_em->flush(); + + $this->assertNull($this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->fix->getId())); + } + + public function testFindAllForAbstractBaseClass() + { + $this->loadFullFixture(); + $contracts = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyContract')->findAll(); + + $this->assertEquals(3, count($contracts)); + $this->assertContainsOnly('Doctrine\Tests\Models\Company\CompanyContract', $contracts); + } + + public function testFindAllForChildClass() + { + $this->loadFullFixture(); + + $this->assertEquals(1, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyFixContract')->findAll())); + $this->assertEquals(2, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyFlexContract')->findAll())); + $this->assertEquals(1, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyFlexUltraContract')->findAll())); + } + + public function testFindForAbstractBaseClass() + { + $this->loadFullFixture(); + + $contract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->fix->getId()); + + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyFixContract', $contract); + $this->assertEquals(1000, $contract->getFixPrice()); + } + + public function testQueryForAbstractBaseClass() + { + $this->loadFullFixture(); + + $contracts = $this->_em->createQuery('SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c')->getResult(); + + $this->assertEquals(3, count($contracts)); + $this->assertContainsOnly('Doctrine\Tests\Models\Company\CompanyContract', $contracts); + } + + public function testQueryForChildClass() + { + $this->loadFullFixture(); + + $this->assertEquals(1, count($this->_em->createQuery('SELECT c FROM Doctrine\Tests\Models\Company\CompanyFixContract c')->getResult())); + $this->assertEquals(2, count($this->_em->createQuery('SELECT c FROM Doctrine\Tests\Models\Company\CompanyFlexContract c')->getResult())); + $this->assertEquals(1, count($this->_em->createQuery('SELECT c FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract c')->getResult())); + } + + public function testQueryBaseClassWithJoin() + { + $this->loadFullFixture(); + + $contracts = $this->_em->createQuery('SELECT c, p FROM Doctrine\Tests\Models\Company\CompanyContract c JOIN c.salesPerson p')->getResult(); + $this->assertEquals(3, count($contracts)); + $this->assertContainsOnly('Doctrine\Tests\Models\Company\CompanyContract', $contracts); + } + + public function testQueryScalarWithDiscrimnatorValue() + { + $this->loadFullFixture(); + + $contracts = $this->_em->createQuery('SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c ORDER BY c.id')->getScalarResult(); + + $discrValues = \array_map(function($a) { + return $a['c_discr']; + }, $contracts); + + sort($discrValues); + + $this->assertEquals(array('fix', 'flexible', 'flexultra'), $discrValues); + } + + public function testQueryChildClassWithCondition() + { + $this->loadFullFixture(); + + $dql = 'SELECT c FROM Doctrine\Tests\Models\Company\CompanyFixContract c WHERE c.fixPrice = ?1'; + $contract = $this->_em->createQuery($dql)->setParameter(1, 1000)->getSingleResult(); + + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyFixContract', $contract); + $this->assertEquals(1000, $contract->getFixPrice()); + } + + public function testUpdateChildClassWithCondition() + { + $this->loadFullFixture(); + + $dql = 'UPDATE Doctrine\Tests\Models\Company\CompanyFlexContract c SET c.hoursWorked = c.hoursWorked * 2 WHERE c.hoursWorked = 150'; + $affected = $this->_em->createQuery($dql)->execute(); + + $this->assertEquals(1, $affected); + + $flexContract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->flex->getId()); + $ultraContract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->ultra->getId()); + + $this->assertEquals(300, $ultraContract->getHoursWorked()); + $this->assertEquals(100, $flexContract->getHoursWorked()); + } + + public function testUpdateBaseClassWithCondition() + { + $this->loadFullFixture(); + + $dql = 'UPDATE Doctrine\Tests\Models\Company\CompanyContract c SET c.completed = true WHERE c.completed = false'; + $affected = $this->_em->createQuery($dql)->execute(); + + $this->assertEquals(1, $affected); + + $dql = 'UPDATE Doctrine\Tests\Models\Company\CompanyContract c SET c.completed = false'; + $affected = $this->_em->createQuery($dql)->execute(); + + $this->assertEquals(3, $affected); + } + + public function testDeleteByChildClassCondition() + { + $this->loadFullFixture(); + + $dql = 'DELETE Doctrine\Tests\Models\Company\CompanyFlexContract c'; + $affected = $this->_em->createQuery($dql)->execute(); + + $this->assertEquals(2, $affected); + } + + public function testDeleteByBaseClassCondition() + { + $this->loadFullFixture(); + + $dql = "DELETE Doctrine\Tests\Models\Company\CompanyContract c WHERE c.completed = true"; + $affected = $this->_em->createQuery($dql)->execute(); + + $this->assertEquals(2, $affected); + + $contracts = $this->_em->createQuery('SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c')->getResult(); + $this->assertEquals(1, count($contracts)); + + $this->assertFalse($contracts[0]->isCompleted(), "Only non completed contracts should be left."); + } + + /** + * @group DDC-130 + */ + public function testDeleteJoinTableRecords() + { + $this->loadFullFixture(); + + // remove managed copy of the fix contract + $this->_em->remove($this->_em->find(get_class($this->fix), $this->fix->getId())); + $this->_em->flush(); + + $this->assertNull($this->_em->find(get_class($this->fix), $this->fix->getId()), "Contract should not be present in the database anymore."); + } + + /** + * @group DDC-817 + */ + public function testFindByAssociation() + { + $this->loadFullFixture(); + + $repos = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyContract"); + $contracts = $repos->findBy(array('salesPerson' => $this->salesPerson->getId())); + $this->assertEquals(3, count($contracts), "There should be 3 entities related to " . $this->salesPerson->getId() . " for 'Doctrine\Tests\Models\Company\CompanyContract'"); + + $repos = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyFixContract"); + $contracts = $repos->findBy(array('salesPerson' => $this->salesPerson->getId())); + $this->assertEquals(1, count($contracts), "There should be 1 entities related to " . $this->salesPerson->getId() . " for 'Doctrine\Tests\Models\Company\CompanyFixContract'"); + + $repos = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyFlexContract"); + $contracts = $repos->findBy(array('salesPerson' => $this->salesPerson->getId())); + $this->assertEquals(2, count($contracts), "There should be 2 entities related to " . $this->salesPerson->getId() . " for 'Doctrine\Tests\Models\Company\CompanyFlexContract'"); + + $repos = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyFlexUltraContract"); + $contracts = $repos->findBy(array('salesPerson' => $this->salesPerson->getId())); + $this->assertEquals(1, count($contracts), "There should be 1 entities related to " . $this->salesPerson->getId() . " for 'Doctrine\Tests\Models\Company\CompanyFlexUltraContract'"); + } + + /** + * @group DDC-1637 + */ + public function testInheritanceMatching() + { + $this->loadFullFixture(); + + $repository = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyContract"); + $contracts = $repository->matching(new Criteria( + Criteria::expr()->eq('salesPerson', $this->salesPerson->getId()) + )); + $this->assertEquals(3, count($contracts)); + + $repository = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyFixContract"); + $contracts = $repository->matching(new Criteria( + Criteria::expr()->eq('salesPerson', $this->salesPerson->getId()) + )); + $this->assertEquals(1, count($contracts)); + } + + /** + * @group DDC-834 + */ + public function testGetReferenceEntityWithSubclasses() + { + $this->loadFullFixture(); + + $ref = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyContract', $this->fix->getId()); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $ref, "Cannot Request a proxy from a class that has subclasses."); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyContract', $ref); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyFixContract', $ref, "Direct fetch of the reference has to load the child class Emplyoee directly."); + $this->_em->clear(); + + $ref = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyFixContract', $this->fix->getId()); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $ref, "A proxy can be generated only if no subclasses exists for the requested reference."); + } + + /** + * @group DDC-952 + */ + public function testEagerLoadInheritanceHierachy() + { + $this->loadFullFixture(); + + $dql = 'SELECT f FROM Doctrine\Tests\Models\Company\CompanyFixContract f WHERE f.id = ?1'; + $contract = $this->_em->createQuery($dql) + ->setFetchMode('Doctrine\Tests\Models\Company\CompanyFixContract', 'salesPerson', ClassMetadata::FETCH_EAGER) + ->setParameter(1, $this->fix->getId()) + ->getSingleResult(); + + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $contract->getSalesPerson()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php new file mode 100644 index 0000000..de103eb --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php @@ -0,0 +1,110 @@ + + */ +class StandardEntityPersisterTest extends \Doctrine\Tests\OrmFunctionalTestCase +{ + protected function setUp() + { + $this->useModelSet('ecommerce'); + parent::setUp(); + } + + public function testAcceptsForeignKeysAsCriteria() + { + $customer = new ECommerceCustomer(); + $customer->setName('John Doe'); + $cart = new ECommerceCart(); + $cart->setPayment('Credit card'); + $customer->setCart($cart); + $this->_em->persist($customer); + $this->_em->flush(); + $this->_em->clear(); + $cardId = $cart->getId(); + unset($cart); + + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCart'); + + $persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceCart'); + $newCart = new ECommerceCart(); + $this->_em->getUnitOfWork()->registerManaged($newCart, array('id' => $cardId), array()); + $persister->load(array('customer_id' => $customer->getId()), $newCart, $class->associationMappings['customer']); + $this->assertEquals('Credit card', $newCart->getPayment()); + } + + /** + * Ticket #2478 from Damon Jones (dljones) + */ + public function testAddPersistRetrieve() + { + $f1 = new ECommerceFeature; + $f1->setDescription('AC-3'); + + $f2 = new ECommerceFeature; + $f2->setDescription('DTS'); + + $p = new ECommerceProduct; + $p->addFeature($f1); + $p->addfeature($f2); + $this->_em->persist($p); + + $this->_em->flush(); + + $this->assertEquals(2, count($p->getFeatures())); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $p->getFeatures()); + + $q = $this->_em->createQuery( + 'SELECT p, f + FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p + JOIN p.features f' + ); + + $res = $q->getResult(); + + $this->assertEquals(2, count($p->getFeatures())); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $p->getFeatures()); + + // Check that the features are the same instances still + foreach ($p->getFeatures() as $feature) { + if ($feature->getDescription() == 'AC-3') { + $this->assertTrue($feature === $f1); + } else { + $this->assertTrue($feature === $f2); + } + } + + // Now we test how Hydrator affects IdentityMap + // (change from ArrayCollection to PersistentCollection) + $f3 = new ECommerceFeature(); + $f3->setDescription('XVID'); + $p->addFeature($f3); + + // Now we persist the Feature #3 + $this->_em->persist($p); + $this->_em->flush(); + + $q = $this->_em->createQuery( + 'SELECT p, f + FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p + JOIN p.features f' + ); + + $res = $q->getResult(); + + // Persisted Product now must have 3 Feature items + $this->assertEquals(3, count($res[0]->getFeatures())); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1040Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1040Test.php new file mode 100644 index 0000000..93dc0ee --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1040Test.php @@ -0,0 +1,81 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testReuseNamedEntityParameter() + { + $user = new CmsUser(); + $user->name = "John Galt"; + $user->username = "jgalt"; + $user->status = "inactive"; + + $article = new CmsArticle(); + $article->topic = "This is John Galt speaking!"; + $article->text = "Yadda Yadda!"; + $article->setAuthor($user); + + $this->_em->persist($user); + $this->_em->persist($article); + $this->_em->flush(); + + $dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.user = :author"; + $this->_em->createQuery($dql) + ->setParameter('author', $user) + ->getResult(); + + $dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.user = :author AND a.user = :author"; + $this->_em->createQuery($dql) + ->setParameter('author', $user) + ->getResult(); + + $dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = :topic AND a.user = :author AND a.user = :author"; + $farticle = $this->_em->createQuery($dql) + ->setParameter('author', $user) + ->setParameter('topic', 'This is John Galt speaking!') + ->getSingleResult(); + + $this->assertSame($article, $farticle); + } + + public function testUseMultiplePositionalParameters() + { + $user = new CmsUser(); + $user->name = "John Galt"; + $user->username = "jgalt"; + $user->status = "inactive"; + + $article = new CmsArticle(); + $article->topic = "This is John Galt speaking!"; + $article->text = "Yadda Yadda!"; + $article->setAuthor($user); + + $this->_em->persist($user); + $this->_em->persist($article); + $this->_em->flush(); + + $dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = ?1 AND a.user = ?2 AND a.user = ?3"; + $farticle = $this->_em->createQuery($dql) + ->setParameter(1, 'This is John Galt speaking!') + ->setParameter(2, $user) + ->setParameter(3, $user) + ->getSingleResult(); + + $this->assertSame($article, $farticle); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1041Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1041Test.php new file mode 100644 index 0000000..5b30c04 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1041Test.php @@ -0,0 +1,33 @@ +useModelSet('company'); + parent::setUp(); + } + + public function testGrabWrongSubtypeReturnsNull() + { + $fix = new \Doctrine\Tests\Models\Company\CompanyFixContract(); + $fix->setFixPrice(2000); + + $this->_em->persist($fix); + $this->_em->flush(); + + $id = $fix->getId(); + + $this->assertNull($this->_em->find('Doctrine\Tests\Models\Company\CompanyFlexContract', $id)); + $this->assertNull($this->_em->getReference('Doctrine\Tests\Models\Company\CompanyFlexContract', $id)); + $this->assertNull($this->_em->getPartialReference('Doctrine\Tests\Models\Company\CompanyFlexContract', $id)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1043Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1043Test.php new file mode 100644 index 0000000..31bd835 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1043Test.php @@ -0,0 +1,36 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testChangeSetPlusWeirdPHPCastingIntCastingRule() + { + $user = new \Doctrine\Tests\Models\CMS\CmsUser(); + $user->name = "John Galt"; + $user->username = "jgalt"; + $user->status = "+44"; + + $this->_em->persist($user); + $this->_em->flush(); + + $user->status = "44"; + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find("Doctrine\Tests\Models\CMS\CmsUser", $user->id); + $this->assertSame("44", $user->status); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1050Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1050Test.php new file mode 100644 index 0000000..31c0733 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1050Test.php @@ -0,0 +1,37 @@ +markTestSkipped('performance skipped'); + $this->useModelSet('cms'); + parent::setUp(); + } + + public function testPerformance() + { + for ($i = 2; $i < 10000; ++$i) { + $user = new \Doctrine\Tests\Models\CMS\CmsUser(); + $user->status = 'developer'; + $user->username = 'jwage'+$i; + $user->name = 'Jonathan'; + $this->_em->persist($user); + } + $this->_em->flush(); + $this->_em->clear(); + + $s = microtime(true); + $users = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->findAll(); + $e = microtime(true); + echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1080Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1080Test.php new file mode 100644 index 0000000..2b9d579 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1080Test.php @@ -0,0 +1,317 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1080Foo'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1080Bar'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1080FooBar'), + )); + + $foo1 = new DDC1080Foo(); + $foo1->setFooTitle('foo title 1'); + $foo2 = new DDC1080Foo(); + $foo2->setFooTitle('foo title 2'); + + $bar1 = new DDC1080Bar(); + $bar1->setBarTitle('bar title 1'); + $bar2 = new DDC1080Bar(); + $bar2->setBarTitle('bar title 2'); + $bar3 = new DDC1080Bar(); + $bar3->setBarTitle('bar title 3'); + + $foobar1 = new DDC1080FooBar(); + $foobar1->setFoo($foo1); + $foobar1->setBar($bar1); + $foobar1->setOrderNr(0); + + $foobar2 = new DDC1080FooBar(); + $foobar2->setFoo($foo1); + $foobar2->setBar($bar2); + $foobar2->setOrderNr(0); + + $foobar3 = new DDC1080FooBar(); + $foobar3->setFoo($foo1); + $foobar3->setBar($bar3); + $foobar3->setOrderNr(0); + + $this->_em->persist($foo1); + $this->_em->persist($foo2); + $this->_em->persist($bar1); + $this->_em->persist($bar2); + $this->_em->persist($bar3); + $this->_em->flush(); + + $this->_em->persist($foobar1); + $this->_em->persist($foobar2); + $this->_em->persist($foobar3); + $this->_em->flush(); + $this->_em->clear(); + + $foo = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC1080Foo', $foo1->getFooId()); + $fooBars = $foo->getFooBars(); + + $this->assertEquals(3, count($fooBars), "Should return three foobars."); + } +} + + +/** + * @Entity + * @Table(name="foo") + */ +class DDC1080Foo +{ + + /** + * @Id + * @Column(name="fooID", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + protected $_fooID; + /** + * @Column(name="fooTitle", type="string") + */ + protected $_fooTitle; + /** + * @OneToMany(targetEntity="DDC1080FooBar", mappedBy="_foo", + * cascade={"persist"}) + * @OrderBy({"_orderNr"="ASC"}) + */ + protected $_fooBars; + + public function __construct() + { + $this->_fooBars = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * @return the $fooID + */ + public function getFooID() + { + return $this->_fooID; + } + + /** + * @return the $fooTitle + */ + public function getFooTitle() + { + return $this->_fooTitle; + } + + /** + * @return the $fooBars + */ + public function getFooBars() + { + return $this->_fooBars; + } + + /** + * @param field_type $fooID + */ + public function setFooID($fooID) + { + $this->_fooID = $fooID; + } + + /** + * @param field_type $fooTitle + */ + public function setFooTitle($fooTitle) + { + $this->_fooTitle = $fooTitle; + } + + /** + * @param field_type $fooBars + */ + public function setFooBars($fooBars) + { + $this->_fooBars = $fooBars; + } + +} +/** + * @Entity + * @Table(name="bar") + */ +class DDC1080Bar +{ + + /** + * @Id + * @Column(name="barID", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + protected $_barID; + /** + * @Column(name="barTitle", type="string") + */ + protected $_barTitle; + /** + * @OneToMany(targetEntity="DDC1080FooBar", mappedBy="_bar", + * cascade={"persist"}) + * @OrderBy({"_orderNr"="ASC"}) + */ + protected $_fooBars; + + public function __construct() + { + $this->_fooBars = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * @return the $barID + */ + public function getBarID() + { + return $this->_barID; + } + + /** + * @return the $barTitle + */ + public function getBarTitle() + { + return $this->_barTitle; + } + + /** + * @return the $fooBars + */ + public function getFooBars() + { + return $this->_fooBars; + } + + /** + * @param field_type $barID + */ + public function setBarID($barID) + { + $this->_barID = $barID; + } + + /** + * @param field_type $barTitle + */ + public function setBarTitle($barTitle) + { + $this->_barTitle = $barTitle; + } + + /** + * @param field_type $fooBars + */ + public function setFooBars($fooBars) + { + $this->_fooBars = $fooBars; + } + +} + +/** + * @Table(name="fooBar") + * @Entity + */ +class DDC1080FooBar +{ + + /** + * @ManyToOne(targetEntity="DDC1080Foo") + * @JoinColumn(name="fooID", referencedColumnName="fooID") + * @Id + */ + protected $_foo = null; + /** + * @ManyToOne(targetEntity="DDC1080Bar") + * @JoinColumn(name="barID", referencedColumnName="barID") + * @Id + */ + protected $_bar = null; + /** + * @var integer orderNr + * @Column(name="orderNr", type="integer", nullable=false) + */ + protected $_orderNr = null; + + /** + * Retrieve the foo property + * + * @return DDC1080Foo + */ + public function getFoo() + { + return $this->_foo; + } + + /** + * Set the foo property + * + * @param DDC1080Foo $foo + * @return DDC1080FooBar + */ + public function setFoo($foo) + { + $this->_foo = $foo; + return $this; + } + + /** + * Retrieve the bar property + * + * @return DDC1080Bar + */ + public function getBar() + { + return $this->_bar; + } + + /** + * Set the bar property + * + * @param DDC1080Bar $bar + * @return DDC1080FooBar + */ + public function setBar($bar) + { + $this->_bar = $bar; + return $this; + } + + /** + * Retrieve the orderNr property + * + * @return integer|null + */ + public function getOrderNr() + { + return $this->_orderNr; + } + + /** + * Set the orderNr property + * + * @param integer|null $orderNr + * @return DDC1080FooBar + */ + public function setOrderNr($orderNr) + { + $this->_orderNr = $orderNr; + return $this; + } + +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1113Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1113Test.php new file mode 100644 index 0000000..3e8a2fc --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1113Test.php @@ -0,0 +1,99 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1113Engine'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1113Vehicle'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1113Car'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1113Bus'), + )); + } catch (\Exception $e) { + + } + } + + public function testIssue() + { + $car = new DDC1113Car(); + $car->engine = new DDC1113Engine(); + + $bus = new DDC1113Bus(); + $bus->engine = new DDC1113Engine(); + + $this->_em->persist($car); + $this->_em->flush(); + + $this->_em->persist($bus); + $this->_em->flush(); + + $this->_em->remove($bus); + $this->_em->remove($car); + $this->_em->flush(); + } + +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorMap({"car" = "DDC1113Car", "bus" = "DDC1113Bus"}) + */ +class DDC1113Vehicle +{ + + /** @Id @GeneratedValue @Column(type="integer") */ + public $id; + + /** + * @ManyToOne(targetEntity="DDC1113Vehicle") + */ + public $parent; + + /** @OneToOne(targetEntity="DDC1113Engine", cascade={"persist", "remove"}) */ + public $engine; + +} + +/** + * @Entity + */ +class DDC1113Car extends DDC1113Vehicle +{ + +} + +/** + * @Entity + */ +class DDC1113Bus extends DDC1113Vehicle +{ + +} + +/** + * @Entity + */ +class DDC1113Engine +{ + + /** @Id @GeneratedValue @Column(type="integer") */ + public $id; + +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1129Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1129Test.php new file mode 100644 index 0000000..c481aa3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1129Test.php @@ -0,0 +1,46 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testVersionFieldIgnoredInChangesetComputation() + { + $article = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article->text = "I don't know."; + $article->topic = "Who is John Galt?"; + + $this->_em->persist($article); + $this->_em->flush(); + + $this->assertEquals(1, $article->version); + + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'); + $uow = $this->_em->getUnitOfWork(); + + $uow->computeChangeSet($class, $article); + $changeSet = $uow->getEntityChangeSet($article); + $this->assertEquals(0, count($changeSet), "No changesets should be computed."); + + $article->text = "This is John Galt speaking."; + $this->_em->flush(); + + $this->assertEquals(2, $article->version); + + $uow->computeChangeSet($class, $article); + $changeSet = $uow->getEntityChangeSet($article); + $this->assertEquals(0, count($changeSet), "No changesets should be computed."); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1151Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1151Test.php new file mode 100644 index 0000000..fe975f6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1151Test.php @@ -0,0 +1,56 @@ +_em->getConnection()->getDatabasePlatform()->getName() != 'postgresql') { + $this->markTestSkipped("This test is useful for all databases, but designed only for postgresql."); + } + + $sql = $this->_schemaTool->getCreateSchemaSql(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1151User'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1151Group'), + )); + + $this->assertEquals("CREATE TABLE \"User\" (id INT NOT NULL, PRIMARY KEY(id))", $sql[0]); + $this->assertEquals("CREATE TABLE ddc1151user_ddc1151group (ddc1151user_id INT NOT NULL, ddc1151group_id INT NOT NULL, PRIMARY KEY(ddc1151user_id, ddc1151group_id))", $sql[1]); + $this->assertEquals("CREATE INDEX IDX_88A3259AC5AD08A ON ddc1151user_ddc1151group (ddc1151user_id)", $sql[2]); + $this->assertEquals("CREATE INDEX IDX_88A32597357E0B1 ON ddc1151user_ddc1151group (ddc1151group_id)", $sql[3]); + $this->assertEquals("CREATE TABLE \"Group\" (id INT NOT NULL, PRIMARY KEY(id))", $sql[4]); + $this->assertEquals("CREATE SEQUENCE \"User_id_seq\" INCREMENT BY 1 MINVALUE 1 START 1", $sql[5]); + $this->assertEquals("CREATE SEQUENCE \"Group_id_seq\" INCREMENT BY 1 MINVALUE 1 START 1", $sql[6]); + $this->assertEquals("ALTER TABLE ddc1151user_ddc1151group ADD CONSTRAINT FK_88A3259AC5AD08A FOREIGN KEY (ddc1151user_id) REFERENCES \"User\" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[7]); + $this->assertEquals("ALTER TABLE ddc1151user_ddc1151group ADD CONSTRAINT FK_88A32597357E0B1 FOREIGN KEY (ddc1151group_id) REFERENCES \"Group\" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE", $sql[8]); + } +} + +/** + * @Entity + * @Table(name="`User`") + */ +class DDC1151User +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + + /** @ManyToMany(targetEntity="DDC1151Group") */ + public $groups; +} + +/** + * @Entity + * @Table(name="`Group`") + */ +class DDC1151Group +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php new file mode 100644 index 0000000..1e8cae6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php @@ -0,0 +1,215 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1163Product'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1163SpecialProduct'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1163ProxyHolder'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1163Tag'), + )); + } + + public function testIssue() + { + $this->createSpecialProductAndProxyHolderReferencingIt(); + $this->_em->clear(); + + $this->createProxyForSpecialProduct(); + + $this->setPropertyAndAssignTagToSpecialProduct(); + + // fails + $this->_em->flush(); + } + + private function createSpecialProductAndProxyHolderReferencingIt() + { + $specialProduct = new DDC1163SpecialProduct(); + $this->_em->persist($specialProduct); + + $proxyHolder = new DDC1163ProxyHolder(); + $this->_em->persist($proxyHolder); + + $proxyHolder->setSpecialProduct($specialProduct); + + $this->_em->flush(); + + $this->productId = $specialProduct->getId(); + $this->proxyHolderId = $proxyHolder->getId(); + } + + /** + * We want Doctrine to instantiate a lazy-load proxy for the previously created + * 'SpecialProduct' and register it. + * + * When Doctrine loads the 'ProxyHolder', it will do just that because the 'ProxyHolder' + * references the 'SpecialProduct'. + */ + private function createProxyForSpecialProduct() + { + /* @var $proxyHolder ProxyHolder */ + $proxyHolder = $this->_em->find(__NAMESPACE__ . '\\DDC1163ProxyHolder', $this->proxyHolderId); + + $this->assertInstanceOf(__NAMESPACE__.'\\DDC1163SpecialProduct', $proxyHolder->getSpecialProduct()); + } + + private function setPropertyAndAssignTagToSpecialProduct() + { + /* @var $specialProduct SpecialProduct */ + $specialProduct = $this->_em->find(__NAMESPACE__ . '\\DDC1163SpecialProduct', $this->productId); + + $this->assertInstanceOf(__NAMESPACE__.'\\DDC1163SpecialProduct', $specialProduct); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $specialProduct); + + $specialProduct->setSubclassProperty('foobar'); + + // this screams violation of law of demeter ;) + $this->assertEquals( + __NAMESPACE__.'\\DDC1163SpecialProduct', + $this->_em->getUnitOfWork()->getEntityPersister(get_class($specialProduct))->getClassMetadata()->name + ); + + $tag = new DDC1163Tag('Foo'); + $this->_em->persist($tag); + $tag->setProduct($specialProduct); + } +} + +/** + * @Entity + */ +class DDC1163ProxyHolder +{ + + /** + * @var int + * @Column(name="id", type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + private $id; + /** + * @var SpecialProduct + * @OneToOne(targetEntity="DDC1163SpecialProduct") + */ + private $specialProduct; + + public function getId() + { + return $this->id; + } + + public function setSpecialProduct(DDC1163SpecialProduct $specialProduct) + { + $this->specialProduct = $specialProduct; + } + + public function getSpecialProduct() + { + return $this->specialProduct; + } + +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="type", type="string") + * @DiscriminatorMap({"special" = "DDC1163SpecialProduct"}) + */ +abstract class DDC1163Product +{ + + /** + * @var int + * @Column(name="id", type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + protected $id; + + public function getId() + { + return $this->id; + } + +} + +/** + * @Entity + */ +class DDC1163SpecialProduct extends DDC1163Product +{ + + /** + * @var string + * @Column(name="subclass_property", type="string", nullable=true) + */ + private $subclassProperty; + + /** + * @param string $value + */ + public function setSubclassProperty($value) + { + $this->subclassProperty = $value; + } + +} + +/** + * @Entity + */ +class DDC1163Tag +{ + + /** + * @var int + * @Column(name="id", type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + private $id; + /** + * @var string + * @Column(name="name", type="string") + */ + private $name; + /** + * @var Product + * @ManyToOne(targetEntity="DDC1163Product", inversedBy="tags") + * @JoinColumns({ + * @JoinColumn(name="product_id", referencedColumnName="id") + * }) + */ + private $product; + + /** + * @param string $name + */ + public function __construct($name) + { + $this->name = $name; + } + + /** + * @param Product $product + */ + public function setProduct(DDC1163Product $product) + { + $this->product = $product; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC117Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC117Test.php new file mode 100644 index 0000000..6ae4595 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC117Test.php @@ -0,0 +1,464 @@ +useModelSet('ddc117'); + parent::setUp(); + + $this->article1 = new DDC117Article("Foo"); + $this->article2 = new DDC117Article("Bar"); + + $this->_em->persist($this->article1); + $this->_em->persist($this->article2); + $this->_em->flush(); + + $this->reference = new DDC117Reference($this->article1, $this->article2, "Test-Description"); + $this->_em->persist($this->reference); + + $this->translation = new DDC117Translation($this->article1, "en", "Bar"); + $this->_em->persist($this->translation); + + $this->articleDetails = new DDC117ArticleDetails($this->article1, "Very long text"); + $this->_em->persist($this->articleDetails); + $this->_em->flush(); + + $this->_em->clear(); + } + + /** + * @group DDC-117 + */ + public function testAssociationOnlyCompositeKey() + { + $idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id()); + + $mapRef = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Reference", $mapRef); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Article", $mapRef->target()); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Article", $mapRef->source()); + $this->assertSame($mapRef, $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria)); + + $this->_em->clear(); + + $dql = "SELECT r, s FROM "."Doctrine\Tests\Models\DDC117\DDC117Reference r JOIN r.source s WHERE r.source = ?1"; + $dqlRef = $this->_em->createQuery($dql)->setParameter(1, 1)->getSingleResult(); + + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Reference", $mapRef); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Article", $mapRef->target()); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Article", $mapRef->source()); + $this->assertSame($dqlRef, $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria)); + + $this->_em->clear(); + + $dql = "SELECT r, s FROM "."Doctrine\Tests\Models\DDC117\DDC117Reference r JOIN r.source s WHERE s.title = ?1"; + $dqlRef = $this->_em->createQuery($dql)->setParameter(1, 'Foo')->getSingleResult(); + + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Reference", $dqlRef); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Article", $dqlRef->target()); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Article", $dqlRef->source()); + $this->assertSame($dqlRef, $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria)); + + $dql = "SELECT r, s FROM "."Doctrine\Tests\Models\DDC117\DDC117Reference r JOIN r.source s WHERE s.title = ?1"; + $dqlRef = $this->_em->createQuery($dql)->setParameter(1, 'Foo')->getSingleResult(); + + $this->_em->contains($dqlRef); + } + + /** + * @group DDC-117 + */ + public function testUpdateAssocationEntity() + { + $idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id()); + + $mapRef = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria); + $this->assertNotNull($mapRef); + $mapRef->setDescription("New Description!!"); + $this->_em->flush(); + $this->_em->clear(); + + $mapRef = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria); + + $this->assertEquals('New Description!!', $mapRef->getDescription()); + } + + /** + * @group DDC-117 + */ + public function testFetchDql() + { + $dql = "SELECT r, s FROM "."Doctrine\Tests\Models\DDC117\DDC117Reference r JOIN r.source s WHERE s.title = ?1"; + $refs = $this->_em->createQuery($dql)->setParameter(1, 'Foo')->getResult(); + + $this->assertTrue(count($refs) > 0, "Has to contain at least one Reference."); + + foreach ($refs AS $ref) { + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Reference", $ref, "Contains only Reference instances."); + $this->assertTrue($this->_em->contains($ref), "Contains Reference in the IdentityMap."); + } + } + + /** + * @group DDC-117 + */ + public function testRemoveCompositeElement() + { + $idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id()); + + $refRep = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria); + + $this->_em->remove($refRep); + $this->_em->flush(); + $this->_em->clear(); + + $this->assertNull($this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria)); + } + + /** + * @group DDC-117 + */ + public function testDqlRemoveCompositeElement() + { + $idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id()); + + $dql = "DELETE "."Doctrine\Tests\Models\DDC117\DDC117Reference r WHERE r.source = ?1 AND r.target = ?2"; + $this->_em->createQuery($dql) + ->setParameter(1, $this->article1->id()) + ->setParameter(2, $this->article2->id()) + ->execute(); + + $this->assertNull($this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria)); + } + + /** + * @group DDC-117 + */ + public function testInverseSideAccess() + { + $this->article1 = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Article", $this->article1->id()); + + $this->assertEquals(1, count($this->article1->references())); + + foreach ($this->article1->references() AS $this->reference) { + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Reference", $this->reference); + $this->assertSame($this->article1, $this->reference->source()); + } + + $this->_em->clear(); + + $dql = 'SELECT a, r FROM '. 'Doctrine\Tests\Models\DDC117\DDC117Article a INNER JOIN a.references r WHERE a.id = ?1'; + $articleDql = $this->_em->createQuery($dql) + ->setParameter(1, $this->article1->id()) + ->getSingleResult(); + + $this->assertEquals(1, count($this->article1->references())); + + foreach ($this->article1->references() AS $this->reference) { + $this->assertInstanceOf("Doctrine\Tests\Models\DDC117\DDC117Reference", $this->reference); + $this->assertSame($this->article1, $this->reference->source()); + } + } + + /** + * @group DDC-117 + */ + public function testMixedCompositeKey() + { + $idCriteria = array('article' => $this->article1->id(), 'language' => 'en'); + + $this->translation = $this->_em->find('Doctrine\Tests\Models\DDC117\DDC117Translation', $idCriteria); + $this->assertInstanceOf('Doctrine\Tests\Models\DDC117\DDC117Translation', $this->translation); + + $this->assertSame($this->translation, $this->_em->find('Doctrine\Tests\Models\DDC117\DDC117Translation', $idCriteria)); + + $this->_em->clear(); + + $dql = 'SELECT t, a FROM ' . 'Doctrine\Tests\Models\DDC117\DDC117Translation t JOIN t.article a WHERE t.article = ?1 AND t.language = ?2'; + $dqlTrans = $this->_em->createQuery($dql) + ->setParameter(1, $this->article1->id()) + ->setParameter(2, 'en') + ->getSingleResult(); + + $this->assertInstanceOf('Doctrine\Tests\Models\DDC117\DDC117Translation', $this->translation); + } + + /** + * @group DDC-117 + */ + public function testMixedCompositeKeyViolateUniqueness() + { + $this->article1 = $this->_em->find('Doctrine\Tests\Models\DDC117\DDC117Article', $this->article1->id()); + $this->article1->addTranslation('en', 'Bar'); + $this->article1->addTranslation('en', 'Baz'); + + $exceptionThrown = false; + try { + // exception depending on the underyling Database Driver + $this->_em->flush(); + } catch(\Exception $e) { + $exceptionThrown = true; + } + + $this->assertTrue($exceptionThrown, "The underlying database driver throws an exception."); + } + + /** + * @group DDC-117 + */ + public function testOneToOneForeignObjectId() + { + $this->article1 = new DDC117Article("Foo"); + $this->_em->persist($this->article1); + $this->_em->flush(); + + $this->articleDetails = new DDC117ArticleDetails($this->article1, "Very long text"); + $this->_em->persist($this->articleDetails); + $this->_em->flush(); + + $this->articleDetails->update("not so very long text!"); + $this->_em->flush(); + $this->_em->clear(); + + /* @var $article DDC117Article */ + $article = $this->_em->find(get_class($this->article1), $this->article1->id()); + $this->assertEquals('not so very long text!', $article->getText()); + } + + /** + * @group DDC-117 + */ + public function testOneToOneCascadeRemove() + { + $article = $this->_em->find(get_class($this->article1), $this->article1->id()); + $this->_em->remove($article); + $this->_em->flush(); + + $this->assertFalse($this->_em->contains($article->getDetails())); + } + + /** + * @group DDC-117 + */ + public function testOneToOneCascadePersist() + { + if (!$this->_em->getConnection()->getDatabasePlatform()->prefersSequences()) { + $this->markTestSkipped('Test only works with databases that prefer sequences as ID strategy.'); + } + + $this->article1 = new DDC117Article("Foo"); + + $this->articleDetails = new DDC117ArticleDetails($this->article1, "Very long text"); + + $this->_em->persist($this->article1); + $this->_em->flush(); + } + + /** + * @group DDC-117 + */ + public function testReferencesToForeignKeyEntities() + { + $idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id()); + $reference = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria); + + $idCriteria = array('article' => $this->article1->id(), 'language' => 'en'); + $translation = $this->_em->find('Doctrine\Tests\Models\DDC117\DDC117Translation', $idCriteria); + + $approveChanges = new DDC117ApproveChanges($reference->source()->getDetails(), $reference, $translation); + $this->_em->persist($approveChanges); + $this->_em->flush(); + $this->_em->clear(); + + $approveChanges = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117ApproveChanges", $approveChanges->getId()); + + $this->assertInstanceOf('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails', $approveChanges->getArticleDetails()); + $this->assertInstanceOf('Doctrine\Tests\Models\DDC117\DDC117Reference', $approveChanges->getReference()); + $this->assertInstanceOf('Doctrine\Tests\Models\DDC117\DDC117Translation', $approveChanges->getTranslation()); + } + + /** + * @group DDC-117 + */ + public function testLoadOneToManyCollectionOfForeignKeyEntities() + { + /* @var $article DDC117Article */ + $article = $this->_em->find(get_class($this->article1), $this->article1->id()); + + $translations = $article->getTranslations(); + $this->assertFalse($translations->isInitialized()); + $this->assertContainsOnly('Doctrine\Tests\Models\DDC117\DDC117Translation', $translations); + $this->assertTrue($translations->isInitialized()); + } + + /** + * @group DDC-117 + */ + public function testLoadManyToManyCollectionOfForeignKeyEntities() + { + $editor = $this->loadEditorFixture(); + + $this->assertFalse($editor->reviewingTranslations->isInitialized()); + $this->assertContainsOnly("Doctrine\Tests\Models\DDC117\DDC117Translation", $editor->reviewingTranslations); + $this->assertTrue($editor->reviewingTranslations->isInitialized()); + + $this->_em->clear(); + + $dql = "SELECT e, t FROM Doctrine\Tests\Models\DDC117\DDC117Editor e JOIN e.reviewingTranslations t WHERE e.id = ?1"; + $editor = $this->_em->createQuery($dql)->setParameter(1, $editor->id)->getSingleResult(); + $this->assertTrue($editor->reviewingTranslations->isInitialized()); + $this->assertContainsOnly("Doctrine\Tests\Models\DDC117\DDC117Translation", $editor->reviewingTranslations); + } + + /** + * @group DDC-117 + */ + public function testClearManyToManyCollectionOfForeignKeyEntities() + { + $editor = $this->loadEditorFixture(); + $this->assertEquals(3, count($editor->reviewingTranslations)); + + $editor->reviewingTranslations->clear(); + $this->_em->flush(); + $this->_em->clear(); + + $editor = $this->_em->find(get_class($editor), $editor->id); + $this->assertEquals(0, count($editor->reviewingTranslations)); + } + + /** + * @group DDC-117 + */ + public function testLoadInverseManyToManyCollection() + { + $editor = $this->loadEditorFixture(); + + $this->assertInstanceOf('Doctrine\Tests\Models\DDC117\DDC117Translation', $editor->reviewingTranslations[0]); + + $reviewedBy = $editor->reviewingTranslations[0]->getReviewedByEditors(); + $this->assertEquals(1, count($reviewedBy)); + $this->assertSame($editor, $reviewedBy[0]); + + $this->_em->clear(); + + $dql = "SELECT t, e FROM Doctrine\Tests\Models\DDC117\DDC117Translation t ". + "JOIN t.reviewedByEditors e WHERE t.article = ?1 AND t.language = ?2"; + $trans = $this->_em->createQuery($dql) + ->setParameter(1, $this->translation->getArticleId()) + ->setParameter(2, $this->translation->getLanguage()) + ->getSingleResult(); + + $this->assertInstanceOf('Doctrine\Tests\Models\DDC117\DDC117Translation', $trans); + $this->assertContainsOnly('Doctrine\Tests\Models\DDC117\DDC117Editor', $trans->reviewedByEditors); + $this->assertEquals(1, count($trans->reviewedByEditors)); + } + + /** + * @group DDC-117 + */ + public function testLoadOneToManyOfSourceEntityWithAssociationIdentifier() + { + $editor = $this->loadEditorFixture(); + + $editor->addLastTranslation($editor->reviewingTranslations[0]); + $this->_em->flush(); + $this->_em->clear(); + + $editor = $this->_em->find(get_class($editor), $editor->id); + $lastTranslatedBy = $editor->reviewingTranslations[0]->getLastTranslatedBy(); + $lastTranslatedBy->count(); + + $this->assertEquals(1, count($lastTranslatedBy)); + } + + /** + * @return DDC117Editor + */ + private function loadEditorFixture() + { + $editor = new DDC117Editor("beberlei"); + + /* @var $article1 DDC117Article */ + $article1 = $this->_em->find(get_class($this->article1), $this->article1->id()); + foreach ($article1->getTranslations() AS $translation) { + $editor->reviewingTranslations[] = $translation; + } + + /* @var $article2 DDC117Article */ + $article2 = $this->_em->find(get_class($this->article2), $this->article2->id()); + $article2->addTranslation("de", "Vanille-Krapferl"); // omnomnom + $article2->addTranslation("fr", "Sorry can't speak french!"); + + foreach ($article2->getTranslations() AS $translation) { + $this->_em->persist($translation); // otherwise persisting the editor won't work, reachability! + $editor->reviewingTranslations[] = $translation; + } + + $this->_em->persist($editor); + $this->_em->flush(); + $this->_em->clear(); + + return $this->_em->find(get_class($editor), $editor->id); + } + + /** + * @group DDC-1519 + */ + public function testMergeForeignKeyIdentifierEntity() + { + $idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id()); + + $refRep = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria); + + $this->_em->detach($refRep); + $refRep = $this->_em->merge($refRep); + + $this->assertEquals($this->article1->id(), $refRep->source()->id()); + $this->assertEquals($this->article2->id(), $refRep->target()->id()); + } + + /** + * @group DDC-1652 + */ + public function testArrayHydrationWithCompositeKey() + { + $dql = "SELECT r,s,t FROM Doctrine\Tests\Models\DDC117\DDC117Reference r INNER JOIN r.source s INNER JOIN r.target t"; + $before = count($this->_em->createQuery($dql)->getResult()); + + $this->article1 = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Article", $this->article1->id()); + $this->article2 = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Article", $this->article2->id()); + + $this->reference = new DDC117Reference($this->article2, $this->article1, "Test-Description"); + $this->_em->persist($this->reference); + + $this->reference = new DDC117Reference($this->article1, $this->article1, "Test-Description"); + $this->_em->persist($this->reference); + + $this->reference = new DDC117Reference($this->article2, $this->article2, "Test-Description"); + $this->_em->persist($this->reference); + + $this->_em->flush(); + + $dql = "SELECT r,s,t FROM Doctrine\Tests\Models\DDC117\DDC117Reference r INNER JOIN r.source s INNER JOIN r.target t"; + $data = $this->_em->createQuery($dql)->getArrayResult(); + + $this->assertEquals($before + 3, count($data)); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1181Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1181Test.php new file mode 100644 index 0000000..32856ac --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1181Test.php @@ -0,0 +1,101 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1181Hotel'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1181Booking'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1181Room'), + )); + } + + /** + * @group DDC-1181 + */ + public function testIssue() + { + $hotel = new DDC1181Hotel(); + $room1 = new DDC1181Room(); + $room2 = new DDC1181Room(); + + $this->_em->persist($hotel); + $this->_em->persist($room1); + $this->_em->persist($room2); + $this->_em->flush(); + + $booking1 = new DDC1181Booking; + $booking1->hotel = $hotel; + $booking1->room = $room1; + $booking2 = new DDC1181Booking; + $booking2->hotel = $hotel; + $booking2->room = $room2; + $hotel->bookings[] = $booking1; + $hotel->bookings[] = $booking2; + + $this->_em->persist($booking1); + $this->_em->persist($booking2); + $this->_em->flush(); + + $this->_em->remove($hotel); + $this->_em->flush(); + } +} + +/** + * @Entity + */ +class DDC1181Hotel +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + + /** + * @oneToMany(targetEntity="DDC1181Booking", mappedBy="hotel", cascade={"remove"}) + * @var Booking[] + */ + public $bookings; + +} + +/** + * @Entity + */ +class DDC1181Booking +{ + /** + * @var Hotel + * + * @Id + * @ManyToOne(targetEntity="DDC1181Hotel", inversedBy="bookings") + * @JoinColumns({ + * @JoinColumn(name="hotel_id", referencedColumnName="id") + * }) + */ + public $hotel; + /** + * @var Room + * + * @Id + * @ManyToOne(targetEntity="DDC1181Room") + * @JoinColumns({ + * @JoinColumn(name="room_id", referencedColumnName="id") + * }) + */ + public $room; +} + +/** + * @Entity + */ +class DDC1181Room +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1193Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1193Test.php new file mode 100644 index 0000000..6465fa6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1193Test.php @@ -0,0 +1,93 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1193Company'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1193Person'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1193Account') + )); + } + + /** + * @group DDC-1193 + */ + public function testIssue() + { + $company = new DDC1193Company(); + $person = new DDC1193Person(); + $account = new DDC1193Account(); + + $person->account = $account; + $person->company = $company; + + $company->member = $person; + + $this->_em->persist($company); + + $this->_em->flush(); + + $companyId = $company->id; + $accountId = $account->id; + $this->_em->clear(); + + $company = $this->_em->find(get_class($company), $companyId); + + $this->assertTrue($this->_em->getUnitOfWork()->isInIdentityMap($company), "Company is in identity map."); + $this->assertFalse($company->member->__isInitialized__, "Pre-Condition"); + $this->assertTrue($this->_em->getUnitOfWork()->isInIdentityMap($company->member), "Member is in identity map."); + + $this->_em->remove($company); + $this->_em->flush(); + + $this->assertEquals(count($this->_em->getRepository(get_class($account))->findAll()), 0); + } +} + +/** @Entity */ +class DDC1193Company { + /** + * @Id @Column(type="integer") + * @GeneratedValue + */ + public $id; + + /** @OneToOne(targetEntity="DDC1193Person", cascade={"persist", "remove"}) */ + public $member; + +} + +/** @Entity */ +class DDC1193Person { + /** + * @Id @Column(type="integer") + * @GeneratedValue + */ + public $id; + + /** + * @OneToOne(targetEntity="DDC1193Account", cascade={"persist", "remove"}) + */ + public $account; +} + +/** @Entity */ +class DDC1193Account { + /** + * @Id @Column(type="integer") + * @GeneratedValue + */ + public $id; + +} + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1209Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1209Test.php new file mode 100644 index 0000000..bddbbdf --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1209Test.php @@ -0,0 +1,125 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1209_1'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1209_2'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1209_3') + )); + } catch(\Exception $e) { + } + } + + /** + * @group DDC-1209 + */ + public function testIdentifierCanHaveCustomType() + { + $this->_em->persist(new DDC1209_3()); + $this->_em->flush(); + } + + /** + * @group DDC-1209 + */ + public function testCompositeIdentifierCanHaveCustomType() + { + $future1 = new DDC1209_1(); + $this->_em->persist($future1); + + $this->_em->flush(); + + $future2 = new DDC1209_2($future1); + $this->_em->persist($future2); + + $this->_em->flush(); + } +} + +/** + * @Entity + */ +class DDC1209_1 +{ + /** + * @Id @GeneratedValue @Column(type="integer") + */ + private $id; + + public function getId() + { + return $this->id; + } +} + +/** + * @Entity + */ +class DDC1209_2 +{ + /** + * @Id + * @ManyToOne(targetEntity="DDC1209_1") + * @JoinColumn(referencedColumnName="id", nullable=false) + */ + private $future1; + /** + * @Id + * @Column(type="datetime", nullable=false) + */ + private $starting_datetime; + /** + * @Id + * @Column(type="datetime", nullable=false) + */ + private $during_datetime; + /** + * @Id + * @Column(type="datetime", nullable=false) + */ + private $ending_datetime; + + public function __construct(DDC1209_1 $future1) + { + $this->future1 = $future1; + $this->starting_datetime = new DateTime2(); + $this->during_datetime = new DateTime2(); + $this->ending_datetime = new DateTime2(); + } +} + +/** + * @Entity + */ +class DDC1209_3 +{ + /** + * @Id + * @Column(type="datetime", name="somedate") + */ + private $date; + + public function __construct() + { + $this->date = new DateTime2(); + } +} + +class DateTime2 extends \DateTime +{ + public function __toString() + { + return $this->format('Y'); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1225Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1225Test.php new file mode 100644 index 0000000..95dcc2b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1225Test.php @@ -0,0 +1,85 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1225_TestEntity1'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1225_TestEntity2'), + )); + } catch(\PDOException $e) { + + } + } + + public function testIssue() + { + $qb = $this->_em->createQueryBuilder(); + $qb->from('Doctrine\Tests\ORM\Functional\Ticket\DDC1225_TestEntity1', 'te1') + ->select('te1') + ->where('te1.testEntity2 = ?1') + ->setParameter(1, 0); + + $this->assertEquals( + strtolower('SELECT t0_.test_entity2_id AS test_entity2_id0 FROM te1 t0_ WHERE t0_.test_entity2_id = ?'), + strtolower($qb->getQuery()->getSQL()) + ); + } +} + +/** + * @Entity + * @Table(name="te1") + */ +class DDC1225_TestEntity1 +{ + /** + * @Id + * @ManyToOne(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\DDC1225_TestEntity2") + * @JoinColumn(name="test_entity2_id", referencedColumnName="id", nullable=false) + */ + private $testEntity2; + + /** + * @param DDC1225_TestEntity2 $testEntity2 + */ + public function setTestEntity2(DDC1225_TestEntity2 $testEntity2) + { + $this->testEntity2 = $testEntity2; + } + + /** + * @return DDC1225_TestEntity2 + */ + public function getTestEntity2() + { + return $this->testEntity2; + } +} + +/** + * @Entity + * @Table(name="te2") + */ +class DDC1225_TestEntity2 +{ + /** + * @Id + * @GeneratedValue(strategy="AUTO") + * @Column(type="integer") + */ + private $id; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1228Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1228Test.php new file mode 100644 index 0000000..6e14e21 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1228Test.php @@ -0,0 +1,136 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228User'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228Profile'), + )); + } catch(\Exception $e) { + + } + } + + public function testOneToOnePersist() + { + $user = new DDC1228User; + $profile = new DDC1228Profile(); + $profile->name = "Foo"; + $user->profile = $profile; + + $this->_em->persist($user); + $this->_em->persist($profile); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id); + + $this->assertFalse($user->getProfile()->__isInitialized__, "Proxy is not initialized"); + $user->getProfile()->setName("Bar"); + $this->assertTrue($user->getProfile()->__isInitialized__, "Proxy is not initialized"); + + $this->assertEquals("Bar", $user->getProfile()->getName()); + $this->assertEquals(array("id" => 1, "name" => "Foo"), $this->_em->getUnitOfWork()->getOriginalEntityData($user->getProfile())); + + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id); + $this->assertEquals("Bar", $user->getProfile()->getName()); + } + + public function testRefresh() + { + $user = new DDC1228User; + $profile = new DDC1228Profile(); + $profile->name = "Foo"; + $user->profile = $profile; + + $this->_em->persist($user); + $this->_em->persist($profile); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1228User', $user->id); + + $this->_em->refresh($user); + $user->name = "Baz"; + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id); + $this->assertEquals("Baz", $user->name); + } +} + +/** + * @Entity + */ +class DDC1228User +{ + /** + * @Id @Column(type="integer") @GeneratedValue + * @var int + */ + public $id; + + /** + * @Column(type="string") + * @var string + */ + public $name = 'Bar'; + + /** + * @OneToOne(targetEntity="DDC1228Profile") + * @var Profile + */ + public $profile; + + public function getProfile() + { + return $this->profile; + } +} + +/** + * @Entity + */ +class DDC1228Profile +{ + /** + * @Id @Column(type="integer") @GeneratedValue + * @var int + */ + public $id; + + /** + * @column(type="string") + * @var string + */ + public $name; + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1238Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1238Test.php new file mode 100644 index 0000000..6783928 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1238Test.php @@ -0,0 +1,100 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1238User'), + )); + } catch(\Exception $e) { + + } + } + + public function testIssue() + { + $user = new DDC1238User; + $user->setName("test"); + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $userId = $user->getId(); + $this->_em->clear(); + + $user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId); + $this->_em->clear(); + + $userId2 = $user->getId(); + $this->assertEquals($userId, $userId2, "This proxy can still be initialized."); + } + + public function testIssueProxyClear() + { + $user = new DDC1238User; + $user->setName("test"); + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + // force proxy load, getId() doesn't work anymore + $user->getName(); + $userId = $user->getId(); + $this->_em->clear(); + + $user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId); + $this->_em->clear(); + + $user2 = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId); + + // force proxy load, getId() doesn't work anymore + $user->getName(); + $this->assertNull($user->getId(), "Now this is null, we already have a user instance of that type"); + } +} + +/** + * @Entity + */ +class DDC1238User +{ + /** @Id @GeneratedValue @Column(type="integer") */ + private $id; + + /** + * @Column + * @var string + */ + private $name; + + public function getId() + { + return $this->id; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1250Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1250Test.php new file mode 100644 index 0000000..3a756da --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1250Test.php @@ -0,0 +1,96 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1250ClientHistory'), + )); + } catch(\PDOException $e) { + + } + } + + public function testIssue() + { + $c1 = new DDC1250ClientHistory; + $c2 = new DDC1250ClientHistory; + $c1->declinedClientsHistory = $c2; + $c1->declinedBy = $c2; + $c2->declinedBy = $c1; + $c2->declinedClientsHistory= $c1; + + $this->_em->persist($c1); + $this->_em->persist($c2); + $this->_em->flush(); + $this->_em->clear(); + + $history = $this->_em->createQuery('SELECT h FROM ' . __NAMESPACE__ . '\\DDC1250ClientHistory h WHERE h.id = ?1') + ->setParameter(1, $c2->id)->getSingleResult(); + + $this->assertInstanceOf(__NAMESPACE__ . '\\DDC1250ClientHistory', $history); + } +} + +/** + * @Entity + */ +class DDC1250ClientHistory +{ + /** @Id @GeneratedValue @Column(type="integer") */ + public $id; + + /** @OneToOne(targetEntity="DDC1250ClientHistory", inversedBy="declinedBy") + * @JoinColumn(name="declined_clients_history_id", referencedColumnName="id") + */ + public $declinedClientsHistory; + + /** + * @OneToOne(targetEntity="DDC1250ClientHistory", mappedBy="declinedClientsHistory") + * @var + */ + public $declinedBy; +} + +/** + * +Entities\ClientsHistory: +type: entity +table: clients_history +fields: +id: +id: true +type: integer +unsigned: false +nullable: false +generator: +strategy: IDENTITY +[...skiped...] +oneToOne: +declinedClientsHistory: +targetEntity: Entities\ClientsHistory +joinColumn: +name: declined_clients_history_id +referencedColumnName: id +inversedBy: declinedBy +declinedBy: +targetEntity: Entities\ClientsHistory +mappedBy: declinedClientsHistory +lifecycleCallbacks: { } +repositoryClass: Entities\ClientsHistoryRepository + + + */ \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1276Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1276Test.php new file mode 100644 index 0000000..a4f54b5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1276Test.php @@ -0,0 +1,50 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testIssue() + { + $user = new CmsUser(); + $user->name = "Benjamin"; + $user->username = "beberlei"; + $user->status = "active"; + $this->_em->persist($user); + + for ($i = 0; $i < 2; $i++) { + $group = new CmsGroup(); + $group->name = "group".$i; + $user->groups[] = $group; + $this->_em->persist($group); + } + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->id); + $cloned = clone $user; + + $this->assertSame($user->groups, $cloned->groups); + $this->assertEquals(2, count($user->groups)); + $this->_em->merge($cloned); + + $this->assertEquals(2, count($user->groups)); + + $this->_em->flush(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1300Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1300Test.php new file mode 100644 index 0000000..38278dc --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1300Test.php @@ -0,0 +1,108 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1300Foo'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1300FooLocale'), + )); + } + + public function testIssue() + { + $foo = new DDC1300Foo(); + $foo->_fooReference = "foo"; + + $this->_em->persist($foo); + $this->_em->flush(); + + $locale = new DDC1300FooLocale(); + $locale->_foo = $foo; + $locale->_locale = "en"; + $locale->_title = "blub"; + + $this->_em->persist($locale); + $this->_em->flush(); + + $query = $this->_em->createQuery('SELECT f, fl FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1300Foo f JOIN f._fooLocaleRefFoo fl'); + $result = $query->getResult(); + + $this->assertEquals(1, count($result)); + } +} + +/** + * @Entity + */ +class DDC1300Foo +{ + /** + * @var integer fooID + * @Column(name="fooID", type="integer", nullable=false) + * @GeneratedValue(strategy="AUTO") + * @Id + */ + public $_fooID = null; + + /** + * @var string fooReference + * @Column(name="fooReference", type="string", nullable=true, length=45) + */ + public $_fooReference = null; + + /** + * @OneToMany(targetEntity="DDC1300FooLocale", mappedBy="_foo", + * cascade={"persist"}) + */ + public $_fooLocaleRefFoo = null; + + /** + * Constructor + * + * @param array|Zend_Config|null $options + * @return Bug_Model_Foo + */ + public function __construct($options = null) + { + $this->_fooLocaleRefFoo = new \Doctrine\Common\Collections\ArrayCollection(); + } + +} + +/** + * @Entity + */ +class DDC1300FooLocale +{ + + /** + * @ManyToOne(targetEntity="DDC1300Foo") + * @JoinColumn(name="fooID", referencedColumnName="fooID") + * @Id + */ + public $_foo = null; + + /** + * @var string locale + * @Column(name="locale", type="string", nullable=false, length=5) + * @Id + */ + public $_locale = null; + + /** + * @var string title + * @Column(name="title", type="string", nullable=true, length=150) + */ + public $_title = null; + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1301Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1301Test.php new file mode 100644 index 0000000..94d02f9 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1301Test.php @@ -0,0 +1,148 @@ +useModelSet('legacy'); + parent::setUp(); + + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\Legacy\LegacyUser'); + $class->associationMappings['_articles']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['_references']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['_cars']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + + $this->loadFixture(); + } + + public function tearDown() + { + parent::tearDown(); + + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\Legacy\LegacyUser'); + $class->associationMappings['_articles']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + $class->associationMappings['_references']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + $class->associationMappings['_cars']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + } + + public function testCountNotInitializesLegacyCollection() + { + $user = $this->_em->find('Doctrine\Tests\Models\Legacy\LegacyUser', $this->userId); + $queryCount = $this->getCurrentQueryCount(); + + $this->assertFalse($user->_articles->isInitialized()); + $this->assertEquals(2, count($user->_articles)); + $this->assertFalse($user->_articles->isInitialized()); + + foreach ($user->_articles AS $article) { } + + $this->assertEquals($queryCount + 2, $this->getCurrentQueryCount(), "Expecting two queries to be fired for count, then iteration."); + } + + public function testCountNotInitializesLegacyCollectionWithForeignIdentifier() + { + $user = $this->_em->find('Doctrine\Tests\Models\Legacy\LegacyUser', $this->userId); + $queryCount = $this->getCurrentQueryCount(); + + $this->assertFalse($user->_references->isInitialized()); + $this->assertEquals(2, count($user->_references)); + $this->assertFalse($user->_references->isInitialized()); + + foreach ($user->_references AS $reference) { } + + $this->assertEquals($queryCount + 2, $this->getCurrentQueryCount(), "Expecting two queries to be fired for count, then iteration."); + } + + public function testCountNotInitializesLegacyManyToManyCollection() + { + $user = $this->_em->find('Doctrine\Tests\Models\Legacy\LegacyUser', $this->userId); + $queryCount = $this->getCurrentQueryCount(); + + $this->assertFalse($user->_cars->isInitialized()); + $this->assertEquals(3, count($user->_cars)); + $this->assertFalse($user->_cars->isInitialized()); + + foreach ($user->_cars AS $reference) { } + + $this->assertEquals($queryCount + 2, $this->getCurrentQueryCount(), "Expecting two queries to be fired for count, then iteration."); + } + + public function loadFixture() + { + $user1 = new \Doctrine\Tests\Models\Legacy\LegacyUser(); + $user1->_username = "beberlei"; + $user1->_name = "Benjamin"; + $user1->_status = "active"; + + $user2 = new \Doctrine\Tests\Models\Legacy\LegacyUser(); + $user2->_username = "jwage"; + $user2->_name = "Jonathan"; + $user2->_status = "active"; + + $user3 = new \Doctrine\Tests\Models\Legacy\LegacyUser(); + $user3->_username = "romanb"; + $user3->_name = "Roman"; + $user3->_status = "active"; + + $this->_em->persist($user1); + $this->_em->persist($user2); + $this->_em->persist($user3); + + $article1 = new \Doctrine\Tests\Models\Legacy\LegacyArticle(); + $article1->_topic = "Test"; + $article1->_text = "Test"; + $article1->setAuthor($user1); + + $article2 = new \Doctrine\Tests\Models\Legacy\LegacyArticle(); + $article2->_topic = "Test"; + $article2->_text = "Test"; + $article2->setAuthor($user1); + + $this->_em->persist($article1); + $this->_em->persist($article2); + + $car1 = new \Doctrine\Tests\Models\Legacy\LegacyCar(); + $car1->_description = "Test1"; + + $car2 = new \Doctrine\Tests\Models\Legacy\LegacyCar(); + $car2->_description = "Test2"; + + $car3 = new \Doctrine\Tests\Models\Legacy\LegacyCar(); + $car3->_description = "Test3"; + + $user1->addCar($car1); + $user1->addCar($car2); + $user1->addCar($car3); + + $user2->addCar($car1); + $user3->addCar($car1); + + $this->_em->persist($car1); + $this->_em->persist($car2); + $this->_em->persist($car3); + + $this->_em->flush(); + + $detail1 = new \Doctrine\Tests\Models\Legacy\LegacyUserReference($user1, $user2, "foo"); + $detail2 = new \Doctrine\Tests\Models\Legacy\LegacyUserReference($user1, $user3, "bar"); + + $this->_em->persist($detail1); + $this->_em->persist($detail2); + + $this->_em->flush(); + $this->_em->clear(); + + $this->userId = $user1->getId(); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1306Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1306Test.php new file mode 100644 index 0000000..b143b00 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1306Test.php @@ -0,0 +1,54 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testIssue() + { + $phone = new CmsPhonenumber(); + $phone->phonenumber = "1234"; + + // puts user and phone into commit order calculator + $this->_em->persist($phone); + $this->_em->flush(); + + $address = new \Doctrine\Tests\Models\CMS\CmsAddress(); + $address->city = "bonn"; + $address->country = "Germany"; + $address->street = "somestreet!"; + $address->zip = 12345; + + $this->_em->persist($address); + + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "benjamin"; + $user->status = "active"; + $user->setAddress($address); + + // puts user and address into commit order calculator, but does not calculate user dependencies new + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->remove($user->getAddress()); + $this->_em->remove($user); + $this->_em->flush(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1335Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1335Test.php new file mode 100644 index 0000000..0500a0e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1335Test.php @@ -0,0 +1,218 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335User'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335Phone'), + )); + $this->loadFixture(); + } catch(\Exception $e) { + } + } + + + public function testDql() + { + $dql = 'SELECT u FROM ' . __NAMESPACE__ . '\DDC1335User u INDEX BY u.id'; + $query = $this->_em->createQuery($dql); + $result = $query->getResult(); + + $this->assertEquals(sizeof($result), 3); + $this->assertArrayHasKey(1, $result); + $this->assertArrayHasKey(2, $result); + $this->assertArrayHasKey(3, $result); + + $dql = 'SELECT u, p FROM '.__NAMESPACE__ . '\DDC1335User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id'; + $query = $this->_em->createQuery($dql); + $result = $query->getResult(); + + $this->assertEquals(sizeof($result), 3); + $this->assertArrayHasKey('foo@foo.com', $result); + $this->assertArrayHasKey('bar@bar.com', $result); + $this->assertArrayHasKey('foobar@foobar.com', $result); + + $this->assertEquals(sizeof($result['foo@foo.com']->phones), 3); + $this->assertEquals(sizeof($result['bar@bar.com']->phones), 3); + $this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3); + + $foo = $result['foo@foo.com']->phones->toArray(); + $bar = $result['bar@bar.com']->phones->toArray(); + $foobar = $result['foobar@foobar.com']->phones->toArray(); + + $this->assertArrayHasKey(1, $foo); + $this->assertArrayHasKey(2, $foo); + $this->assertArrayHasKey(3, $foo); + + $this->assertArrayHasKey(4, $bar); + $this->assertArrayHasKey(5, $bar); + $this->assertArrayHasKey(6, $bar); + + $this->assertArrayHasKey(7, $foobar); + $this->assertArrayHasKey(8, $foobar); + $this->assertArrayHasKey(9, $foobar); + } + + public function testTicket() + { + $builder = $this->_em->createQueryBuilder(); + $builder->select('u')->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.id'); + + $dql = $builder->getQuery()->getDQL(); + $result = $builder->getQuery()->getResult(); + + $this->assertEquals(sizeof($result), 3); + $this->assertArrayHasKey(1, $result); + $this->assertArrayHasKey(2, $result); + $this->assertArrayHasKey(3, $result); + $this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1335User u INDEX BY u.id', $dql); + } + + public function testIndexByUnique() + { + $builder = $this->_em->createQueryBuilder(); + $builder->select('u')->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.email'); + + $dql = $builder->getQuery()->getDQL(); + $result = $builder->getQuery()->getResult(); + + $this->assertEquals(sizeof($result), 3); + $this->assertArrayHasKey('foo@foo.com', $result); + $this->assertArrayHasKey('bar@bar.com', $result); + $this->assertArrayHasKey('foobar@foobar.com', $result); + $this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1335User u INDEX BY u.email', $dql); + } + + public function testIndexWithJoin() + { + $builder = $this->_em->createQueryBuilder(); + $builder->select('u','p') + ->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.email') + ->join('u.phones', 'p', null, null, 'p.id'); + + $dql = $builder->getQuery()->getDQL(); + $result = $builder->getQuery()->getResult(); + + $this->assertEquals(sizeof($result), 3); + $this->assertArrayHasKey('foo@foo.com', $result); + $this->assertArrayHasKey('bar@bar.com', $result); + $this->assertArrayHasKey('foobar@foobar.com', $result); + + $this->assertEquals(sizeof($result['foo@foo.com']->phones), 3); + $this->assertEquals(sizeof($result['bar@bar.com']->phones), 3); + $this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3); + + $this->assertArrayHasKey(1, $result['foo@foo.com']->phones->toArray()); + $this->assertArrayHasKey(2, $result['foo@foo.com']->phones->toArray()); + $this->assertArrayHasKey(3, $result['foo@foo.com']->phones->toArray()); + + $this->assertArrayHasKey(4, $result['bar@bar.com']->phones->toArray()); + $this->assertArrayHasKey(5, $result['bar@bar.com']->phones->toArray()); + $this->assertArrayHasKey(6, $result['bar@bar.com']->phones->toArray()); + + $this->assertArrayHasKey(7, $result['foobar@foobar.com']->phones->toArray()); + $this->assertArrayHasKey(8, $result['foobar@foobar.com']->phones->toArray()); + $this->assertArrayHasKey(9, $result['foobar@foobar.com']->phones->toArray()); + + $this->assertEquals('SELECT u, p FROM '.__NAMESPACE__ . '\DDC1335User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id', $dql); + } + + private function loadFixture() + { + $p1 = array('11 xxxx-xxxx','11 yyyy-yyyy','11 zzzz-zzzz'); + $p2 = array('22 xxxx-xxxx','22 yyyy-yyyy','22 zzzz-zzzz'); + $p3 = array('33 xxxx-xxxx','33 yyyy-yyyy','33 zzzz-zzzz'); + + $u1 = new DDC1335User("foo@foo.com", "Foo",$p1); + $u2 = new DDC1335User("bar@bar.com", "Bar",$p2); + $u3 = new DDC1335User("foobar@foobar.com", "Foo Bar",$p3); + + $this->_em->persist($u1); + $this->_em->persist($u2); + $this->_em->persist($u3); + $this->_em->flush(); + $this->_em->clear(); + } + +} + +/** + * @Entity + */ +class DDC1335User +{ + /** + * @Id @Column(type="integer") + * @GeneratedValue + */ + public $id; + + /** + * @Column(type="string", unique=true) + */ + public $email; + + /** + * @Column(type="string") + */ + public $name; + + /** + * @OneToMany(targetEntity="DDC1335Phone", mappedBy="user", cascade={"persist", "remove"}) + */ + public $phones; + + public function __construct($email, $name, array $numbers = array()) + { + $this->name = $name; + $this->email = $email; + $this->phones = new \Doctrine\Common\Collections\ArrayCollection(); + + foreach ($numbers as $number) { + $this->phones->add(new DDC1335Phone($this,$number)); + } + } +} + +/** + * @Entity + */ +class DDC1335Phone +{ + /** + * @Id + * @Column(name="id", type="integer") + * @GeneratedValue + */ + public $id; + + /** + * @Column(name="numericalValue", type="string", nullable = false) + */ + public $numericalValue; + + /** + * @ManyToOne(targetEntity="DDC1335User", inversedBy="phones") + * @JoinColumn(name="user_id", referencedColumnName="id", nullable = false) + */ + public $user; + + public function __construct($user, $number) + { + $this->user = $user; + $this->numericalValue = $number; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1360Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1360Test.php new file mode 100644 index 0000000..38f5837 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1360Test.php @@ -0,0 +1,37 @@ +_em->getConnection()->getDatabasePlatform()->getName() != "postgresql") { + $this->markTestSkipped("PostgreSQL only test."); + } + + $sql = $this->_schemaTool->getCreateSchemaSQL(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1360DoubleQuote') + )); + + $this->assertEquals(array( + 'CREATE TABLE "user"."user" (id INT NOT NULL, PRIMARY KEY(id))', + 'CREATE SEQUENCE "user"."user_id_seq" INCREMENT BY 1 MINVALUE 1 START 1', + ), $sql); + } +} + +/** + * @Entity @Table(name="`user`.`user`") + */ +class DDC1360DoubleQuote +{ + /** @Id @GeneratedValue @Column(type="integer") */ + public $id; +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1383Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1383Test.php new file mode 100644 index 0000000..f6b5a24 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1383Test.php @@ -0,0 +1,99 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1383AbstractEntity'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1383Entity'), + )); + } catch(\Exception $ignored) {} + } + + public function testFailingCase() + { + $parent = new DDC1383Entity(); + $child = new DDC1383Entity(); + + $child->setReference($parent); + + $this->_em->persist($parent); + $this->_em->persist($child); + + $id = $child->getId(); + + $this->_em->flush(); + $this->_em->clear(); + + // Try merging the parent entity + $child = $this->_em->merge($child); + $parent = $child->getReference(); + + // Parent is not instance of the abstract class + self::assertTrue($parent instanceof DDC1383AbstractEntity, + "Entity class is " . get_class($parent) . ', "DDC1383AbstractEntity" was expected'); + + // Parent is NOT instance of entity + self::assertTrue($parent instanceof DDC1383Entity, + "Entity class is " . get_class($parent) . ', "DDC1383Entity" was expected'); + } +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="integer") + * @DiscriminatorMap({1 = "DDC1383Entity"}) + */ +abstract class DDC1383AbstractEntity +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + protected $id; + + public function getId() + { + return $this->id; + } + + public function setId($id) + { + $this->id = $id; + } +} + +/** + * @Entity + */ +class DDC1383Entity extends DDC1383AbstractEntity +{ + /** + * @ManyToOne(targetEntity="DDC1383AbstractEntity") + */ + protected $reference; + + public function getReference() + { + return $this->reference; + } + + public function setReference(DDC1383AbstractEntity $reference) + { + $this->reference = $reference; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1392Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1392Test.php new file mode 100644 index 0000000..095b197 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1392Test.php @@ -0,0 +1,127 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1392File'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1392Picture'), + )); + } catch (\Exception $ignored) { + } + } + + public function testFailingCase() + { + $file = new DDC1392File; + + $picture = new DDC1392Picture; + $picture->setFile($file); + + $em = $this->_em; + $em->persist($picture); + $em->flush(); + $em->clear(); + + $fileId = $file->getFileId(); + $pictureId = $picture->getPictureId(); + + $this->assertTrue($fileId > 0); + + $picture = $em->find(__NAMESPACE__ . '\DDC1392Picture', $pictureId); + $this->assertEquals(UnitOfWork::STATE_MANAGED, $em->getUnitOfWork()->getEntityState($picture->getFile()), "Lazy Proxy should be marked MANAGED."); + + $file = $picture->getFile(); + + // With this activated there will be no problem + //$file->__load(); + + $picture->setFile(null); + + $em->clear(); + + $em->merge($file); + + $em->flush(); + + $q = $this->_em->createQuery("SELECT COUNT(e) FROM " . __NAMESPACE__ . '\DDC1392File e'); + $result = $q->getSingleScalarResult(); + + self::assertEquals(1, $result); + } +} + +/** + * @Entity + */ +class DDC1392Picture +{ + /** + * @Column(name="picture_id", type="integer") + * @Id @GeneratedValue + */ + private $pictureId; + + /** + * @ManyToOne(targetEntity="DDC1392File", cascade={"persist", "remove"}) + * @JoinColumn(name="file_id", referencedColumnName="file_id") + */ + private $file; + + /** + * Get pictureId + */ + public function getPictureId() + { + return $this->pictureId; + } + + /** + * Set file + */ + public function setFile($value = null) + { + $this->file = $value; + } + + /** + * Get file + */ + public function getFile() + { + return $this->file; + } +} + +/** + * @Entity + */ +class DDC1392File +{ + /** + * @Column(name="file_id", type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + public $fileId; + + /** + * Get fileId + */ + public function getFileId() + { + return $this->fileId; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php new file mode 100644 index 0000000..2523b5b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1400Test.php @@ -0,0 +1,131 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1400Article'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1400User'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1400UserState'), + )); + } catch (\Exception $ignored) { + } + } + + public function testFailingCase() + { + $article = new DDC1400Article; + $user1 = new DDC1400User; + $user2 = new DDC1400User; + + $this->_em->persist($article); + $this->_em->persist($user1); + $this->_em->persist($user2); + $this->_em->flush(); + + $userState1 = new DDC1400UserState; + $userState1->article = $article; + $userState1->articleId = $article->id; + $userState1->user = $user1; + $userState1->userId = $user1->id; + + $userState2 = new DDC1400UserState; + $userState2->article = $article; + $userState2->articleId = $article->id; + $userState2->user = $user2; + $userState2->userId = $user2->id; + + $this->_em->persist($userState1); + $this->_em->persist($userState2); + + $this->_em->flush(); + $this->_em->clear(); + + $user1 = $this->_em->getReference(__NAMESPACE__.'\DDC1400User', $user1->id); + + $q = $this->_em->createQuery("SELECT a, s FROM ".__NAMESPACE__."\DDC1400Article a JOIN a.userStates s WITH s.user = :activeUser"); + $q->setParameter('activeUser', $user1); + $articles = $q->getResult(); + + $this->_em->flush(); + } +} + +/** + * @Entity + */ +class DDC1400Article +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + public $id; + + /** + * @OneToMany(targetEntity="DDC1400UserState", mappedBy="article", indexBy="userId", fetch="EXTRA_LAZY") + */ + public $userStates; +} + +/** + * @Entity + */ +class DDC1400User +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + public $id; + + /** + * @OneToMany(targetEntity="DDC1400UserState", mappedBy="user", indexBy="articleId", fetch="EXTRA_LAZY") + */ + public $userStates; +} + +/** + * @Entity + */ +class DDC1400UserState +{ + + /** + * @Id + * @ManyToOne(targetEntity="DDC1400Article", inversedBy="userStates") + */ + public $article; + + /** + * @Id + * @ManyToOne(targetEntity="DDC1400User", inversedBy="userStates") + */ + public $user; + + /** + * @Column(name="user_id", type="integer") + */ + public $userId; + + /** + * @Column(name="article_id", type="integer") + */ + public $articleId; + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1404Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1404Test.php new file mode 100644 index 0000000..cc1d7c9 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1404Test.php @@ -0,0 +1,129 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1404ParentEntity'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1404ChildEntity'), + )); + + $this->loadFixtures(); + + } catch (Exception $exc) { + } + } + + public function testTicket() + { + $repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC1404ChildEntity'); + $queryAll = $repository->createNamedQuery('all'); + $queryFirst = $repository->createNamedQuery('first'); + $querySecond = $repository->createNamedQuery('second'); + + + $this->assertEquals('SELECT p FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1404ChildEntity p', $queryAll->getDQL()); + $this->assertEquals('SELECT p FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1404ChildEntity p WHERE p.id = 1', $queryFirst->getDQL()); + $this->assertEquals('SELECT p FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1404ChildEntity p WHERE p.id = 2', $querySecond->getDQL()); + + + $this->assertEquals(sizeof($queryAll->getResult()), 2); + $this->assertEquals(sizeof($queryFirst->getResult()), 1); + $this->assertEquals(sizeof($querySecond->getResult()), 1); + } + + + public function loadFixtures() + { + $c1 = new DDC1404ChildEntity("ChildEntity 1"); + $c2 = new DDC1404ChildEntity("ChildEntity 2"); + + $this->_em->persist($c1); + $this->_em->persist($c2); + + $this->_em->flush(); + } + +} + +/** + * @MappedSuperclass + * + * @NamedQueries({ + * @NamedQuery(name="all", query="SELECT p FROM __CLASS__ p"), + * @NamedQuery(name="first", query="SELECT p FROM __CLASS__ p WHERE p.id = 1"), + * }) + */ +class DDC1404ParentEntity +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue() + */ + protected $id; + + /** + * @return integer + */ + public function getId() + { + return $this->id; + } + +} + +/** + * @Entity + * + * @NamedQueries({ + * @NamedQuery(name="first", query="SELECT p FROM __CLASS__ p WHERE p.id = 1"), + * @NamedQuery(name="second", query="SELECT p FROM __CLASS__ p WHERE p.id = 2") + * }) + */ +class DDC1404ChildEntity extends DDC1404ParentEntity +{ + + /** + * @column(type="string") + */ + private $name; + + /** + * @param string $name + */ + public function __construct($name) + { + $this->name = $name; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC142Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC142Test.php new file mode 100644 index 0000000..6965c6e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC142Test.php @@ -0,0 +1,89 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\User'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Group'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Phone'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Address'), + )); + } catch(\Exception $e) { + } + } + + public function testCreateRetreaveUpdateDelete() + { + + $user = new User; + $user->name = 'FabioBatSilva'; + $this->_em->persist($user); + + $address = new Address; + $address->zip = '12345'; + $this->_em->persist($address); + + $this->_em->flush(); + + $addressRef = $this->_em->getReference('Doctrine\Tests\Models\Quote\Address', $address->getId()); + + $user->setAddress($addressRef); + + $this->_em->flush(); + $this->_em->clear(); + + $id = $user->id; + $this->assertNotNull($id); + + + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $id); + $address = $user->getAddress(); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Address', $user->getAddress()); + + $this->assertEquals('FabioBatSilva', $user->name); + $this->assertEquals('12345', $address->zip); + + + $user->name = 'FabioBatSilva1'; + $user->address = null; + + $this->_em->persist($user); + $this->_em->remove($address); + $this->_em->flush(); + $this->_em->clear(); + + + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $id); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertNull($user->getAddress()); + + $this->assertEquals('FabioBatSilva1', $user->name); + + + $this->_em->remove($user); + $this->_em->flush(); + $this->_em->clear(); + + $this->assertNull($this->_em->find('Doctrine\Tests\Models\Quote\User', $id)); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1430Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1430Test.php new file mode 100644 index 0000000..a810223 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1430Test.php @@ -0,0 +1,297 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1430Order'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1430OrderProduct'), + )); + $this->loadFixtures(); + } catch (\Exception $exc) { + + } + } + + public function testOrderByFields() + { + $repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC1430Order'); + $builder = $repository->createQueryBuilder('o'); + $query = $builder->select('o.id, o.date, COUNT(p.id) AS p_count') + ->leftJoin('o.products', 'p') + ->groupBy('o.id, o.date') + ->orderBy('o.id') + ->getQuery(); + + $this->assertEquals('SELECT o.id, o.date, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o.id, o.date ORDER BY o.id ASC', $query->getDQL()); + $this->assertEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, COUNT(d1_.id) AS sclr2 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at ORDER BY d0_.order_id ASC', $query->getSQL()); + + + $result = $query->getResult(); + + $this->assertEquals(2, sizeof($result)); + + $this->assertArrayHasKey('id', $result[0]); + $this->assertArrayHasKey('id', $result[1]); + + $this->assertArrayHasKey('p_count', $result[0]); + $this->assertArrayHasKey('p_count', $result[1]); + + $this->assertEquals(1, $result[0]['id']); + $this->assertEquals(2, $result[1]['id']); + + $this->assertEquals(2, $result[0]['p_count']); + $this->assertEquals(3, $result[1]['p_count']); + } + + public function testOrderByAllObjectFields() + { + $repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC1430Order'); + $builder = $repository->createQueryBuilder('o'); + $query = $builder->select('o, COUNT(p.id) AS p_count') + ->leftJoin('o.products', 'p') + ->groupBy('o.id, o.date, o.status') + ->orderBy('o.id') + ->getQuery(); + + + $this->assertEquals('SELECT o, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o.id, o.date, o.status ORDER BY o.id ASC', $query->getDQL()); + $this->assertEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, d0_.order_status AS order_status2, COUNT(d1_.id) AS sclr3 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at, d0_.order_status ORDER BY d0_.order_id ASC', $query->getSQL()); + + $result = $query->getResult(); + + + $this->assertEquals(2, sizeof($result)); + + $this->assertTrue($result[0][0] instanceof DDC1430Order); + $this->assertTrue($result[1][0] instanceof DDC1430Order); + + $this->assertEquals($result[0][0]->getId(), 1); + $this->assertEquals($result[1][0]->getId(), 2); + + $this->assertEquals($result[0]['p_count'], 2); + $this->assertEquals($result[1]['p_count'], 3); + } + + public function testTicket() + { + $repository = $this->_em->getRepository(__NAMESPACE__ . '\DDC1430Order'); + $builder = $repository->createQueryBuilder('o'); + $query = $builder->select('o, COUNT(p.id) AS p_count') + ->leftJoin('o.products', 'p') + ->groupBy('o') + ->orderBy('o.id') + ->getQuery(); + + + $this->assertEquals('SELECT o, COUNT(p.id) AS p_count FROM Doctrine\Tests\ORM\Functional\Ticket\DDC1430Order o LEFT JOIN o.products p GROUP BY o ORDER BY o.id ASC', $query->getDQL()); + $this->assertEquals('SELECT d0_.order_id AS order_id0, d0_.created_at AS created_at1, d0_.order_status AS order_status2, COUNT(d1_.id) AS sclr3 FROM DDC1430Order d0_ LEFT JOIN DDC1430OrderProduct d1_ ON d0_.order_id = d1_.order_id GROUP BY d0_.order_id, d0_.created_at, d0_.order_status ORDER BY d0_.order_id ASC', $query->getSQL()); + + + $result = $query->getResult(); + + $this->assertEquals(2, sizeof($result)); + + $this->assertTrue($result[0][0] instanceof DDC1430Order); + $this->assertTrue($result[1][0] instanceof DDC1430Order); + + $this->assertEquals($result[0][0]->getId(), 1); + $this->assertEquals($result[1][0]->getId(), 2); + + $this->assertEquals($result[0]['p_count'], 2); + $this->assertEquals($result[1]['p_count'], 3); + } + + public function loadFixtures() + { + $o1 = new DDC1430Order('NEW'); + $o2 = new DDC1430Order('OK'); + + $o1->addProduct(new DDC1430OrderProduct(1.1)); + $o1->addProduct(new DDC1430OrderProduct(1.2)); + + $o2->addProduct(new DDC1430OrderProduct(2.1)); + $o2->addProduct(new DDC1430OrderProduct(2.2)); + $o2->addProduct(new DDC1430OrderProduct(2.3)); + + $this->_em->persist($o1); + $this->_em->persist($o2); + + $this->_em->flush(); + } + +} + +/** + * @Entity + */ +class DDC1430Order +{ + + /** + * @Id + * @Column(name="order_id", type="integer") + * @GeneratedValue() + */ + protected $id; + + /** + * @Column(name="created_at", type="datetime") + */ + private $date; + + /** + * @Column(name="order_status", type="string") + */ + private $status; + + /** + * @OneToMany(targetEntity="DDC1430OrderProduct", mappedBy="order", cascade={"persist", "remove"}) + * + * @var \Doctrine\Common\Collections\ArrayCollection $products + */ + private $products; + + /** + * @return integer + */ + public function getId() + { + return $this->id; + } + + public function __construct($status) + { + $this->status = $status; + $this->date = new \DateTime(); + $this->products = new \Doctrine\Common\Collections\ArrayCollection(); + } + /** + * @return \DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * @return string + */ + public function getStatus() + { + return $this->status; + } + + /** + * @param string $status + */ + public function setStatus($status) + { + $this->status = $status; + } + + /** + * @return \Doctrine\Common\Collections\ArrayCollection + */ + public function getProducts() + { + return $this->products; + } + + /** + * @param DDC1430OrderProduct $product + */ + public function addProduct(DDC1430OrderProduct $product) + { + $product->setOrder($this); + $this->products->add($product); + } +} + +/** + * @Entity + */ +class DDC1430OrderProduct +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue() + */ + protected $id; + + /** + * @var DDC1430Order $order + * + * @ManyToOne(targetEntity="DDC1430Order", inversedBy="products") + * @JoinColumn(name="order_id", referencedColumnName="order_id", nullable = false) + */ + private $order; + + /** + * @column(type="float") + */ + private $value; + + /** + * @param float $value + */ + public function __construct($value) + { + $this->value = $value; + } + + /** + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * @return DDC1430Order + */ + public function getOrder() + { + return $this->order; + } + + /** + * @param DDC1430Order $order + */ + public function setOrder(DDC1430Order $order) + { + $this->order = $order; + } + + /** + * @return float + */ + public function getValue() + { + return $this->value; + } + + /** + * @param float $value + */ + public function setValue($value) + { + $this->value = $value; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1436Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1436Test.php new file mode 100644 index 0000000..906290c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1436Test.php @@ -0,0 +1,89 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1436Page'), + )); + } catch (\Exception $ignored) { + } + } + + public function testIdentityMap() + { + // fixtures + $parent = null; + for ($i = 0; $i < 3; $i++) { + $page = new DDC1436Page(); + $page->setParent($parent); + $this->_em->persist($page); + $parent = $page; + } + $this->_em->flush(); + $this->_em->clear(); + + $id = $parent->getId(); + + // step 1 + $page = $this->_em + ->createQuery('SELECT p, parent FROM ' . __NAMESPACE__ . '\DDC1436Page p LEFT JOIN p.parent parent WHERE p.id = :id') + ->setParameter('id', $id) + ->getOneOrNullResult(); + + $this->assertInstanceOf(__NAMESPACE__ . '\DDC1436Page', $page); + + // step 2 + $page = $this->_em->find(__NAMESPACE__ . '\DDC1436Page', $id); + $this->assertInstanceOf(__NAMESPACE__ . '\DDC1436Page', $page); + $this->assertInstanceOf(__NAMESPACE__ . '\DDC1436Page', $page->getParent()); + $this->assertInstanceOf(__NAMESPACE__ . '\DDC1436Page', $page->getParent()->getParent()); + } +} + +/** + * @Entity + */ +class DDC1436Page +{ + /** + * @Id + * @GeneratedValue + * @Column(type="integer", name="id") + */ + protected $id; + /** + * @ManyToOne(targetEntity="DDC1436Page") + * @JoinColumn(name="pid", referencedColumnName="id") + */ + protected $parent; + + public function getId() + { + return $this->id; + } + + /** + * @return DDC1436Page + */ + public function getParent() + { + return $this->parent; + } + + public function setParent($parent) + { + $this->parent = $parent; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC144Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC144Test.php new file mode 100644 index 0000000..dd6391a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC144Test.php @@ -0,0 +1,64 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC144FlowElement'), + // $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC144Expression'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC144Operand'), + )); + + } + + /** + * @group DDC-144 + */ + public function testIssue() + { + + $operand = new DDC144Operand; + $operand->property = 'flowValue'; + $operand->operandProperty = 'operandValue'; + $this->_em->persist($operand); + $this->_em->flush(); + + } +} + +/** + * @Entity + * @Table(name="ddc144_flowelements") + * @InheritanceType("JOINED") + * @DiscriminatorColumn(type="string", name="discr") + * @DiscriminatorMap({"flowelement" = "DDC144FlowElement", "operand" = "DDC144Operand"}) + */ +class DDC144FlowElement { + /** + * @Id @Column(type="integer") @GeneratedValue + * @var integer + */ + public $id; + /** @Column */ + public $property; +} + +abstract class DDC144Expression extends DDC144FlowElement { + abstract function method(); +} + +/** @Entity @Table(name="ddc144_operands") */ +class DDC144Operand extends DDC144Expression { + /** @Column */ + public $operandProperty; + function method() {} +} + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1452Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1452Test.php new file mode 100644 index 0000000..aef2d10 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1452Test.php @@ -0,0 +1,127 @@ +useModelSet('cms'); + parent::setUp(); + + try { + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1452EntityA'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1452EntityB'), + )); + } catch (\Exception $ignored) { + } + } + + public function testIssue() + { + $a1 = new DDC1452EntityA(); + $a1->title = "foo"; + + $a2 = new DDC1452EntityA(); + $a2->title = "bar"; + + $b = new DDC1452EntityB(); + $b->entityAFrom = $a1; + $b->entityATo = $a2; + + $this->_em->persist($a1); + $this->_em->persist($a2); + $this->_em->persist($b); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT a, b, ba FROM " . __NAMESPACE__ . "\DDC1452EntityA AS a LEFT JOIN a.entitiesB AS b LEFT JOIN b.entityATo AS ba"; + $results = $this->_em->createQuery($dql)->setMaxResults(1)->getResult(); + + $this->assertSame($results[0], $results[0]->entitiesB[0]->entityAFrom); + $this->assertFalse( $results[0]->entitiesB[0]->entityATo instanceof \Doctrine\ORM\Proxy\Proxy ); + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $results[0]->entitiesB[0]->entityATo->getEntitiesB()); + } + + public function testFetchJoinOneToOneFromInverse() + { + $address = new \Doctrine\Tests\Models\CMS\CmsAddress(); + $address->city = "Bonn"; + $address->country = "Germany"; + $address->street = "Somestreet"; + $address->zip = 12345; + + $user = new \Doctrine\Tests\Models\CMS\CmsUser(); + $user->name = "beberlei"; + $user->username = "beberlei"; + $user->status = "active"; + $user->address = $address; + $address->user = $user; + + $this->_em->persist($address); + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT a, u FROM Doctrine\Tests\Models\CMS\CmsAddress a INNER JOIN a.user u"; + $data = $this->_em->createQuery($dql)->getResult(); + $this->_em->clear(); + + $this->assertFalse($data[0]->user instanceof \Doctrine\ORM\Proxy\Proxy); + + $dql = "SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.address a"; + $data = $this->_em->createQuery($dql)->getResult(); + + $this->assertFalse($data[0]->address instanceof \Doctrine\ORM\Proxy\Proxy); + } +} + +/** + * @Entity + */ +class DDC1452EntityA +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @Column */ + public $title; + /** @ManyToMany(targetEntity="DDC1452EntityB", mappedBy="entityAFrom") */ + public $entitiesB; + + public function __construct() + { + $this->entitiesB = new ArrayCollection(); + } + + public function getEntitiesB() + { + return $this->entitiesB; + } +} + +/** + * @Entity + */ +class DDC1452EntityB +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + + /** + * @ManyToOne(targetEntity="DDC1452EntityA", inversedBy="entitiesB") + */ + public $entityAFrom; + /** + * @ManyToOne(targetEntity="DDC1452EntityA") + */ + public $entityATo; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1454Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1454Test.php new file mode 100644 index 0000000..eaf9dd3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1454Test.php @@ -0,0 +1,69 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1454File'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1454Picture'), + )); + } catch (\Exception $ignored) { + + } + } + + public function testFailingCase() + { + $pic = new DDC1454Picture(); + $this->_em->getUnitOfWork()->getEntityState($pic); + } + +} + +/** + * @Entity + */ +class DDC1454Picture extends DDC1454File +{ + +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"picture" = "DDC1454Picture"}) + */ +class DDC1454File +{ + /** + * @Column(name="file_id", type="integer") + * @Id + */ + public $fileId; + + public function __construct() { + $this->fileId = rand(); + } + + /** + * Get fileId + */ + public function getFileId() { + return $this->fileId; + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1458Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1458Test.php new file mode 100644 index 0000000..745b51c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1458Test.php @@ -0,0 +1,131 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\TestEntity'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\TestAdditionalEntity') + )); + } + + public function testIssue() + { + $testEntity = new TestEntity(); + $testEntity->setValue(3); + $testEntity->setAdditional(new TestAdditionalEntity()); + $this->_em->persist($testEntity); + $this->_em->flush(); + $this->_em->clear(); + + // So here the value is 3 + $this->assertEquals(3, $testEntity->getValue()); + + $test = $this->_em->getRepository(__NAMESPACE__ . '\TestEntity')->find(1); + + // New value is set + $test->setValue(5); + + // So here the value is 5 + $this->assertEquals(5, $test->getValue()); + + // Get the additional entity + $additional = $test->getAdditional(); + + // Still 5.. + $this->assertEquals(5, $test->getValue()); + + // Force the proxy to load + $additional->getBool(); + + // The value should still be 5 + $this->assertEquals(5, $test->getValue()); + } +} + + +/** + * @Entity + */ +class TestEntity +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + protected $id; + /** + * @Column(type="integer") + */ + protected $value; + /** + * @OneToOne(targetEntity="TestAdditionalEntity", inversedBy="entity", orphanRemoval=true, cascade={"persist", "remove"}) + */ + protected $additional; + + public function getValue() + { + return $this->value; + } + + public function setValue($value) + { + $this->value = $value; + } + + public function getAdditional() + { + return $this->additional; + } + + public function setAdditional($additional) + { + $this->additional = $additional; + } +} +/** + * @Entity + */ +class TestAdditionalEntity +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + protected $id; + /** + * @OneToOne(targetEntity="TestEntity", mappedBy="additional") + */ + protected $entity; + /** + * @Column(type="boolean") + */ + protected $bool; + + public function __construct() + { + $this->bool = false; + } + + public function getBool() + { + return $this->bool; + } + + public function setBool($bool) + { + $this->bool = $bool; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1461Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1461Test.php new file mode 100644 index 0000000..e6aa2e6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1461Test.php @@ -0,0 +1,86 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1461TwitterAccount'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1461User') + )); + } catch(\Exception $e) { + + } + } + + public function testChangeDetectionDeferredExplicit() + { + $user = new DDC1461User; + $this->_em->persist($user); + $this->_em->flush(); + + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($user, \Doctrine\ORM\UnitOfWork::STATE_NEW), "Entity should be managed."); + $this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $this->_em->getUnitOfWork()->getEntityState($user), "Entity should be managed."); + + $acc = new DDC1461TwitterAccount; + $user->twitterAccount = $acc; + + $this->_em->persist($user); + $this->_em->flush(); + + $user = $this->_em->find(get_class($user), $user->id); + $this->assertNotNull($user->twitterAccount); + } +} + +/** + * @Entity + * @ChangeTrackingPolicy("DEFERRED_EXPLICIT") + */ +class DDC1461User +{ + /** + * @Id + * @GeneratedValue(strategy="AUTO") + * @Column(type="integer") + */ + public $id; + + /** + * @OneToOne(targetEntity="DDC1461TwitterAccount", orphanRemoval=true, fetch="EAGER", cascade = {"persist"}, inversedBy="user") + * @var TwitterAccount + */ + public $twitterAccount; +} + +/** + * @Entity + * @ChangeTrackingPolicy("DEFERRED_EXPLICIT") + */ +class DDC1461TwitterAccount +{ + /** + * @Id + * @GeneratedValue(strategy="AUTO") + * @Column(type="integer") + */ + public $id; + + /** + * @OneToOne(targetEntity="DDC1461User", fetch="EAGER") + */ + public $user; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1509Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1509Test.php new file mode 100644 index 0000000..6ba0cd4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1509Test.php @@ -0,0 +1,146 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1509AbstractFile'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1509File'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1509Picture'), + )); + } catch (\Exception $ignored) { + + } + } + + public function testFailingCase() + { + $file = new DDC1509File; + $thumbnail = new DDC1509File; + + $picture = new DDC1509Picture; + $picture->setFile($file); + $picture->setThumbnail($thumbnail); + + + /* @var $em \Doctrine\ORM\EntityManager */ + $em = $this->_em; + $em->persist($picture); + $em->flush(); + $em->clear(); + + $id = $picture->getPictureId(); + + $pic = $em->merge($picture); + /* @var $pic DDC1509Picture */ + + $this->assertNotNull($pic->getThumbnail()); + $this->assertNotNull($pic->getFile()); + } + +} + +/** + * @Entity + */ +class DDC1509Picture +{ + + /** + * @Column(type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @ManyToOne(targetEntity="DDC1509AbstractFile", cascade={"persist", "remove"}) + */ + private $thumbnail; + + /** + * @ManyToOne(targetEntity="DDC1509AbstractFile", cascade={"persist", "remove"}) + */ + private $file; + + /** + * Get pictureId + */ + public function getPictureId() + { + return $this->id; + } + + /** + * Set file + */ + public function setFile($value = null) + { + $this->file = $value; + } + + /** + * Get file + */ + public function getFile() + { + return $this->file; + } + + public function getThumbnail() + { + return $this->thumbnail; + } + + public function setThumbnail($thumbnail) + { + $this->thumbnail = $thumbnail; + } + +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"file" = "DDC1509File"}) + */ +class DDC1509AbstractFile +{ + + /** + * @Column(type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * Get fileId + */ + public function getFileId() + { + return $this->id; + } + +} + +/** + * @Entity + */ +class DDC1509File extends DDC1509AbstractFile +{ + +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1514Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1514Test.php new file mode 100644 index 0000000..cc0f972 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1514Test.php @@ -0,0 +1,111 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1514EntityA'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1514EntityB'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1514EntityC'), + )); + } catch (\Exception $ignored) { + } + } + + public function testIssue() + { + $a1 = new DDC1514EntityA(); + $a1->title = "foo"; + + $a2 = new DDC1514EntityA(); + $a2->title = "bar"; + + $b1 = new DDC1514EntityB(); + $b1->entityAFrom = $a1; + $b1->entityATo = $a2; + + $b2 = new DDC1514EntityB(); + $b2->entityAFrom = $a2; + $b2->entityATo = $a1; + + $c = new DDC1514EntityC(); + $c->title = "baz"; + $a2->entityC = $c; + + $this->_em->persist($a1); + $this->_em->persist($a2); + $this->_em->persist($b1); + $this->_em->persist($b2); + $this->_em->persist($c); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT a, b, ba, c FROM " . __NAMESPACE__ . "\DDC1514EntityA AS a LEFT JOIN a.entitiesB AS b LEFT JOIN b.entityATo AS ba LEFT JOIN a.entityC AS c"; + $results = $this->_em->createQuery($dql)->getResult(); + + $this->assertEquals($c->title, $results[1]->entityC->title); + } +} + +/** + * @Entity + */ +class DDC1514EntityA +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @Column */ + public $title; + /** @ManyToMany(targetEntity="DDC1514EntityB", mappedBy="entityAFrom") */ + public $entitiesB; + /** @ManyToOne(targetEntity="DDC1514EntityC") */ + public $entityC; + + public function __construct() + { + $this->entitiesB = new ArrayCollection(); + } +} + +/** + * @Entity + */ +class DDC1514EntityB +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + + /** + * @ManyToOne(targetEntity="DDC1514EntityA", inversedBy="entitiesB") + */ + public $entityAFrom; + /** + * @ManyToOne(targetEntity="DDC1514EntityA") + */ + public $entityATo; +} + +/** + * @Entity + */ +class DDC1514EntityC +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @Column */ + public $title; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1515Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1515Test.php new file mode 100644 index 0000000..9bd3360 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1515Test.php @@ -0,0 +1,64 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1515Foo'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1515Bar'), + )); + } + + public function testIssue() + { + $bar = new DDC1515Bar(); + $this->_em->persist($bar); + $this->_em->flush(); + + $foo = new DDC1515Foo(); + $foo->bar = $bar; + $this->_em->persist($foo); + $this->_em->flush(); + $this->_em->clear(); + + $bar = $this->_em->find(__NAMESPACE__ . '\DDC1515Bar', $bar->id); + $this->assertInstanceOf(__NAMESPACE__.'\DDC1515Foo', $bar->foo); + } +} + +/** + * @Entity + */ +class DDC1515Foo +{ + /** + * @OneToOne(targetEntity="DDC1515Bar", inversedBy="foo") @Id + */ + public $bar; +} + +/** + * @Entity + */ +class DDC1515Bar +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + public $id; + + /** + * @OneToOne(targetEntity="DDC1515Foo", mappedBy="bar") + */ + public $foo; +} + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1526Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1526Test.php new file mode 100644 index 0000000..27d0a87 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1526Test.php @@ -0,0 +1,67 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1526Menu'), + )); + } + + public function testIssue() + { + $parents = array(); + for ($i = 0; $i < 9; $i++) { + $entity = new DDC1526Menu; + + if (isset ($parents[($i % 3)])) { + $entity->parent = $parents[($i%3)]; + } + + $this->_em->persist($entity); + $parents[$i] = $entity; + } + $this->_em->flush(); + $this->_em->clear(); + + + $dql = "SELECT m, c + FROM " . __NAMESPACE__ . "\DDC1526Menu m + LEFT JOIN m.children c"; + $menus = $this->_em->createQuery($dql)->getResult(); + + // All Children collection now have to be initiailzed + foreach ($menus as $menu) { + $this->assertTrue($menu->children->isInitialized()); + } + } +} + +/** + * @Entity + */ +class DDC1526Menu +{ + /** + * @Column(type="integer") + * @Id + * @GeneratedValue + */ + public $id; + /** + * @ManyToOne(targetEntity="DDC1526Menu", inversedBy="children") + */ + public $parent; + + /** + * @OneToMany(targetEntity="DDC1526Menu", mappedBy="parent") + */ + public $children; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1545Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1545Test.php new file mode 100644 index 0000000..6af9cc5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1545Test.php @@ -0,0 +1,201 @@ +useModelSet('cms'); + parent::setUp(); + } + + private function initDb($link) + { + $article = new CmsArticle(); + $article->topic = 'foo'; + $article->text = 'foo'; + + $user = new CmsUser(); + $user->status = 'foo'; + $user->username = 'foo'; + $user->name = 'foo'; + + $user2 = new CmsUser(); + $user2->status = 'bar'; + $user2->username = 'bar'; + $user2->name = 'bar'; + + if ($link) { + $article->user = $user; + } + + $this->_em->persist($article); + $this->_em->persist($user); + $this->_em->persist($user2); + $this->_em->flush(); + $this->_em->clear(); + + $this->articleId = $article->id; + $this->userId = $user->id; + $this->user2Id = $user2->id; + } + + public function testLinkObjects() + { + $this->initDb(false); + + // don't join association + $article = $this->_em->find('Doctrine\Tests\Models\Cms\CmsArticle', $this->articleId); + + $user = $this->_em->find('Doctrine\Tests\Models\Cms\CmsUser', $this->userId); + + $article->user = $user; + + $this->_em->flush(); + $this->_em->clear(); + + $article = $this->_em + ->createQuery('SELECT a, u FROM Doctrine\Tests\Models\Cms\CmsArticle a LEFT JOIN a.user u WHERE a.id = :id') + ->setParameter('id', $this->articleId) + ->getOneOrNullResult(); + + $this->assertNotNull($article->user); + $this->assertEquals($user->id, $article->user->id); + } + + public function testLinkObjectsWithAssociationLoaded() + { + $this->initDb(false); + + // join association + $article = $this->_em + ->createQuery('SELECT a, u FROM Doctrine\Tests\Models\Cms\CmsArticle a LEFT JOIN a.user u WHERE a.id = :id') + ->setParameter('id', $this->articleId) + ->getOneOrNullResult(); + + $user = $this->_em->find('Doctrine\Tests\Models\Cms\CmsUser', $this->userId); + + $article->user = $user; + + $this->_em->flush(); + $this->_em->clear(); + + $article = $this->_em + ->createQuery('SELECT a, u FROM Doctrine\Tests\Models\Cms\CmsArticle a LEFT JOIN a.user u WHERE a.id = :id') + ->setParameter('id', $this->articleId) + ->getOneOrNullResult(); + + $this->assertNotNull($article->user); + $this->assertEquals($user->id, $article->user->id); + } + + public function testUnlinkObjects() + { + $this->initDb(true); + + // don't join association + $article = $this->_em->find('Doctrine\Tests\Models\Cms\CmsArticle', $this->articleId); + + $article->user = null; + + $this->_em->flush(); + $this->_em->clear(); + + $article = $this->_em + ->createQuery('SELECT a, u FROM Doctrine\Tests\Models\Cms\CmsArticle a LEFT JOIN a.user u WHERE a.id = :id') + ->setParameter('id', $this->articleId) + ->getOneOrNullResult(); + + $this->assertNull($article->user); + } + + public function testUnlinkObjectsWithAssociationLoaded() + { + $this->initDb(true); + + // join association + $article = $this->_em + ->createQuery('SELECT a, u FROM Doctrine\Tests\Models\Cms\CmsArticle a LEFT JOIN a.user u WHERE a.id = :id') + ->setParameter('id', $this->articleId) + ->getOneOrNullResult(); + + $article->user = null; + + $this->_em->flush(); + $this->_em->clear(); + + $article = $this->_em + ->createQuery('SELECT a, u FROM Doctrine\Tests\Models\Cms\CmsArticle a LEFT JOIN a.user u WHERE a.id = :id') + ->setParameter('id', $this->articleId) + ->getOneOrNullResult(); + + $this->assertNull($article->user); + } + + public function testChangeLink() + { + $this->initDb(false); + + // don't join association + $article = $this->_em->find('Doctrine\Tests\Models\Cms\CmsArticle', $this->articleId); + + $user2 = $this->_em->find('Doctrine\Tests\Models\Cms\CmsUser', $this->user2Id); + + $article->user = $user2; + + $this->_em->flush(); + $this->_em->clear(); + + $article = $this->_em + ->createQuery('SELECT a, u FROM Doctrine\Tests\Models\Cms\CmsArticle a LEFT JOIN a.user u WHERE a.id = :id') + ->setParameter('id', $this->articleId) + ->getOneOrNullResult(); + + $this->assertNotNull($article->user); + $this->assertEquals($user2->id, $article->user->id); + } + + public function testChangeLinkWithAssociationLoaded() + { + $this->initDb(false); + + // join association + $article = $this->_em + ->createQuery('SELECT a, u FROM Doctrine\Tests\Models\Cms\CmsArticle a LEFT JOIN a.user u WHERE a.id = :id') + ->setParameter('id', $this->articleId) + ->getOneOrNullResult(); + + $user2 = $this->_em->find('Doctrine\Tests\Models\Cms\CmsUser', $this->user2Id); + + $article->user = $user2; + + $this->_em->flush(); + $this->_em->clear(); + + $article = $this->_em + ->createQuery('SELECT a, u FROM Doctrine\Tests\Models\Cms\CmsArticle a LEFT JOIN a.user u WHERE a.id = :id') + ->setParameter('id', $this->articleId) + ->getOneOrNullResult(); + + $this->assertNotNull($article->user); + $this->assertEquals($user2->id, $article->user->id); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1548Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1548Test.php new file mode 100644 index 0000000..74c1fe1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1548Test.php @@ -0,0 +1,81 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1548E1'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1548E2'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1548Rel'), + )); + } + + public function testIssue() + { + $rel = new DDC1548Rel(); + $this->_em->persist($rel); + $this->_em->flush(); + + $e1 = new DDC1548E1(); + $e1->rel = $rel; + $this->_em->persist($e1); + $this->_em->flush(); + $this->_em->clear(); + + $obt = $this->_em->find(__NAMESPACE__ . '\DDC1548Rel', $rel->id); + + $this->assertNull($obt->e2); + } +} + +/** + * @Entity + */ +class DDC1548E1 +{ + /** + * @Id + * @OneToOne(targetEntity="DDC1548Rel", inversedBy="e1") + */ + public $rel; +} + +/** + * @Entity + */ +class DDC1548E2 +{ + /** + * @Id + * @OneToOne(targetEntity="DDC1548Rel", inversedBy="e2") + */ + public $rel; +} + +/** + * @Entity + */ +class DDC1548Rel +{ + /** + * @Id @GeneratedValue + * @Column(type="integer") + */ + public $id; + + /** + * @OneToOne(targetEntity="DDC1548E1", mappedBy="rel") + */ + public $e1; + /** + * @OneToOne(targetEntity="DDC1548E2", mappedBy="rel") + */ + public $e2; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1594Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1594Test.php new file mode 100644 index 0000000..b8dec40 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1594Test.php @@ -0,0 +1,45 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testIssue() + { + $user = new CmsUser(); + $user->status = 'foo'; + $user->username = 'foo'; + $user->name = 'foo'; + + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + $detachedUser = clone $user; + $detachedUser->name = 'bar'; + $detachedUser->status = 'bar'; + + $newUser = $this->_em->getReference(get_class($user), $user->id); + + $mergedUser = $this->_em->merge($detachedUser); + + $this->assertNotSame($mergedUser, $detachedUser); + $this->assertEquals('bar', $detachedUser->getName()); + $this->assertEquals('bar', $mergedUser->getName()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1595Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1595Test.php new file mode 100644 index 0000000..a45c9f1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1595Test.php @@ -0,0 +1,111 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\DebugStack); + + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1595BaseInheritance'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1595InheritedEntity1'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1595InheritedEntity2'), + )); + } + + public function testIssue() + { + $e1 = new DDC1595InheritedEntity1(); + + $this->_em->persist($e1); + $this->_em->flush(); + $this->_em->clear(); + + $sqlLogger = $this->_em->getConnection()->getConfiguration()->getSQLLogger(); + $repository = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1595InheritedEntity1'); + + $entity1 = $repository->find($e1->id); + + // DDC-1596 + $this->assertEquals( + "SELECT t0.id AS id1, t0.type FROM base t0 WHERE t0.id = ? AND t0.type IN ('Entity1')", + $sqlLogger->queries[count($sqlLogger->queries)]['sql'] + ); + + $entities = $entity1->getEntities()->getValues(); + + $this->assertEquals( + "SELECT t0.id AS id1, t0.type FROM base t0 INNER JOIN entity1_entity2 ON t0.id = entity1_entity2.item WHERE entity1_entity2.parent = ? AND t0.type IN ('Entity2')", + $sqlLogger->queries[count($sqlLogger->queries)]['sql'] + ); + + $this->_em->clear(); + + $entity1 = $repository->find($e1->id); + $entities = $entity1->getEntities()->count(); + + $this->assertEquals( + "SELECT COUNT(*) FROM entity1_entity2 t WHERE parent = ?", + $sqlLogger->queries[count($sqlLogger->queries)]['sql'] + ); + } +} + +/** + * @Entity + * @Table(name="base") + * + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorColumn(name="type", type="string") + * @DiscriminatorMap({ + * "Entity1" = "DDC1595InheritedEntity1", + * "Entity2" = "DDC1595InheritedEntity2" + * }) + */ +abstract class DDC1595BaseInheritance +{ + /** + * @Id @GeneratedValue + * @Column(type="integer") + * + * @var integer + */ + public $id; +} + +/** + * @Entity + * @Table(name="entity1") + */ +class DDC1595InheritedEntity1 extends DDC1595BaseInheritance +{ + /** + * @ManyToMany(targetEntity="DDC1595InheritedEntity2", fetch="EXTRA_LAZY") + * @JoinTable(name="entity1_entity2", + * joinColumns={@JoinColumn(name="parent", referencedColumnName="id")}, + * inverseJoinColumns={@JoinColumn(name="item", referencedColumnName="id")} + * ) + */ + protected $entities; + + public function getEntities() + { + return $this->entities; + } +} + +/** + * @Entity + * @Table(name="entity2") + */ +class DDC1595InheritedEntity2 extends DDC1595BaseInheritance +{ +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC163Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC163Test.php new file mode 100644 index 0000000..3126d54 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC163Test.php @@ -0,0 +1,65 @@ +useModelSet('company'); + parent::setUp(); + } + + /** + * @group DDC-163 + */ + public function testQueryWithOrConditionUsingTwoRelationOnSameEntity() + { + $p1 = new CompanyPerson; + $p1->setName('p1'); + + $p2 = new CompanyPerson; + $p2->setName('p2'); + + $p3 = new CompanyPerson; + $p3->setName('p3'); + + $p4 = new CompanyPerson; + $p4->setName('p4'); + + $p1->setSpouse($p3); + $p1->addFriend($p2); + $p2->addFriend($p3); + + $p3->addFriend($p4); + + $this->_em->persist($p1); + $this->_em->persist($p2); + $this->_em->persist($p3); + $this->_em->persist($p4); + + $this->_em->flush(); + $this->_em->clear(); + + $dql = 'SELECT PARTIAL person.{id,name}, PARTIAL spouse.{id,name}, PARTIAL friend.{id,name} + FROM Doctrine\Tests\Models\Company\CompanyPerson person + LEFT JOIN person.spouse spouse + LEFT JOIN person.friends friend + LEFT JOIN spouse.friends spouse_friend + LEFT JOIN friend.friends friend_friend + WHERE person.name=:name AND (spouse_friend.name=:name2 OR friend_friend.name=:name2)'; + + $q = $this->_em->createQuery($dql); + $q->setParameter('name', "p1"); + $q->setParameter('name2', "p4"); + $result = $q->getScalarResult(); + + $this->assertEquals('p3', $result[0]['spouse_name']); + $this->assertEquals('p1', $result[0]['person_name']); + $this->assertEquals('p2', $result[0]['friend_name']); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1643Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1643Test.php new file mode 100644 index 0000000..53d6bb6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1643Test.php @@ -0,0 +1,121 @@ +useModelSet('cms'); + parent::setUp(); + + $user1 = new CmsUser(); + $user1->username = "beberlei"; + $user1->name = "Benjamin"; + $user1->status = "active"; + $group1 = new CmsGroup(); + $group1->name = "test"; + $group2 = new CmsGroup(); + $group2->name = "test"; + $user1->addGroup($group1); + $user1->addGroup($group2); + $user2 = new CmsUser(); + $user2->username = "romanb"; + $user2->name = "Roman"; + $user2->status = "active"; + + $this->_em->persist($user1); + $this->_em->persist($user2); + $this->_em->persist($group1); + $this->_em->persist($group2); + $this->_em->flush(); + $this->_em->clear(); + + $this->user1 = $this->_em->find(get_class($user1), $user1->id); + $this->user2 = $this->_em->find(get_class($user1), $user2->id); + } + + public function testClonePersistentCollectionAndReuse() + { + $user1 = $this->user1; + + $user1->groups = clone $user1->groups; + + $this->_em->flush(); + $this->_em->clear(); + + $user1 = $this->_em->find(get_class($user1), $user1->id); + + $this->assertEquals(2, count($user1->groups)); + } + + public function testClonePersistentCollectionAndShare() + { + $user1 = $this->user1; + $user2 = $this->user2; + + $user2->groups = clone $user1->groups; + + $this->_em->flush(); + $this->_em->clear(); + + $user1 = $this->_em->find(get_class($user1), $user1->id); + $user2 = $this->_em->find(get_class($user1), $user2->id); + + $this->assertEquals(2, count($user1->groups)); + $this->assertEquals(2, count($user2->groups)); + } + + public function testCloneThenDirtyPersistentCollection() + { + $user1 = $this->user1; + $user2 = $this->user2; + + $group3 = new CmsGroup(); + $group3->name = "test"; + $user2->groups = clone $user1->groups; + $user2->groups->add($group3); + + $this->_em->persist($group3); + $this->_em->flush(); + $this->_em->clear(); + + $user1 = $this->_em->find(get_class($user1), $user1->id); + $user2 = $this->_em->find(get_class($user1), $user2->id); + + $this->assertEquals(3, count($user2->groups)); + $this->assertEquals(2, count($user1->groups)); + } + + public function testNotCloneAndPassAroundFlush() + { + $user1 = $this->user1; + $user2 = $this->user2; + + $group3 = new CmsGroup(); + $group3->name = "test"; + $user2->groups = $user1->groups; + $user2->groups->add($group3); + + $this->assertEQuals(1, count($user1->groups->getInsertDiff())); + + $this->_em->persist($group3); + $this->_em->flush(); + $this->_em->clear(); + + $user1 = $this->_em->find(get_class($user1), $user1->id); + $user2 = $this->_em->find(get_class($user1), $user2->id); + + $this->assertEquals(3, count($user2->groups)); + $this->assertEquals(3, count($user1->groups)); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php new file mode 100644 index 0000000..0169619 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php @@ -0,0 +1,103 @@ +setUpEntitySchema(array( + __NAMESPACE__ . '\\DDC1654Post', + __NAMESPACE__ . '\\DDC1654Comment', + )); + } + + public function testManyToManyRemoveFromCollectionOrphanRemoval() + { + $post = new DDC1654Post(); + $post->comments[] = new DDC1654Comment(); + $post->comments[] = new DDC1654Comment(); + + $this->_em->persist($post); + $this->_em->flush(); + + $post->comments->remove(0); + $post->comments->remove(1); + + $this->_em->flush(); + $this->_em->clear(); + + $comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll(); + $this->assertEquals(0, count($comments)); + } + + public function testManyToManyRemoveElementFromCollectionOrphanRemoval() + { + $post = new DDC1654Post(); + $post->comments[] = new DDC1654Comment(); + $post->comments[] = new DDC1654Comment(); + + $this->_em->persist($post); + $this->_em->flush(); + + $post->comments->removeElement($post->comments[0]); + $post->comments->removeElement($post->comments[1]); + + $this->_em->flush(); + $this->_em->clear(); + + $comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll(); + $this->assertEquals(0, count($comments)); + } + + public function testManyToManyClearCollectionOrphanRemoval() + { + $post = new DDC1654Post(); + $post->comments[] = new DDC1654Comment(); + $post->comments[] = new DDC1654Comment(); + + $this->_em->persist($post); + $this->_em->flush(); + + $post->comments->clear(); + + $this->_em->flush(); + $this->_em->clear(); + + $comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll(); + $this->assertEquals(0, count($comments)); + + } +} + +/** + * @Entity + */ +class DDC1654Post +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + public $id; + + /** + * @ManyToMany(targetEntity="DDC1654Comment", orphanRemoval=true, + * cascade={"persist"}) + */ + public $comments = array(); +} + +/** + * @Entity + */ +class DDC1654Comment +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + public $id; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1655Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1655Test.php new file mode 100644 index 0000000..22b20e7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1655Test.php @@ -0,0 +1,144 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1655Foo'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1655Bar'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1655Baz'), + )); + } catch(\Exception $e) { + + } + } + + public function testPostLoadOneToManyInheritance() + { + $cm = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1655Foo'); + $this->assertEquals(array("postLoad" => array("postLoad")), $cm->lifecycleCallbacks); + + $cm = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1655Bar'); + $this->assertEquals(array("postLoad" => array("postLoad", "postSubLoaded")), $cm->lifecycleCallbacks); + + $baz = new DDC1655Baz(); + $foo = new DDC1655Foo(); + $foo->baz = $baz; + $bar = new DDC1655Bar(); + $bar->baz = $baz; + + $this->_em->persist($foo); + $this->_em->persist($bar); + $this->_em->persist($baz); + $this->_em->flush(); + $this->_em->clear(); + + $baz = $this->_em->find(get_class($baz), $baz->id); + foreach ($baz->foos as $foo) { + $this->assertEquals(1, $foo->loaded, "should have loaded callback counter incremented for " . get_class($foo)); + } + } + + /** + * Check that post load is not executed several times when the entity + * is rehydrated again although its already known. + */ + public function testPostLoadInheritanceChild() + { + $bar = new DDC1655Bar(); + + $this->_em->persist($bar); + $this->_em->flush(); + $this->_em->clear(); + + $bar = $this->_em->find(get_class($bar), $bar->id); + $this->assertEquals(1, $bar->loaded); + $this->assertEquals(1, $bar->subLoaded); + + $bar = $this->_em->find(get_class($bar), $bar->id); + $this->assertEquals(1, $bar->loaded); + $this->assertEquals(1, $bar->subLoaded); + + $dql = "SELECT b FROM " . __NAMESPACE__ . "\DDC1655Bar b WHERE b.id = ?1"; + $bar = $this->_em->createQuery($dql)->setParameter(1, $bar->id)->getSingleResult(); + + $this->assertEquals(1, $bar->loaded); + $this->assertEquals(1, $bar->subLoaded); + + $this->_em->refresh($bar); + + $this->assertEquals(2, $bar->loaded); + $this->assertEquals(2, $bar->subLoaded); + } +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorMap({ + * "foo" = "DDC1655Foo", + * "bar" = "DDC1655Bar" + * }) + * @HasLifecycleCallbacks + */ +class DDC1655Foo +{ + /** @Id @GeneratedValue @Column(type="integer") */ + public $id; + + public $loaded = 0; + + /** + * @ManyToOne(targetEntity="DDC1655Baz", inversedBy="foos") + */ + public $baz; + + /** + * @PostLoad + */ + public function postLoad() + { + $this->loaded++; + } +} + +/** + * @Entity + * @HasLifecycleCallbacks + */ +class DDC1655Bar extends DDC1655Foo +{ + public $subLoaded; + + /** + * @PostLoad + */ + public function postSubLoaded() + { + $this->subLoaded++; + } +} + +/** + * @Entity + */ +class DDC1655Baz +{ + /** @Id @GeneratedValue @Column(type="integer") */ + public $id; + + /** + * @OneToMany(targetEntity="DDC1655Foo", mappedBy="baz") + */ + public $foos = array(); +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1685Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1685Test.php new file mode 100644 index 0000000..ee4c64a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1685Test.php @@ -0,0 +1,64 @@ +useModelSet('ddc117'); + parent::setUp(); + + $this->_em->createQuery('DELETE FROM Doctrine\Tests\Models\DDC117\DDC117ArticleDetails ad')->execute(); + + $article = new DDC117Article("Foo"); + $this->_em->persist($article); + $this->_em->flush(); + + $articleDetails = new DDC117ArticleDetails($article, "Very long text"); + $this->_em->persist($articleDetails); + $this->_em->flush(); + + $dql = "SELECT ad FROM Doctrine\Tests\Models\DDC117\DDC117ArticleDetails ad"; + $query = $this->_em->createQuery($dql); + + $this->paginator = new Paginator($query); + } + + public function testPaginateCount() + { + $this->assertEquals(1, count($this->paginator)); + } + + public function testPaginateIterate() + { + foreach ($this->paginator as $ad) { + $this->assertInstanceOf('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails', $ad); + } + } + + public function testPaginateCountNoOutputWalkers() + { + $this->paginator->setUseOutputWalkers(false); + $this->assertEquals(1, count($this->paginator)); + } + + public function testPaginateIterateNoOutputWalkers() + { + $this->paginator->setUseOutputWalkers(false); + + $this->setExpectedException('RuntimeException', 'Paginating an entity with foreign key as identifier only works when using the Output Walkers. Call Paginator#setUseOutputWalkers(true) before iterating the paginator.'); + foreach ($this->paginator as $ad) { + $this->assertInstanceOf('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails', $ad); + } + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC168Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC168Test.php new file mode 100644 index 0000000..0b53780 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC168Test.php @@ -0,0 +1,64 @@ +useModelSet('company'); + parent::setUp(); + + $this->oldMetadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee'); + + $metadata = clone $this->oldMetadata; + ksort($metadata->reflFields); + $this->_em->getMetadataFactory()->setMetadataFor('Doctrine\Tests\Models\Company\CompanyEmployee', $metadata); + } + + public function tearDown() + { + $this->_em->getMetadataFactory()->setMetadataFor('Doctrine\Tests\Models\Company\CompanyEmployee', $this->oldMetadata); + parent::tearDown(); + } + + /** + * @group DDC-168 + */ + public function testJoinedSubclassPersisterRequiresSpecificOrderOfMetadataReflFieldsArray() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $spouse = new CompanyEmployee; + $spouse->setName("Blub"); + $spouse->setDepartment("Accounting"); + $spouse->setSalary(500); + + $employee = new CompanyEmployee; + $employee->setName("Foo"); + $employee->setDepartment("bar"); + $employee->setSalary(1000); + $employee->setSpouse($spouse); + + $this->_em->persist($spouse); + $this->_em->persist($employee); + + $this->_em->flush(); + $this->_em->clear(); + + $q = $this->_em->createQuery("SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e WHERE e.name = ?1"); + $q->setParameter(1, "Foo"); + $theEmployee = $q->getSingleResult(); + + $this->assertEquals("bar", $theEmployee->getDepartment()); + $this->assertEquals("Foo", $theEmployee->getName()); + $this->assertEquals(1000, $theEmployee->getSalary()); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $theEmployee); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $theEmployee->getSpouse()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1695Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1695Test.php new file mode 100644 index 0000000..dc1f884 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1695Test.php @@ -0,0 +1,158 @@ +_em->getConnection()->getDatabasePlatform()->getName() != "sqlite") { + $this->markTestSkipped("Only with sqlite"); + } + $dql = "SELECT n.smallText, n.publishDate FROM " . __NAMESPACE__ . "\\DDC1695News n"; + $sql = $this->_em->createQuery($dql)->getSQL(); + + $this->assertEquals( + 'SELECT d0_."SmallText" AS SmallText0, d0_."PublishDate" AS PublishDate1 FROM "DDC1695News" d0_', + $sql + ); + } +} + +/** + * @Table(name="`DDC1695News`") + * @Entity + */ +class DDC1695News +{ + /** + * @var integer $idNews + * + * @Column(name="`IdNews`", type="integer", nullable=false) + * @Id + * @GeneratedValue + */ + private $idNews; + + /** + * @var bigint $iduser + * + * @Column(name="`IdUser`", type="bigint", nullable=false) + */ + private $idUser; + + /** + * @var integer $idLanguage + * + * @Column(name="`IdLanguage`", type="integer", nullable=false) + */ + private $idLanguage; + + /** + * @var integer $idCondition + * + * @Column(name="`IdCondition`", type="integer", nullable=true) + */ + private $idCondition; + + /** + * @var integer $idHealthProvider + * + * @Column(name="`IdHealthProvider`", type="integer", nullable=true) + */ + private $idHealthProvider; + + /** + * @var integer $idSpeciality + * + * @Column(name="`IdSpeciality`", type="integer", nullable=true) + */ + private $idSpeciality; + + /** + * @var integer $idMedicineType + * + * @Column(name="`IdMedicineType`", type="integer", nullable=true) + */ + private $idMedicineType; + + /** + * @var integer $idTreatment + * + * @Column(name="`IdTreatment`", type="integer", nullable=true) + */ + private $idTreatment; + + /** + * @var string $title + * + * @Column(name="`Title`", type="string", nullable=true) + */ + private $title; + + /** + * @var string $smallText + * + * @Column(name="`SmallText`", type="string", nullable=true) + */ + private $smallText; + + /** + * @var string $longText + * + * @Column(name="`LongText`", type="string", nullable=true) + */ + private $longText; + + /** + * @var datetimetz $publishDate + * + * @Column(name="`PublishDate`", type="datetimetz", nullable=true) + */ + private $publishDate; + + /** + * @var tsvector $idxNews + * + * @Column(name="`IdxNews`", type="tsvector", nullable=true) + */ + private $idxNews; + + /** + * @var boolean $highlight + * + * @Column(name="`Highlight`", type="boolean", nullable=false) + */ + private $highlight; + + /** + * @var integer $order + * + * @Column(name="`Order`", type="integer", nullable=false) + */ + private $order; + + /** + * @var boolean $deleted + * + * @Column(name="`Deleted`", type="boolean", nullable=false) + */ + private $deleted; + + /** + * @var boolean $active + * + * @Column(name="`Active`", type="boolean", nullable=false) + */ + private $active; + + /** + * @var boolean $updateToHighlighted + * + * @Column(name="`UpdateToHighlighted`", type="boolean", nullable=true) + */ + private $updateToHighlighted; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1707Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1707Test.php new file mode 100644 index 0000000..50e702d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1707Test.php @@ -0,0 +1,64 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1509File'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1509Picture'), + )); + } catch (\Exception $ignored) { + + } + } + + public function testPostLoadOnChild() + { + $class = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1707Child'); + $entity = new DDC1707Child(); + $class->invokeLifecycleCallbacks(\Doctrine\ORM\Events::postLoad, $entity); + + $this->assertTrue($entity->postLoad); + } +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorMap({"c": "DDC1707Child"}) + * @HasLifecycleCallbacks + */ +abstract class DDC1707Base +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + protected $id; + + public $postLoad = false; + + /** + * @PostLoad + */ + public function onPostLoad() + { + $this->postLoad = true; + } +} +/** + * @Entity + */ +class DDC1707Child extends DDC1707Base +{ +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1719Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1719Test.php new file mode 100644 index 0000000..93b3458 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1719Test.php @@ -0,0 +1,88 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(self::CLASS_NAME), + )); + } catch(\Exception $e) { + } + } + + public function testCreateRetreaveUpdateDelete() + { + $e1 = new SimpleEntity('Bar 1'); + $e2 = new SimpleEntity('Foo 1'); + + // Create + $this->_em->persist($e1); + $this->_em->persist($e2); + $this->_em->flush(); + $this->_em->clear(); + + $e1Id = $e1->id; + $e2Id = $e2->id; + + // Retreave + $e1 = $this->_em->find(self::CLASS_NAME, $e1Id); + $e2 = $this->_em->find(self::CLASS_NAME, $e2Id); + + $this->assertInstanceOf(self::CLASS_NAME, $e1); + $this->assertInstanceOf(self::CLASS_NAME, $e2); + + $this->assertEquals($e1Id, $e1->id); + $this->assertEquals($e2Id, $e2->id); + + $this->assertEquals('Bar 1', $e1->value); + $this->assertEquals('Foo 1', $e2->value); + + $e1->value = 'Bar 2'; + $e2->value = 'Foo 2'; + + // Update + $this->_em->persist($e1); + $this->_em->persist($e2); + $this->_em->flush(); + + $this->assertEquals('Bar 2', $e1->value); + $this->assertEquals('Foo 2', $e2->value); + + $this->assertInstanceOf(self::CLASS_NAME, $e1); + $this->assertInstanceOf(self::CLASS_NAME, $e2); + + $this->assertEquals($e1Id, $e1->id); + $this->assertEquals($e2Id, $e2->id); + + $this->assertEquals('Bar 2', $e1->value); + $this->assertEquals('Foo 2', $e2->value); + + // Delete + $this->_em->remove($e1); + $this->_em->remove($e2); + $this->_em->flush(); + + + $e1 = $this->_em->find(self::CLASS_NAME, $e1Id); + $e2 = $this->_em->find(self::CLASS_NAME, $e2Id); + + $this->assertNull($e1); + $this->assertNull($e2); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1757Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1757Test.php new file mode 100644 index 0000000..488f469 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1757Test.php @@ -0,0 +1,92 @@ +_em->createQueryBuilder(); + /* @var $qb \Doctrine\ORM\QueryBuilder */ + + $qb->select('_a') + ->from(__NAMESPACE__ . '\DDC1757A', '_a') + ->from(__NAMESPACE__ . '\DDC1757B', '_b') + ->join('_b.c', '_c') + ->join('_c.d', '_d'); + + $q = $qb->getQuery(); + $dql = $q->getDQL(); + + // Show difference between expected and actual queries on error + self::assertEquals("SELECT _a FROM " . __NAMESPACE__ . "\DDC1757A _a, " . __NAMESPACE__ . "\DDC1757B _b INNER JOIN _b.c _c INNER JOIN _c.d _d", + $dql, + "Wrong DQL query"); + } +} + +/** + * @Entity + */ +class DDC1757A +{ + /** + * @Column(type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + private $id; +} + +/** + * @Entity + */ +class DDC1757B +{ + /** + * @Column(type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @OneToOne(targetEntity="DDC1757C") + */ + private $c; +} + +/** + * @Entity + */ +class DDC1757C +{ + /** + * @Column(type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @OneToOne(targetEntity="DDC1757D") + */ + private $d; +} + +/** + * @Entity + */ +class DDC1757D +{ + /** + * @Column(type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + public $id; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1778Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1778Test.php new file mode 100644 index 0000000..aebc642 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1778Test.php @@ -0,0 +1,74 @@ +useModelSet('cms'); + parent::setUp(); + + $this->user = new CmsUser(); + $this->user->username = "beberlei"; + $this->user->name = "Benjamin"; + $this->user->status = "active"; + + $this->phone = new CmsPhoneNumber(); + $this->phone->phonenumber = '0123456789'; + $this->user->addPhoneNumber($this->phone); + + $this->_em->persist($this->user); + $this->_em->persist($this->phone); + $this->_em->flush(); + $this->_em->clear(); + + $this->user = $this->_em->find('Doctrine\\Tests\\Models\\CMS\\CmsUser', $this->user->getId()); + $this->phone = $this->_em->find('Doctrine\\Tests\\Models\\CMS\\CmsPhonenumber', $this->phone->phonenumber); + } + + public function testClear() + { + $clonedNumbers = clone $this->user->getPhonenumbers(); + $clonedNumbers->clear(); + $this->_em->flush(); + $this->_em->clear(); + + $this->user = $this->_em->find('Doctrine\\Tests\\Models\\CMS\\CmsUser', $this->user->getId()); + + $this->assertCount(1, $this->user->getPhonenumbers()); + } + + public function testRemove() + { + $clonedNumbers = clone $this->user->getPhonenumbers(); + $clonedNumbers->remove(0); + $this->_em->flush(); + $this->_em->clear(); + + $this->user = $this->_em->find('Doctrine\\Tests\\Models\\CMS\\CmsUser', $this->user->getId()); + + $this->assertCount(1, $this->user->getPhonenumbers()); + } + + public function testRemoveElement() + { + $clonedNumbers = clone $this->user->getPhonenumbers(); + $clonedNumbers->removeElement($this->phone); + $this->_em->flush(); + $this->_em->clear(); + + $this->user = $this->_em->find('Doctrine\\Tests\\Models\\CMS\\CmsUser', $this->user->getId()); + + $this->assertCount(1, $this->user->getPhonenumbers()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1843Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1843Test.php new file mode 100644 index 0000000..15cfd59 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1843Test.php @@ -0,0 +1,136 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\User'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Group'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Phone'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Address'), + )); + } catch(\Exception $e) { + } + } + + public function testCreateRetreaveUpdateDelete() + { + + $e1 = new Group('Parent Bar 1'); + $e2 = new Group('Parent Foo 2'); + + $this->_em->persist($e1); + $this->_em->persist($e2); + $this->_em->flush(); + + $e3 = new Group('Bar 3', $e1); + $e4 = new Group('Foo 4', $e2); + + // Create + $this->_em->persist($e3); + $this->_em->persist($e4); + $this->_em->flush(); + $this->_em->clear(); + + $e1Id = $e1->id; + $e2Id = $e2->id; + $e3Id = $e3->id; + $e4Id = $e4->id; + + // Retreave + $e1 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e1Id); + $e2 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e2Id); + $e3 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e3Id); + $e4 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e4Id); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e1); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e2); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e3); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e4); + + $this->assertEquals($e1Id, $e1->id); + $this->assertEquals($e2Id, $e2->id); + $this->assertEquals($e3Id, $e3->id); + $this->assertEquals($e4Id, $e4->id); + + + $this->assertEquals('Parent Bar 1', $e1->name); + $this->assertEquals('Parent Foo 2', $e2->name); + $this->assertEquals('Bar 3', $e3->name); + $this->assertEquals('Foo 4', $e4->name); + + $e1->name = 'Parent Bar 11'; + $e2->name = 'Parent Foo 22'; + $e3->name = 'Bar 33'; + $e4->name = 'Foo 44'; + + // Update + $this->_em->persist($e1); + $this->_em->persist($e2); + $this->_em->persist($e3); + $this->_em->persist($e4); + $this->_em->flush(); + + $this->assertEquals('Parent Bar 11', $e1->name); + $this->assertEquals('Parent Foo 22', $e2->name); + $this->assertEquals('Bar 33', $e3->name); + $this->assertEquals('Foo 44', $e4->name); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e1); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e2); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e3); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e4); + + $this->assertEquals($e1Id, $e1->id); + $this->assertEquals($e2Id, $e2->id); + $this->assertEquals($e3Id, $e3->id); + $this->assertEquals($e4Id, $e4->id); + + $this->assertEquals('Parent Bar 11', $e1->name); + $this->assertEquals('Parent Foo 22', $e2->name); + $this->assertEquals('Bar 33', $e3->name); + $this->assertEquals('Foo 44', $e4->name); + + // Delete + $this->_em->remove($e4); + $this->_em->remove($e3); + $this->_em->remove($e2); + $this->_em->remove($e1); + + $this->_em->flush(); + $this->_em->clear(); + + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e1); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e2); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e3); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $e4); + + // Retreave + $e1 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e1Id); + $e2 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e2Id); + $e3 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e3Id); + $e4 = $this->_em->find('Doctrine\Tests\Models\Quote\Group', $e4Id); + + $this->assertNull($e1); + $this->assertNull($e2); + $this->assertNull($e3); + $this->assertNull($e4); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1885Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1885Test.php new file mode 100644 index 0000000..9d15815 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1885Test.php @@ -0,0 +1,171 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\User'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Group'), + $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\Address'), + )); + } catch(\Exception $e) { + } + + $user = new User(); + $user->name = "FabioBatSilva"; + $user->email = "fabio.bat.silva@gmail.com"; + $user->groups[] = new Group('G 1'); + $user->groups[] = new Group('G 2'); + $this->user = $user; + + // Create + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + } + + public function testCreateRetreaveUpdateDelete() + { + $user = $this->user; + $g1 = $user->getGroups()->get(0); + $g2 = $user->getGroups()->get(1); + + $u1Id = $user->id; + $g1Id = $g1->id; + $g2Id = $g2->id; + + // Retreave + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $u1Id); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertEquals('FabioBatSilva', $user->name); + $this->assertEquals($u1Id, $user->id); + + $this->assertCount(2, $user->groups); + + $g1 = $user->getGroups()->get(0); + $g2 = $user->getGroups()->get(1); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $g1); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $g2); + + $g1->name = 'Bar 11'; + $g2->name = 'Foo 22'; + + // Update + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $u1Id); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertEquals('FabioBatSilva', $user->name); + $this->assertEquals($u1Id, $user->id); + + // Delete + $this->_em->remove($user); + + $this->_em->flush(); + $this->_em->clear(); + + $this->assertNull($this->_em->find('Doctrine\Tests\Models\Quote\User', $u1Id)); + $this->assertNull($this->_em->find('Doctrine\Tests\Models\Quote\Group', $g1Id)); + $this->assertNull($this->_em->find('Doctrine\Tests\Models\Quote\Group', $g2Id)); + } + + public function testRemoveItem() + { + $user = $this->user; + $u1Id = $user->id; + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $u1Id); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertEquals('FabioBatSilva', $user->name); + $this->assertEquals($u1Id, $user->id); + + $this->assertCount(2, $user->groups); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $user->getGroups()->get(0)); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $user->getGroups()->get(1)); + + $user->getGroups()->remove(0); + + // Update + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $u1Id); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertEquals('FabioBatSilva', $user->name); + $this->assertEquals($u1Id, $user->id); + + $this->assertCount(1, $user->getGroups()); + } + + public function testClearAll() + { + $user = $this->user; + $u1Id = $user->id; + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $u1Id); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertEquals('FabioBatSilva', $user->name); + $this->assertEquals($u1Id, $user->id); + + $this->assertCount(2, $user->groups); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $user->getGroups()->get(0)); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $user->getGroups()->get(1)); + + $user->getGroups()->clear(); + + // Update + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $u1Id); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertEquals('FabioBatSilva', $user->name); + $this->assertEquals($u1Id, $user->id); + + $this->assertCount(0, $user->getGroups()); + } + + public function testCountExtraLazy() + { + $user = $this->user; + $u1Id = $user->id; + $user = $this->_em->find('Doctrine\Tests\Models\Quote\User', $u1Id); + + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\User', $user); + $this->assertEquals('FabioBatSilva', $user->name); + $this->assertEquals($u1Id, $user->id); + + $this->assertCount(0, $user->extraLazyGroups); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $user->getGroups()->get(0)); + $this->assertInstanceOf('Doctrine\Tests\Models\Quote\Group', $user->getGroups()->get(1)); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1918Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1918Test.php new file mode 100644 index 0000000..64b3ad4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1918Test.php @@ -0,0 +1,62 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testLastPageCorrect() + { + $groups = array(); + for ($i = 0; $i < 3; $i++) { + $group = new CmsGroup(); + $group->name = "test"; + $this->_em->persist($group); + + $groups[] = $group; + } + + for ($i = 0; $i < 10; $i++) { + $user = new CmsUser(); + $user->username = "user$i"; + $user->name = "user$i"; + $user->status = "active"; + $user->groups = $groups; + + $this->_em->persist($user); + } + + $this->_em->flush(); + + $query = $this->_em->createQuery('SELECT u, g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g'); + $query->setFirstResult(6); + $query->setMaxResults(3); + + $paginator = new Paginator($query, true); + $this->assertEquals(3, count(iterator_to_array($paginator))); + + $query->setFirstResult(8); + $query->setMaxResults(3); + + $paginator = new Paginator($query, true); + $this->assertEquals(2, count(iterator_to_array($paginator))); + + $query->setFirstResult(10); + $query->setMaxResults(3); + + $paginator = new Paginator($query, true); + $this->assertEquals(0, count(iterator_to_array($paginator))); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC192Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC192Test.php new file mode 100644 index 0000000..18eb769 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC192Test.php @@ -0,0 +1,65 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC192User'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC192Phonenumber') + )); + } +} + + +/** + * @Entity @Table(name="ddc192_users") + */ +class DDC192User +{ + /** + * @Id @Column(name="id", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @Column(name="name", type="string") + */ + public $name; +} + + +/** + * @Entity @Table(name="ddc192_phonenumbers") + */ +class DDC192Phonenumber +{ + /** + * @Id @Column(name="phone", type="string", length=40) + */ + protected $phone; + + /** + * @Id + * @ManyToOne(targetEntity="DDC192User") + * @JoinColumn(name="userId", referencedColumnName="id") + */ + protected $User; + + + public function setPhone($value) { $this->phone = $value; } + + public function getPhone() { return $this->phone; } + + public function setUser(User $user) + { + $this->User = $user; + } + + public function getUser() { return $this->User; } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC199Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC199Test.php new file mode 100644 index 0000000..9084ec0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC199Test.php @@ -0,0 +1,100 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC199ParentClass'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC199ChildClass'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC199RelatedClass') + )); + } + + public function testPolymorphicLoading() + { + $child = new DDC199ChildClass; + $child->parentData = 'parentData'; + $child->childData = 'childData'; + $this->_em->persist($child); + + $related1 = new DDC199RelatedClass; + $related1->relatedData = 'related1'; + $related1->parent = $child; + $this->_em->persist($related1); + + $related2 = new DDC199RelatedClass; + $related2->relatedData = 'related2'; + $related2->parent = $child; + $this->_em->persist($related2); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery('select e,r from Doctrine\Tests\ORM\Functional\Ticket\DDC199ParentClass e join e.relatedEntities r'); + $result = $query->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC199ParentClass', $result[0]); + $this->assertTrue($result[0]->relatedEntities->isInitialized()); + $this->assertEquals(2, $result[0]->relatedEntities->count()); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC199RelatedClass', $result[0]->relatedEntities[0]); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC199RelatedClass', $result[0]->relatedEntities[1]); + } +} + + +/** + * @Entity @Table(name="ddc199_entities") + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"parent" = "DDC199ParentClass", "child" = "DDC199ChildClass"}) + */ +class DDC199ParentClass +{ + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @Column(type="string") + */ + public $parentData; + + /** + * @OneToMany(targetEntity="DDC199RelatedClass", mappedBy="parent") + */ + public $relatedEntities; +} + + +/** @Entity */ +class DDC199ChildClass extends DDC199ParentClass +{ + /** + * @Column + */ + public $childData; +} + +/** @Entity @Table(name="ddc199_relatedclass") */ +class DDC199RelatedClass +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @Column */ + public $relatedData; + + /** + * @ManyToOne(targetEntity="DDC199ParentClass", inversedBy="relatedEntities") + * @JoinColumn(name="parent_id", referencedColumnName="id") + */ + public $parent; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC211Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC211Test.php new file mode 100644 index 0000000..6104c9c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC211Test.php @@ -0,0 +1,116 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC211User'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC211Group') + )); + } + + public function testIssue() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $user = new DDC211User; + $user->setName('John Doe'); + + $this->_em->persist($user); + $this->_em->flush(); + + $groupNames = array('group 1', 'group 2', 'group 3', 'group 4'); + foreach ($groupNames as $name) { + + $group = new DDC211Group; + $group->setName($name); + $this->_em->persist($group); + $this->_em->flush(); + + if (!$user->getGroups()->contains($group)) { + $user->getGroups()->add($group); + $group->getUsers()->add($user); + $this->_em->flush(); + } + } + + $this->assertEquals(4, $user->getGroups()->count()); + + } +} + + +/** + * @Entity + * @Table(name="ddc211_users") +*/ +class DDC211User +{ + /** + * @Id + * @Column(name="id", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + protected $id; + + /** + * @Column(name="name", type="string") + */ + protected $name; + + /** + * @ManyToMany(targetEntity="DDC211Group", inversedBy="users") + * @JoinTable(name="user_groups", + * joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")}, + * inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")} + * ) + */ + protected $groups; + + public function __construct() { + $this->groups = new \Doctrine\Common\Collections\ArrayCollection(); + } + + public function setName($name) { $this->name = $name; } + + public function getGroups() { return $this->groups; } +} + +/** + * @Entity + * @Table(name="ddc211_groups") + */ +class DDC211Group +{ + /** + * @Id + * @Column(name="id", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + protected $id; + + /** + * @Column(name="name", type="string") + */ + protected $name; + + /** + * @ManyToMany(targetEntity="DDC211User", mappedBy="groups") + */ + protected $users; + + public function __construct() { + $this->users = new \Doctrine\Common\Collections\ArrayCollection(); + } + + public function setName($name) { $this->name = $name; } + + public function getUsers() { return $this->users; } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC237Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC237Test.php new file mode 100644 index 0000000..413e564 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC237Test.php @@ -0,0 +1,112 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC237EntityX'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC237EntityY'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC237EntityZ') + )); + } + + public function testUninitializedProxyIsInitializedOnFetchJoin() + { + $x = new DDC237EntityX; + $y = new DDC237EntityY; + $z = new DDC237EntityZ; + + $x->data = 'X'; + $y->data = 'Y'; + $z->data = 'Z'; + + $x->y = $y; + $z->y = $y; + + $this->_em->persist($x); + $this->_em->persist($y); + $this->_em->persist($z); + + $this->_em->flush(); + $this->_em->clear(); + + $x2 = $this->_em->find(get_class($x), $x->id); // proxy injected for Y + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $x2->y); + $this->assertFalse($x2->y->__isInitialized__); + + // proxy for Y is in identity map + + $z2 = $this->_em->createQuery('select z,y from ' . get_class($z) . ' z join z.y y where z.id = ?1') + ->setParameter(1, $z->id) + ->getSingleResult(); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $z2->y); + $this->assertTrue($z2->y->__isInitialized__); + $this->assertEquals('Y', $z2->y->data); + $this->assertEquals($y->id, $z2->y->id); + + // since the Y is the same, the instance from the identity map is + // used, even if it is a proxy. + + $this->assertNotSame($x, $x2); + $this->assertNotSame($z, $z2); + $this->assertSame($z2->y, $x2->y); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $z2->y); + + } +} + + +/** + * @Entity @Table(name="ddc237_x") + */ +class DDC237EntityX +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + public $id; + /** + * @Column(type="string") + */ + public $data; + /** + * @OneToOne(targetEntity="DDC237EntityY") + * @JoinColumn(name="y_id", referencedColumnName="id") + */ + public $y; +} + + +/** @Entity @Table(name="ddc237_y") */ +class DDC237EntityY +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + public $id; + /** + * @Column(type="string") + */ + public $data; +} + +/** @Entity @Table(name="ddc237_z") */ +class DDC237EntityZ +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @Column(type="string") */ + public $data; + + /** + * @OneToOne(targetEntity="DDC237EntityY") + * @JoinColumn(name="y_id", referencedColumnName="id") + */ + public $y; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC258Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC258Test.php new file mode 100644 index 0000000..0d766ea --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC258Test.php @@ -0,0 +1,142 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC258Super'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC258Class1'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC258Class2'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC258Class3'), + )); + } + + /** + * @group DDC-258 + */ + public function testIssue() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $c1 = new DDC258Class1(); + $c1->title = "Foo"; + $c1->description = "Foo"; + + $c2 = new DDC258Class2(); + $c2->title = "Bar"; + $c2->description = "Bar"; + $c2->text = "Bar"; + + $c3 = new DDC258Class3(); + $c3->apples = "Baz"; + $c3->bananas = "Baz"; + + $this->_em->persist($c1); + $this->_em->persist($c2); + $this->_em->persist($c3); + $this->_em->flush(); + $this->_em->clear(); + + $e2 = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC258Super', $c2->id); + + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC258Class2', $e2); + $this->assertEquals('Bar', $e2->title); + $this->assertEquals('Bar', $e2->description); + $this->assertEquals('Bar', $e2->text); + + $all = $this->_em->getRepository(__NAMESPACE__.'\DDC258Super')->findAll(); + + foreach ($all as $obj) { + if ($obj instanceof DDC258Class1) { + $this->assertEquals('Foo', $obj->title); + $this->assertEquals('Foo', $obj->description); + } else if ($obj instanceof DDC258Class2) { + $this->assertTrue($e2 === $obj); + $this->assertEquals('Bar', $obj->title); + $this->assertEquals('Bar', $obj->description); + $this->assertEquals('Bar', $obj->text); + } else if ($obj instanceof DDC258Class3) { + $this->assertEquals('Baz', $obj->apples); + $this->assertEquals('Baz', $obj->bananas); + } else { + $this->fail('Instance of DDC258Class1, DDC258Class2 or DDC258Class3 expected.'); + } + } + } +} + +/** + * @Entity + * @Table(name="DDC258Super") + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="type", type="string") + * @DiscriminatorMap({"class1" = "DDC258Class1", "class2" = "DDC258Class2", "class3"="DDC258Class3"}) + */ +abstract class DDC258Super +{ + /** + * @Id @Column(name="id", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; +} + +/** + * @Entity + */ +class DDC258Class1 extends DDC258Super +{ + /** + * @Column(name="title", type="string", length=150) + */ + public $title; + + /** + * @Column(name="content", type="string", length=500) + */ + public $description; +} + +/** + * @Entity + */ +class DDC258Class2 extends DDC258Super +{ + /** + * @Column(name="title", type="string", length=150) + */ + public $title; + + /** + * @Column(name="content", type="string", length=500) + */ + public $description; + + /** + * @Column(name="text", type="text") + */ + public $text; +} + +/** + * An extra class to demonstrate why title and description aren't in Super + * + * @Entity + */ +class DDC258Class3 extends DDC258Super +{ + /** + * @Column(name="title", type="string", length=150) + */ + public $apples; + + /** + * @Column(name="content", type="string", length=500) + */ + public $bananas; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC279Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC279Test.php new file mode 100644 index 0000000..6d41ea8 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC279Test.php @@ -0,0 +1,133 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC279EntityXAbstract'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC279EntityX'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC279EntityY'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC279EntityZ'), + )); + } + + /** + * @group DDC-279 + */ + public function testDDC279() + { + $x = new DDC279EntityX(); + $y = new DDC279EntityY(); + $z = new DDC279EntityZ(); + + $x->data = 'X'; + $y->data = 'Y'; + $z->data = 'Z'; + + $x->y = $y; + $y->z = $z; + + $this->_em->persist($x); + $this->_em->persist($y); + $this->_em->persist($z); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery( + 'SELECT x, y, z FROM Doctrine\Tests\ORM\Functional\Ticket\DDC279EntityX x '. + 'INNER JOIN x.y y INNER JOIN y.z z WHERE x.id = ?1' + )->setParameter(1, $x->id); + + $result = $query->getResult(); + + $expected1 = 'Y'; + $expected2 = 'Z'; + + $this->assertEquals(1, count($result)); + + $this->assertEquals($expected1, $result[0]->y->data); + $this->assertEquals($expected2, $result[0]->y->z->data); + } +} + + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"DDC279EntityX" = "DDC279EntityX"}) + */ +abstract class DDC279EntityXAbstract +{ + /** + * @Id + * @GeneratedValue + * @Column(name="id", type="integer") + */ + public $id; + + /** + * @column(type="string") + */ + public $data; + +} + +/** + * @Entity + */ +class DDC279EntityX extends DDC279EntityXAbstract +{ + /** + * @OneToOne(targetEntity="DDC279EntityY") + * @JoinColumn(name="y_id", referencedColumnName="id") + */ + public $y; +} + +/** + * @Entity + */ +class DDC279EntityY +{ + /** + * @Id @GeneratedValue + * @Column(name="id", type="integer") + */ + public $id; + + /** + * @column(type="string") + */ + public $data; + + /** + * @OneToOne(targetEntity="DDC279EntityZ") + * @JoinColumn(name="z_id", referencedColumnName="id") + */ + public $z; +} + +/** + * @Entity + */ +class DDC279EntityZ +{ + /** + * @Id @GeneratedValue + * @Column(name="id", type="integer") + */ + public $id; + + /** + * @column(type="string") + */ + public $data; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC309Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC309Test.php new file mode 100644 index 0000000..325ce8d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC309Test.php @@ -0,0 +1,73 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC309Country'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC309User'), + )); + } + + public function testTwoIterateHydrations() + { + $c1 = new DDC309Country(); + $c2 = new DDC309Country(); + $u1 = new DDC309User(); + $u2 = new DDC309User(); + + $this->_em->persist($c1); + $this->_em->persist($c2); + $this->_em->persist($u1); + $this->_em->persist($u2); + $this->_em->flush(); + $this->_em->clear(); + + $q = $this->_em->createQuery('SELECT c FROM Doctrine\Tests\ORM\Functional\Ticket\DDC309Country c')->iterate(); + $c = $q->next(); + + $this->assertEquals(1, $c[0]->id); + + $r = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\ORM\Functional\Ticket\DDC309User u')->iterate(); + $u = $r->next(); // This line breaks + + $this->assertEquals(1, $u[0]->id); + + $c = $q->next(); + $u = $r->next(); + + $this->assertEquals(2, $c[0]->id); + $this->assertEquals(2, $u[0]->id); + } +} + +/** + * @Entity + */ +class DDC309Country +{ + /** + * @Id + * @Column(name="id", type="integer") + * @GeneratedValue + */ + public $id; +} + +/** + * @Entity + */ +class DDC309User +{ + /** + * @Id + * @Column(name="id", type="integer") + * @GeneratedValue + */ + public $id; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC331Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC331Test.php new file mode 100644 index 0000000..2db32b9 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC331Test.php @@ -0,0 +1,39 @@ + + */ +class DDC331Test extends \Doctrine\Tests\OrmFunctionalTestCase +{ + protected function setUp() { + $this->useModelSet('company'); + parent::setUp(); + } + + /** + * @group DDC-331 + */ + public function testSelectFieldOnRootEntity() + { + $q = $this->_em->createQuery('SELECT e.name FROM Doctrine\Tests\Models\Company\CompanyEmployee e'); + $this->assertEquals( + strtolower('SELECT c0_.name AS name0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id'), + strtolower($q->getSql()) + ); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC345Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC345Test.php new file mode 100644 index 0000000..757b5ab --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC345Test.php @@ -0,0 +1,157 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC345User'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC345Group'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC345Membership'), + )); + } + + public function testTwoIterateHydrations() + { + // Create User + $user = new DDC345User; + $user->name = 'Test User'; + $this->_em->persist($user); // $em->flush() does not change much here + + // Create Group + $group = new DDC345Group; + $group->name = 'Test Group'; + $this->_em->persist($group); // $em->flush() does not change much here + + $membership = new DDC345Membership; + $membership->group = $group; + $membership->user = $user; + $membership->state = 'active'; + + //$this->_em->persist($membership); // COMMENT OUT TO SEE BUG + /* + This should be not necessary, but without, its PrePersist is called twice, + $membership seems to be persisted twice, but all properties but the + ones set by LifecycleCallbacks are deleted. + */ + + $user->Memberships->add($membership); + $group->Memberships->add($membership); + + $this->_em->flush(); + + $this->assertEquals(1, $membership->prePersistCallCount); + $this->assertEquals(0, $membership->preUpdateCallCount); + $this->assertInstanceOf('DateTime', $membership->updated); + } +} + +/** + * @Entity + */ +class DDC345User +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + public $id; + + /** @Column(type="string") */ + public $name; + + /** @OneToMany(targetEntity="DDC345Membership", mappedBy="user", cascade={"persist"}) */ + public $Memberships; + + public function __construct() + { + $this->Memberships = new \Doctrine\Common\Collections\ArrayCollection; + } +} + +/** + * @Entity + */ +class DDC345Group +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + public $id; + + /** @Column(type="string") */ + public $name; + + /** @OneToMany(targetEntity="DDC345Membership", mappedBy="group", cascade={"persist"}) */ + public $Memberships; + + + public function __construct() + { + $this->Memberships = new \Doctrine\Common\Collections\ArrayCollection; + } +} + +/** + * @Entity + * @HasLifecycleCallbacks + * @Table(name="ddc345_memberships", uniqueConstraints={ + * @UniqueConstraint(name="ddc345_memship_fks", columns={"user_id","group_id"}) + * }) + */ +class DDC345Membership +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + public $id; + + /** + * @OneToOne(targetEntity="DDC345User", inversedBy="Memberships") + * @JoinColumn(name="user_id", referencedColumnName="id", nullable=false) + */ + public $user; + + /** + * @OneToOne(targetEntity="DDC345Group", inversedBy="Memberships") + * @JoinColumn(name="group_id", referencedColumnName="id", nullable=false) + */ + public $group; + + /** @Column(type="string") */ + public $state; + + /** @Column(type="datetime") */ + public $updated; + + public $prePersistCallCount = 0; + public $preUpdateCallCount = 0; + + /** @PrePersist */ + public function doStuffOnPrePersist() + { + //echo "***** PrePersist\n"; + ++$this->prePersistCallCount; + $this->updated = new \DateTime; + } + + /** @PreUpdate */ + public function doStuffOnPreUpdate() + { + //echo "***** PreUpdate\n"; + ++$this->preUpdateCallCount; + $this->updated = new \DateTime; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC353Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC353Test.php new file mode 100644 index 0000000..df78359 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC353Test.php @@ -0,0 +1,150 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC353File'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC353Picture'), + )); + } catch(\Exception $ignored) {} + } + + public function testWorkingCase() + { + $file = new DDC353File; + + $picture = new DDC353Picture; + $picture->setFile($file); + + $em = $this->_em; + $em->persist($picture); + $em->flush(); + $em->clear(); + + $fileId = $file->getFileId(); + $this->assertTrue($fileId > 0); + + $file = $em->getReference('Doctrine\Tests\ORM\Functional\Ticket\DDC353File', $fileId); + $this->assertEquals(UnitOfWork::STATE_MANAGED, $em->getUnitOfWork()->getEntityState($file), "Reference Proxy should be marked MANAGED."); + + $picture = $em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC353Picture', $picture->getPictureId()); + $this->assertEquals(UnitOfWork::STATE_MANAGED, $em->getUnitOfWork()->getEntityState($picture->getFile()), "Lazy Proxy should be marked MANAGED."); + + $em->remove($picture); + $em->flush(); + } + + public function testFailingCase() + { + $file = new DDC353File; + + $picture = new DDC353Picture; + $picture->setFile($file); + + $em = $this->_em; + $em->persist($picture); + $em->flush(); + $em->clear(); + + $fileId = $file->getFileId(); + $pictureId = $picture->getPictureId(); + + $this->assertTrue($fileId > 0); + + $picture = $em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC353Picture', $pictureId); + $this->assertEquals(UnitOfWork::STATE_MANAGED, $em->getUnitOfWork()->getEntityState($picture->getFile()), "Lazy Proxy should be marked MANAGED."); + + $em->remove($picture); + $em->flush(); + } +} + +/** + * @Entity + */ +class DDC353Picture +{ + /** + * @Column(name="picture_id", type="integer") + * @Id @GeneratedValue + */ + private $pictureId; + + /** + * @ManyToOne(targetEntity="DDC353File", cascade={"persist", "remove"}) + * @JoinColumns({ + * @JoinColumn(name="file_id", referencedColumnName="file_id") + * }) + */ + private $file; + + /** + * Get pictureId + */ + public function getPictureId() + { + return $this->pictureId; + } + + /** + * Set product + */ + public function setProduct($value) + { + $this->product = $value; + } + + /** + * Get product + */ + public function getProduct() + { + return $this->product; + } + + /** + * Set file + */ + public function setFile($value) + { + $this->file = $value; + } + + /** + * Get file + */ + public function getFile() + { + return $this->file; + } +} + +/** + * @Entity + */ +class DDC353File +{ + /** + * @Column(name="file_id", type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + public $fileId; + + /** + * Get fileId + */ + public function getFileId() + { + return $this->fileId; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC371Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC371Test.php new file mode 100644 index 0000000..2a99519 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC371Test.php @@ -0,0 +1,72 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC371Parent'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC371Child') + )); + } + + public function testIssue() + { + $parent = new DDC371Parent; + $parent->data = 'parent'; + $parent->children = new \Doctrine\Common\Collections\ArrayCollection; + + $child = new DDC371Child; + $child->data = 'child'; + + $child->parent = $parent; + $parent->children->add($child); + + $this->_em->persist($parent); + $this->_em->persist($child); + + $this->_em->flush(); + $this->_em->clear(); + + $children = $this->_em->createQuery('select c,p from '.__NAMESPACE__.'\DDC371Child c ' + . 'left join c.parent p where c.id = 1 and p.id = 1') + ->setHint(Query::HINT_REFRESH, true) + ->getResult(); + + $this->assertEquals(1, count($children)); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $children[0]->parent); + $this->assertFalse($children[0]->parent->children->isInitialized()); + $this->assertEquals(0, $children[0]->parent->children->unwrap()->count()); + } +} + +/** @Entity */ +class DDC371Child { + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; + /** @Column(type="string") */ + public $data; + /** @ManyToOne(targetEntity="DDC371Parent", inversedBy="children") @JoinColumn(name="parentId") */ + public $parent; +} + +/** @Entity */ +class DDC371Parent { + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; + /** @Column(type="string") */ + public $data; + /** @OneToMany(targetEntity="DDC371Child", mappedBy="parent") */ + public $children; +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC381Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC381Test.php new file mode 100644 index 0000000..9b47bc8 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC381Test.php @@ -0,0 +1,63 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC381Entity'), + )); + } catch(\Exception $e) { + + } + } + + public function testCallUnserializedProxyMethods() + { + $entity = new DDC381Entity(); + + $this->_em->persist($entity); + $this->_em->flush(); + $this->_em->clear(); + $persistedId = $entity->getId(); + + $entity = $this->_em->getReference('Doctrine\Tests\ORM\Functional\Ticket\DDC381Entity', $persistedId); + + // explicitly load proxy (getId() does not trigger reload of proxy) + $id = $entity->getOtherMethod(); + + $data = serialize($entity); + $entity = unserialize($data); + + $this->assertEquals($persistedId, $entity->getId()); + } +} + +/** + * @Entity + */ +class DDC381Entity +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + protected $id; + + public function getId() + { + return $this->id; + } + + public function getOtherMethod() + { + + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC422Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC422Test.php new file mode 100644 index 0000000..3a6dbdb --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC422Test.php @@ -0,0 +1,75 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC422Guest'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC422Customer'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC422Contact') + )); + } + + /** + * @group DDC-422 + */ + public function testIssue() + { + $customer = new DDC422Customer; + $this->_em->persist($customer); + $this->_em->flush(); + $this->_em->clear(); + + $customer = $this->_em->find(get_class($customer), $customer->id); + + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $customer->contacts); + $this->assertFalse($customer->contacts->isInitialized()); + $contact = new DDC422Contact; + $customer->contacts->add($contact); + $this->assertTrue($customer->contacts->isDirty()); + $this->assertFalse($customer->contacts->isInitialized()); + $this->_em->flush(); + + $this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select count(*) from ddc422_customers_contacts")); + } +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"guest" = "DDC422Guest", "customer" = "DDC422Customer"}) + */ +class DDC422Guest { + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; +} + +/** @Entity */ +class DDC422Customer extends DDC422Guest { + /** + * @ManyToMany(targetEntity="DDC422Contact", cascade={"persist","remove"}) + * @JoinTable(name="ddc422_customers_contacts", + * joinColumns={@JoinColumn(name="customer_id", referencedColumnName="id", onDelete="cascade" )}, + * inverseJoinColumns={@JoinColumn(name="contact_id", referencedColumnName="id", onDelete="cascade" )} + * ) + */ + public $contacts; + + public function __construct() { + $this->contacts = new \Doctrine\Common\Collections\ArrayCollection; + } +} + +/** @Entity */ +class DDC422Contact { + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC425Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC425Test.php new file mode 100644 index 0000000..084da56 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC425Test.php @@ -0,0 +1,43 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC425Entity'), + //$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC425Other') + )); + } + + /** + * @group DDC-425 + */ + public function testIssue() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $num = $this->_em->createQuery('DELETE '.__NAMESPACE__.'\DDC425Entity e WHERE e.someDatetimeField > ?1') + ->setParameter(1, new DateTime, Type::DATETIME) + ->getResult(); + $this->assertEquals(0, $num); + } +} + +/** @Entity */ +class DDC425Entity { + /** + * @Id @Column(type="integer") + * @GeneratedValue + */ + public $id; + + /** @Column(type="datetime") */ + public $someDatetimeField; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC440Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC440Test.php new file mode 100644 index 0000000..2b374a8 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC440Test.php @@ -0,0 +1,216 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\DDC440Phone'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\DDC440Client') + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + + /** + * @group DDC-440 + */ + public function testOriginalEntityDataEmptyWhenProxyLoadedFromTwoAssociations() + { + + + /* The key of the problem is that the first phone is fetched via two association, main_phone and phones. + * + * You will notice that the original_entity_datas are not loaded for the first phone. (They are for the second) + * + * In the Client entity definition, if you define the main_phone relation after the phones relation, both assertions pass. + * (for the sake or this test, I defined the main_phone relation before the phones relation) + * + */ + + //Initialize some data + $client = new DDC440Client; + $client->setName('Client1'); + + $phone = new DDC440Phone; + $phone->setNumber('418 111-1111'); + $phone->setClient($client); + + $phone2 = new DDC440Phone; + $phone2->setNumber('418 222-2222'); + $phone2->setClient($client); + + $client->setMainPhone($phone); + + $this->_em->persist($client); + $this->_em->flush(); + $id = $client->getId(); + $this->_em->clear(); + + $uw = $this->_em->getUnitOfWork(); + $client = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC440Client', $id); + $clientPhones = $client->getPhones(); + $p1 = $clientPhones[0]; + $p2 = $clientPhones[1]; + + // Test the first phone. The assertion actually failed because original entity data is not set properly. + // This was because it is also set as MainPhone and that one is created as a proxy, not the + // original object when the find on Client is called. However loading proxies did not work correctly. + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC440Phone', $p1); + $originalData = $uw->getOriginalEntityData($p1); + $this->assertEquals($phone->getNumber(), $originalData['number']); + + + //If you comment out previous test, this one should pass + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC440Phone', $p2); + $originalData = $uw->getOriginalEntityData($p2); + $this->assertEquals($phone2->getNumber(), $originalData['number']); + } + +} + +/** + * @Entity + * @Table(name="phone") + */ +class DDC440Phone +{ + + /** + * @Column(name="id", type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + protected $id; + /** + * @ManyToOne(targetEntity="DDC440Client",inversedBy="phones") + * @JoinColumns({ + * @JoinColumn(name="client_id", referencedColumnName="id") + * }) + */ + protected $client; + /** + * @Column(name="phonenumber", type="string") + */ + protected $number; + + public function setNumber($value) + { + $this->number = $value; + } + + public function getNumber() + { + return $this->number; + } + + public function setClient(DDC440Client $value, $update_inverse=true) + { + $this->client = $value; + if ($update_inverse) { + $value->addPhone($this); + } + } + + public function getClient() + { + return $this->client; + } + + public function getId() + { + return $this->id; + } + + public function setId($value) + { + $this->id = $value; + } + +} + +/** + * @Entity + * @Table(name="client") + */ +class DDC440Client +{ + + /** + * @Column(name="id", type="integer") + * @Id + * @GeneratedValue(strategy="AUTO") + */ + protected $id; + /** + * @OneToOne(targetEntity="DDC440Phone", fetch="EAGER") + * @JoinColumns({ + * @JoinColumn(name="main_phone_id", referencedColumnName="id",onDelete="SET NULL") + * }) + */ + protected $main_phone; + /** + * @OneToMany(targetEntity="DDC440Phone", mappedBy="client", cascade={"persist", "remove"}, fetch="EAGER") + * @orderBy({"number"="ASC"}) + */ + protected $phones; + /** + * @Column(name="name", type="string") + */ + protected $name; + + public function __construct() + { + + } + + public function setName($value) + { + $this->name = $value; + } + + public function getName() + { + return $this->name; + } + + public function addPhone(DDC440Phone $value) + { + $this->phones[] = $value; + $value->setClient($this, false); + } + + public function getPhones() + { + return $this->phones; + } + + public function setMainPhone(DDC440Phone $value) + { + $this->main_phone = $value; + } + + public function getMainPhone() + { + return $this->main_phone; + } + + public function getId() + { + return $this->id; + } + + public function setId($value) + { + $this->id = $value; + } + +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC444Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC444Test.php new file mode 100644 index 0000000..d89e67a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC444Test.php @@ -0,0 +1,77 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC444User'), + )); + } + + public function testExplicitPolicy() + { + $classname = __NAMESPACE__ . "\DDC444User"; + + $u = new $classname; + $u->name = "Initial value"; + + $this->_em->persist($u); + $this->_em->flush(); + $this->_em->clear(); + + $q = $this->_em->createQuery("SELECT u FROM $classname u"); + $u = $q->getSingleResult(); + $this->assertEquals("Initial value", $u->name); + + $u->name = "Modified value"; + + // This should be NOOP as the change hasn't been persisted + $this->_em->flush(); + $this->_em->clear(); + + + $u = $this->_em->createQuery("SELECT u FROM $classname u"); + $u = $q->getSingleResult(); + + $this->assertEquals("Initial value", $u->name); + + + $u->name = "Modified value"; + $this->_em->persist($u); + // Now we however persisted it, and this should have updated our friend + $this->_em->flush(); + + $q = $this->_em->createQuery("SELECT u FROM $classname u"); + $u = $q->getSingleResult(); + + $this->assertEquals("Modified value", $u->name); + } +} + + +/** + * @Entity @Table(name="ddc444") + * @ChangeTrackingPolicy("DEFERRED_EXPLICIT") + */ +class DDC444User +{ + /** + * @Id @Column(name="id", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @Column(name="name", type="string") + */ + public $name; +} + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC448Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC448Test.php new file mode 100644 index 0000000..4ea8308 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC448Test.php @@ -0,0 +1,74 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC448MainTable'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC448ConnectedClass'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC448SubTable'), + )); + } + + public function testIssue() + { + $q = $this->_em->createQuery("select b from ".__NAMESPACE__."\\DDC448SubTable b where b.connectedClassId = ?1"); + $this->assertEquals( + strtolower('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.connectedClassId AS connectedClassId2 FROM SubTable s1_ INNER JOIN DDC448MainTable d0_ ON s1_.id = d0_.id WHERE d0_.connectedClassId = ?'), + strtolower($q->getSQL()) + ); + } +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="smallint") + * @DiscriminatorMap({ + * "0" = "DDC448MainTable", + * "1" = "DDC448SubTable" + * }) + */ +class DDC448MainTable +{ + /** + * @Id + * @Column(name="id", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @ManyToOne(targetEntity="DDC448ConnectedClass", cascade={"all"}, fetch="EAGER") + * @JoinColumn(name="connectedClassId", referencedColumnName="id", onDelete="CASCADE", nullable=true) + */ + private $connectedClassId; +} + +/** + * @Entity + * @Table(name="connectedClass") + * @HasLifecycleCallbacks + */ +class DDC448ConnectedClass +{ + /** + * @Id + * @Column(name="id", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + protected $id; // connected with DDC448MainTable +} + +/** + * @Entity + * @Table(name="SubTable") + */ +class DDC448SubTable extends DDC448MainTable +{ +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC493Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC493Test.php new file mode 100644 index 0000000..9e8d58b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC493Test.php @@ -0,0 +1,72 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC493Customer'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC493Distributor'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC493Contact') + )); + } + + public function testIssue() + { + $q = $this->_em->createQuery("select u, c.data from ".__NAMESPACE__."\\DDC493Distributor u JOIN u.contact c"); + $this->assertEquals( + strtolower('SELECT d0_.id AS id0, d1_.data AS data1, d0_.discr AS discr2, d0_.contact AS contact3 FROM DDC493Distributor d2_ INNER JOIN DDC493Customer d0_ ON d2_.id = d0_.id INNER JOIN DDC493Contact d1_ ON d0_.contact = d1_.id'), + strtolower($q->getSQL()) + ); + } +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"distributor" = "DDC493Distributor", "customer" = "DDC493Customer"}) + */ +class DDC493Customer { + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + /** + * @OneToOne(targetEntity="DDC493Contact", cascade={"remove","persist"}) + * @JoinColumn(name="contact", referencedColumnName="id") + */ + public $contact; + +} + +/** + * @Entity + */ +class DDC493Distributor extends DDC493Customer { +} + +/** + * @Entity + */ +class DDC493Contact +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + /** @Column(type="string") */ + public $data; +} + + + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC501Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC501Test.php new file mode 100644 index 0000000..22897ee --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC501Test.php @@ -0,0 +1,124 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testMergeUnitializedManyToManyAndOneToManyCollections() + { + // Create User + $user = $this->createAndPersistUser(); + $this->_em->flush(); + + $this->assertTrue($this->_em->contains($user)); + $this->_em->clear(); + $this->assertFalse($this->_em->contains($user)); + + unset($user); + + // Reload User from DB *without* any associations (i.e. an uninitialized PersistantCollection) + $userReloaded = $this->loadUserFromEntityManager(); + + $this->assertTrue($this->_em->contains($userReloaded)); + $this->_em->clear(); + $this->assertFalse($this->_em->contains($userReloaded)); + + // freeze and unfreeze + $userClone = unserialize(serialize($userReloaded)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $userClone); + + // detached user can't know about his phonenumbers + $this->assertEquals(0, count($userClone->getPhonenumbers())); + $this->assertFalse($userClone->getPhonenumbers()->isInitialized(), "User::phonenumbers should not be marked initialized."); + + // detached user can't know about his groups either + $this->assertEquals(0, count($userClone->getGroups())); + $this->assertFalse($userClone->getGroups()->isInitialized(), "User::groups should not be marked initialized."); + + // Merge back and flush + $userClone = $this->_em->merge($userClone); + + // Back in managed world I would expect to have my phonenumbers back but they aren't! + // Remember I didn't touch (and propably didn't need) them at all while in detached mode. + $this->assertEquals(4, count($userClone->getPhonenumbers()), 'Phonenumbers are not available anymore'); + + // This works fine as long as cmUser::groups doesn't cascade "merge" + $this->assertEquals(2, count($userClone->getGroups())); + + $this->_em->flush(); + $this->_em->clear(); + + $this->assertFalse($this->_em->contains($userClone)); + + // Reload user from DB + $userFromEntityManager = $this->loadUserFromEntityManager(); + + //Strange: Now the phonenumbers are back again + $this->assertEquals(4, count($userFromEntityManager->getPhonenumbers())); + + // This works fine as long as cmUser::groups doesn't cascade "merge" + // Otherwise group memberships are physically deleted now! + $this->assertEquals(2, count($userClone->getGroups())); + } + + protected function createAndPersistUser() + { + $user = new CmsUser(); + $user->name = 'Luka'; + $user->username = 'lukacho'; + $user->status = 'developer'; + + foreach(array(1111,2222,3333,4444) as $number) { + $phone = new CmsPhonenumber; + $phone->phonenumber = $number; + $user->addPhonenumber($phone); + } + + foreach(array('Moshers', 'Headbangers') as $groupName) { + $group = new CmsGroup; + $group->setName($groupName); + $user->addGroup($group); + } + + $this->_em->persist($user); + + return $user; + } + + /** + * @return Doctrine\Tests\Models\CMS\CmsUser + */ + protected function loadUserFromEntityManager() + { + return $this->_em + ->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name like :name') + ->setParameter('name', 'Luka') + ->getSingleResult(); + } + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC512Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC512Test.php new file mode 100644 index 0000000..97245ef --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC512Test.php @@ -0,0 +1,94 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC512Customer'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC512OfferItem'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC512Item'), + )); + } + + public function testIssue() + { + $customer1 = new DDC512Customer(); + $item = new DDC512OfferItem(); + $customer1->item = $item; + $this->_em->persist($customer1); + + $customer2 = new DDC512Customer(); + $this->_em->persist($customer2); + + $this->_em->flush(); + $this->_em->clear(); + + $q = $this->_em->createQuery("select u,i from ".__NAMESPACE__."\\DDC512Customer u left join u.item i"); + $result = $q->getResult(); + + $this->assertEquals(2, count($result)); + $this->assertInstanceOf(__NAMESPACE__ . '\DDC512Customer', $result[0]); + $this->assertInstanceOf(__NAMESPACE__ . '\DDC512Customer', $result[1]); + if ($result[0]->id == $customer1->id) { + $this->assertInstanceOf(__NAMESPACE__ . '\DDC512OfferItem', $result[0]->item); + $this->assertEquals($item->id, $result[0]->item->id); + $this->assertNull($result[1]->item); + } else { + $this->assertInstanceOf(__NAMESPACE__ . '\DDC512OfferItem', $result[1]->item); + $this->assertNull($result[0]->item); + } + } +} + +/** + * @Entity + */ +class DDC512Customer { + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * NOTE that we can currently not name the join column the same as the field + * (item = item), this currently confuses Doctrine. + * + * @OneToOne(targetEntity="DDC512OfferItem", cascade={"remove","persist"}) + * @JoinColumn(name="item_id", referencedColumnName="id") + */ + public $item; +} + +/** + * @Entity + */ +class DDC512OfferItem extends DDC512Item +{ +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"item" = "DDC512Item", "offerItem" = "DDC512OfferItem"}) + */ +class DDC512Item +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; +} + + + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC513Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC513Test.php new file mode 100644 index 0000000..b71d674 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC513Test.php @@ -0,0 +1,74 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC513OfferItem'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC513Item'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC513Price'), + )); + } + + public function testIssue() + { + $q = $this->_em->createQuery("select u from ".__NAMESPACE__."\\DDC513OfferItem u left join u.price p"); + $this->assertEquals( + strtolower('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.price AS price2 FROM DDC513OfferItem d1_ INNER JOIN DDC513Item d0_ ON d1_.id = d0_.id LEFT JOIN DDC513Price d2_ ON d0_.price = d2_.id'), + strtolower($q->getSQL()) + ); + } +} + +/** + * @Entity + */ +class DDC513OfferItem extends DDC513Item +{ +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"item" = "DDC513Item", "offerItem" = "DDC513OfferItem"}) + */ +class DDC513Item +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @OneToOne(targetEntity="DDC513Price", cascade={"remove","persist"}) + * @JoinColumn(name="price", referencedColumnName="id") + */ + public $price; +} + +/** + * @Entity + */ +class DDC513Price { + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** @Column(type="string") */ + public $data; +} + + + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC518Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC518Test.php new file mode 100644 index 0000000..2a34506 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC518Test.php @@ -0,0 +1,36 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testMergeWithRelatedNew() + { + $article = new \Doctrine\Tests\Models\CMS\CmsArticle(); + $article->text = "foo"; + $article->topic = "bar"; + + $this->_em->persist($article); + $this->_em->flush(); + $this->_em->detach($article); + $this->_em->clear(); + + $user = new \Doctrine\Tests\Models\CMS\CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin Eberlei"; + $user->status = "active"; + $article->user = $user; + + $this->_em->persist($user); + $managedArticle = $this->_em->merge($article); + + $this->assertSame($article->user, $managedArticle->user); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC522Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC522Test.php new file mode 100644 index 0000000..f029e95 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC522Test.php @@ -0,0 +1,121 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC522Customer'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC522Cart'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC522ForeignKeyTest') + )); + } catch(\Exception $e) { + + } + } + + /** + * @group DDC-522 + */ + public function testJoinColumnWithSameNameAsAssociationField() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $cust = new DDC522Customer; + $cust->name = "name"; + $cart = new DDC522Cart; + $cart->total = 0; + $cust->cart = $cart; + $cart->customer = $cust; + $this->_em->persist($cust); + $this->_em->persist($cart); + $this->_em->flush(); + + $this->_em->clear(); + + $r = $this->_em->createQuery("select ca,c from ".get_class($cart)." ca join ca.customer c") + ->getResult(); + + $this->assertInstanceOf(__NAMESPACE__ . '\DDC522Cart', $r[0]); + $this->assertInstanceOf(__NAMESPACE__ . '\DDC522Customer', $r[0]->customer); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $r[0]->customer); + $this->assertEquals('name', $r[0]->customer->name); + + $fkt = new DDC522ForeignKeyTest(); + $fkt->cartId = $r[0]->id; // ignored for persistence + $fkt->cart = $r[0]; // must be set properly + $this->_em->persist($fkt); + $this->_em->flush(); + $this->_em->clear(); + + $fkt2 = $this->_em->find(get_class($fkt), $fkt->id); + $this->assertEquals($fkt->cart->id, $fkt2->cartId); + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $fkt2->cart); + $this->assertFalse($fkt2->cart->__isInitialized__); + } + + /** + * @group DDC-522 + * @group DDC-762 + */ + public function testJoinColumnWithNullSameNameAssociationField() + { + $fkCust = new DDC522ForeignKeyTest; + $fkCust->name = "name"; + $fkCust->cart = null; + + $this->_em->persist($fkCust); + $this->_em->flush(); + $this->_em->clear(); + + $newCust = $this->_em->find(get_class($fkCust), $fkCust->id); + } +} + +/** @Entity */ +class DDC522Customer { + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @Column */ + public $name; + /** @OneToOne(targetEntity="DDC522Cart", mappedBy="customer") */ + public $cart; +} + +/** @Entity */ +class DDC522Cart { + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @Column(type="integer") */ + public $total; + /** + * @OneToOne(targetEntity="DDC522Customer", inversedBy="cart") + * @JoinColumn(name="customer", referencedColumnName="id") + */ + public $customer; +} + +/** @Entity */ +class DDC522ForeignKeyTest { + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + /** @Column(type="integer", name="cart_id", nullable=true) */ + public $cartId; + /** + * @OneToOne(targetEntity="DDC522Cart") + * @JoinColumn(name="cart_id", referencedColumnName="id") + */ + public $cart; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC531Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC531Test.php new file mode 100644 index 0000000..5e22c2c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC531Test.php @@ -0,0 +1,88 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC531Item'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC531SubItem'), + )); + } + + public function testIssue() + { + $item1 = new DDC531Item; + $item2 = new DDC531Item; + $item2->parent = $item1; + $item1->getChildren()->add($item2); + $this->_em->persist($item1); + $this->_em->persist($item2); + $this->_em->flush(); + $this->_em->clear(); + + $item3 = $this->_em->find(__NAMESPACE__ . '\DDC531Item', $item2->id); // Load child item first (id 2) + // parent will already be loaded, cannot be lazy because it has mapped subclasses and we would not + // know which proxy type to put in. + $this->assertInstanceOf(__NAMESPACE__ . '\DDC531Item', $item3->parent); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $item3->parent); + $item4 = $this->_em->find(__NAMESPACE__ . '\DDC531Item', $item1->id); // Load parent item (id 1) + $this->assertNull($item4->parent); + $this->assertNotNull($item4->getChildren()); + $this->assertTrue($item4->getChildren()->contains($item3)); // lazy-loads children + } +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorColumn(name="type", type="integer") + * @DiscriminatorMap({"0" = "DDC531Item", "1" = "DDC531SubItem"}) + */ +class DDC531Item +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @OneToMany(targetEntity="DDC531Item", mappedBy="parent") + */ + protected $children; + + /** + * @ManyToOne(targetEntity="DDC531Item", inversedBy="children") + * @JoinColumn(name="parentId", referencedColumnName="id") + */ + public $parent; + + public function __construct() + { + $this->children = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function getParent() + { + return $this->parent; + } + + public function getChildren() + { + return $this->children; + } +} + +/** + * @Entity + */ +class DDC531SubItem extends DDC531Item +{ +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC588Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC588Test.php new file mode 100644 index 0000000..3f899d7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC588Test.php @@ -0,0 +1,48 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC588Site'), + )); + } + + public function testIssue() + { + $site = new DDC588Site('Foo'); + + $this->_em->persist($site); + $this->_em->flush(); + // Following should not result in exception + $this->_em->refresh($site); + } +} + +/** + * @Entity + */ +class DDC588Site +{ + /** + * @Id + * @Column(type="integer", name="site_id") + * @GeneratedValue + */ + public $id; + + /** + * @Column(type="string", length=45) + */ + protected $name = null; + + public function __construct($name = '') + { + $this->name = $name; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC599Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC599Test.php new file mode 100644 index 0000000..b342796 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC599Test.php @@ -0,0 +1,132 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + try { + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC599Item'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC599Subitem'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC599Child'), + )); + } catch (\Exception $ignored) {} + } + + public function testCascadeRemoveOnInheritanceHierachy() + { + $item = new DDC599Subitem; + $item->elem = "foo"; + $child = new DDC599Child; + $child->parent = $item; + $item->getChildren()->add($child); + $this->_em->persist($item); + $this->_em->persist($child); + $this->_em->flush(); + $this->_em->clear(); + + $item = $this->_em->find(__NAMESPACE__ . '\DDC599Item', $item->id); + + $this->_em->remove($item); + $this->_em->flush(); // Should not fail + + $this->assertFalse($this->_em->contains($item)); + $children = $item->getChildren(); + $this->assertFalse($this->_em->contains($children[0])); + + $this->_em->clear(); + + + $item2 = new DDC599Subitem; + $item2->elem = "bar"; + $this->_em->persist($item2); + $this->_em->flush(); + + $child2 = new DDC599Child; + $child2->parent = $item2; + $item2->getChildren()->add($child2); + $this->_em->persist($child2); + $this->_em->flush(); + + $this->_em->remove($item2); + $this->_em->flush(); // should not fail + + $this->assertFalse($this->_em->contains($item)); + $children = $item->getChildren(); + $this->assertFalse($this->_em->contains($children[0])); + } + + public function testCascadeRemoveOnChildren() + { + $class = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC599Subitem'); + + $this->assertArrayHasKey('children', $class->associationMappings); + $this->assertTrue($class->associationMappings['children']['isCascadeRemove']); + } +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorColumn(name="type", type="integer") + * @DiscriminatorMap({"0" = "DDC599Item", "1" = "DDC599Subitem"}) + */ +class DDC599Item +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @OneToMany(targetEntity="DDC599Child", mappedBy="parent", cascade={"remove"}) + */ + protected $children; + + public function __construct() + { + $this->children = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function getChildren() + { + return $this->children; + } +} + +/** + * @Entity + */ +class DDC599Subitem extends DDC599Item +{ + /** + * @Column(type="string") + */ + public $elem; +} + +/** + * @Entity + */ +class DDC599Child +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; + + /** + * @ManyToOne(targetEntity="DDC599Item", inversedBy="children") + * @JoinColumn(name="parentId", referencedColumnName="id") + */ + public $parent; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC618Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC618Test.php new file mode 100644 index 0000000..b51ed39 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC618Test.php @@ -0,0 +1,185 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC618Author'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC618Book') + )); + + // Create author 10/Joe with two books 22/JoeA and 20/JoeB + $author = new DDC618Author(); + $author->id = 10; + $author->name = 'Joe'; + $this->_em->persist($author); + + // Create author 11/Alice with two books 21/AliceA and 23/AliceB + $author = new DDC618Author(); + $author->id = 11; + $author->name = 'Alice'; + $author->addBook('In Wonderland'); + $author->addBook('Reloaded'); + $author->addBook('Test'); + + $this->_em->persist($author); + + $this->_em->flush(); + $this->_em->clear(); + } catch(\Exception $e) { + + } + } + + public function testIndexByHydrateObject() + { + $dql = 'SELECT A FROM Doctrine\Tests\ORM\Functional\Ticket\DDC618Author A INDEX BY A.name ORDER BY A.name ASC'; + $result = $this->_em->createQuery($dql)->getResult(\Doctrine\ORM\Query::HYDRATE_OBJECT); + + $joe = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC618Author', 10); + $alice = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC618Author', 11); + + $this->assertArrayHasKey('Joe', $result, "INDEX BY A.name should return an index by the name of 'Joe'."); + $this->assertArrayHasKey('Alice', $result, "INDEX BY A.name should return an index by the name of 'Alice'."); + } + + public function testIndexByHydrateArray() + { + $dql = 'SELECT A FROM Doctrine\Tests\ORM\Functional\Ticket\DDC618Author A INDEX BY A.name ORDER BY A.name ASC'; + $result = $this->_em->createQuery($dql)->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY); + + $joe = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC618Author', 10); + $alice = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC618Author', 11); + + $this->assertArrayHasKey('Joe', $result, "INDEX BY A.name should return an index by the name of 'Joe'."); + $this->assertArrayHasKey('Alice', $result, "INDEX BY A.name should return an index by the name of 'Alice'."); + } + + /** + * @group DDC-1018 + */ + public function testIndexByJoin() + { + $dql = 'SELECT A, B FROM Doctrine\Tests\ORM\Functional\Ticket\DDC618Author A '. + 'INNER JOIN A.books B INDEX BY B.title ORDER BY A.name ASC'; + $result = $this->_em->createQuery($dql)->getResult(\Doctrine\ORM\Query::HYDRATE_OBJECT); + + $this->assertEquals(3, count($result[0]->books)); // Alice, Joe doesnt appear because he has no books. + $this->assertEquals('Alice', $result[0]->name); + $this->assertTrue( isset($result[0]->books["In Wonderland"] ), "Indexing by title should have books by title."); + $this->assertTrue( isset($result[0]->books["Reloaded"] ), "Indexing by title should have books by title."); + $this->assertTrue( isset($result[0]->books["Test"] ), "Indexing by title should have books by title."); + + $result = $this->_em->createQuery($dql)->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY); + + $this->assertEquals(3, count($result[0]['books'])); // Alice, Joe doesnt appear because he has no books. + $this->assertEquals('Alice', $result[0]['name']); + $this->assertTrue( isset($result[0]['books']["In Wonderland"] ), "Indexing by title should have books by title."); + $this->assertTrue( isset($result[0]['books']["Reloaded"] ), "Indexing by title should have books by title."); + $this->assertTrue( isset($result[0]['books']["Test"] ), "Indexing by title should have books by title."); + } + + /** + * @group DDC-1018 + */ + public function testIndexByToOneJoinSilentlyIgnored() + { + $dql = 'SELECT B, A FROM Doctrine\Tests\ORM\Functional\Ticket\DDC618Book B '. + 'INNER JOIN B.author A INDEX BY A.name ORDER BY A.name ASC'; + $result = $this->_em->createQuery($dql)->getResult(\Doctrine\ORM\Query::HYDRATE_OBJECT); + + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC618Book', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC618Author', $result[0]->author); + + $dql = 'SELECT B, A FROM Doctrine\Tests\ORM\Functional\Ticket\DDC618Book B '. + 'INNER JOIN B.author A INDEX BY A.name ORDER BY A.name ASC'; + $result = $this->_em->createQuery($dql)->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY); + + $this->assertEquals("Alice", $result[0]['author']['name']); + } + + /** + * @group DDC-1018 + */ + public function testCombineIndexBy() + { + $dql = 'SELECT A, B FROM Doctrine\Tests\ORM\Functional\Ticket\DDC618Author A INDEX BY A.id '. + 'INNER JOIN A.books B INDEX BY B.title ORDER BY A.name ASC'; + $result = $this->_em->createQuery($dql)->getResult(\Doctrine\ORM\Query::HYDRATE_OBJECT); + + $this->assertArrayHasKey(11, $result); // Alice + + $this->assertEquals(3, count($result[11]->books)); // Alice, Joe doesnt appear because he has no books. + $this->assertEquals('Alice', $result[11]->name); + $this->assertTrue( isset($result[11]->books["In Wonderland"] ), "Indexing by title should have books by title."); + $this->assertTrue( isset($result[11]->books["Reloaded"] ), "Indexing by title should have books by title."); + $this->assertTrue( isset($result[11]->books["Test"] ), "Indexing by title should have books by title."); + } +} + +/** + * @Entity + */ +class DDC618Author +{ + /** + * @Id + * @Column(type="integer") + */ + public $id; + + /** @Column(type="string") */ + public $name; + + /** + * @OneToMany(targetEntity="DDC618Book", mappedBy="author", cascade={"persist"}) + */ + public $books; + + public function __construct() + { + $this->books = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function addBook($title) + { + $book = new DDC618Book($title, $this); + $this->books[] = $book; + } +} + +/** + * @Entity + */ +class DDC618Book +{ + /** + * @Id @GeneratedValue + * @Column(type="integer") + */ + public $id; + + /** @column(type="string") */ + public $title; + + /** @ManyToOne(targetEntity="DDC618Author", inversedBy="books") */ + public $author; + + function __construct($title, $author) + { + $this->title = $title; + $this->author = $author; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC633Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC633Test.php new file mode 100644 index 0000000..2ec4383 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC633Test.php @@ -0,0 +1,102 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC633Patient'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC633Appointment'), + )); + } catch(\Exception $e) { + + } + } + + /** + * @group DDC-633 + * @group DDC-952 + * @group DDC-914 + */ + public function testOneToOneEager() + { + $app = new DDC633Appointment(); + $pat = new DDC633Patient(); + $app->patient = $pat; + $pat->appointment = $app; + + $this->_em->persist($app); + $this->_em->persist($pat); + $this->_em->flush(); + $this->_em->clear(); + + $eagerAppointment = $this->_em->find(__NAMESPACE__ . '\DDC633Appointment', $app->id); + + // Eager loading of one to one leads to fetch-join + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $eagerAppointment->patient); + $this->assertTrue($this->_em->contains($eagerAppointment->patient)); + } + + /** + * @group DDC-633 + * @group DDC-952 + */ + public function testDQLDeferredEagerLoad() + { + for ($i = 0; $i < 10; $i++) { + $app = new DDC633Appointment(); + $pat = new DDC633Patient(); + $app->patient = $pat; + $pat->appointment = $app; + + $this->_em->persist($app); + $this->_em->persist($pat); + } + $this->_em->flush(); + $this->_em->clear(); + + $appointments = $this->_em->createQuery("SELECT a FROM " . __NAMESPACE__ . "\DDC633Appointment a")->getResult(); + + foreach ($appointments AS $eagerAppointment) { + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $eagerAppointment->patient); + $this->assertTrue($eagerAppointment->patient->__isInitialized__, "Proxy should already be initialized due to eager loading!"); + } + } +} + +/** + * @Entity + */ +class DDC633Appointment +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + + /** + * @OneToOne(targetEntity="DDC633Patient", inversedBy="appointment", fetch="EAGER") + */ + public $patient; + +} + +/** + * @Entity + */ +class DDC633Patient +{ + /** @Id @Column(type="integer") @GeneratedValue */ + public $id; + + /** + * @OneToOne(targetEntity="DDC633Appointment", mappedBy="patient") + */ + public $appointment; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC656Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC656Test.php new file mode 100644 index 0000000..f2bbc2a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC656Test.php @@ -0,0 +1,82 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC656Entity') + )); + } catch(\Exception $e) { + + } + } + + public function testRecomputeSingleEntityChangeSet_PreservesFieldOrder() + { + $entity = new DDC656Entity(); + $entity->setName('test1'); + $entity->setType('type1'); + $this->_em->persist($entity); + + $this->_em->getUnitOfWork()->computeChangeSet($this->_em->getClassMetadata(get_class($entity)), $entity); + $data1 = $this->_em->getUnitOfWork()->getEntityChangeset($entity); + $entity->setType('type2'); + $this->_em->getUnitOfWork()->recomputeSingleEntityChangeSet($this->_em->getClassMetadata(get_class($entity)), $entity); + $data2 = $this->_em->getUnitOfWork()->getEntityChangeset($entity); + + $this->assertEquals(array_keys($data1), array_keys($data2)); + + $this->_em->flush(); + $this->_em->clear(); + + $persistedEntity = $this->_em->find(get_class($entity), $entity->specificationId); + $this->assertEquals('type2', $persistedEntity->getType()); + $this->assertEquals('test1', $persistedEntity->getName()); + } +} + +/** + * @Entity + */ +class DDC656Entity +{ + /** + * @Column(type="string") + */ + public $name; + + /** + * @Column(type="string") + */ + public $type; + + /** + * @Id @Column(type="integer") @GeneratedValue + */ + public $specificationId; + + public function getName() { + return $this->name; + } + + public function setName($name) { + $this->name = $name; + } + + public function getType() { + return $this->type; + } + + public function setType($type) { + $this->type = $type; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC657Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC657Test.php new file mode 100644 index 0000000..2d4279b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC657Test.php @@ -0,0 +1,120 @@ +useModelSet('generic'); + parent::setUp(); + + $this->loadFixtures(); + } + + public function testEntitySingleResult() + { + $query = $this->_em->createQuery('SELECT d FROM ' . self::NS . '\DateTimeModel d'); + $datetime = $query->setMaxResults(1)->getSingleResult(); + + $this->assertInstanceOf('Doctrine\Tests\Models\Generic\DateTimeModel', $datetime); + + $this->assertInstanceOf('DateTime', $datetime->datetime); + $this->assertInstanceOf('DateTime', $datetime->time); + $this->assertInstanceOf('DateTime', $datetime->date); + } + + public function testScalarResult() + { + $query = $this->_em->createQuery('SELECT d.id, d.time, d.date, d.datetime FROM ' . self::NS . '\DateTimeModel d ORDER BY d.date ASC'); + $result = $query->getScalarResult(); + + $this->assertCount(2,$result); + + $this->assertContains('11:11:11', $result[0]['time']); + $this->assertContains('2010-01-01', $result[0]['date']); + $this->assertContains('2010-01-01 11:11:11', $result[0]['datetime']); + + $this->assertContains('12:12:12', $result[1]['time']); + $this->assertContains('2010-02-02', $result[1]['date']); + $this->assertContains('2010-02-02 12:12:12', $result[1]['datetime']); + } + + public function testaTicketEntityArrayResult() + { + $query = $this->_em->createQuery('SELECT d FROM ' . self::NS . '\DateTimeModel d ORDER BY d.date ASC'); + $result = $query->getArrayResult(); + + $this->assertCount(2,$result); + + $this->assertInstanceOf('DateTime', $result[0]['datetime']); + $this->assertInstanceOf('DateTime', $result[0]['time']); + $this->assertInstanceOf('DateTime', $result[0]['date']); + + $this->assertInstanceOf('DateTime', $result[1]['datetime']); + $this->assertInstanceOf('DateTime', $result[1]['time']); + $this->assertInstanceOf('DateTime', $result[1]['date']); + } + + public function testTicketSingleResult() + { + $query = $this->_em->createQuery('SELECT d.id, d.time, d.date, d.datetime FROM ' . self::NS . '\DateTimeModel d ORDER BY d.date ASC'); + $datetime = $query->setMaxResults(1)->getSingleResult(); + + $this->assertTrue(is_array($datetime)); + + $this->assertInstanceOf('DateTime', $datetime['datetime']); + $this->assertInstanceOf('DateTime', $datetime['time']); + $this->assertInstanceOf('DateTime', $datetime['date']); + } + + public function testTicketResult() + { + $query = $this->_em->createQuery('SELECT d.id, d.time, d.date, d.datetime FROM ' . self::NS . '\DateTimeModel d ORDER BY d.date ASC'); + $result = $query->getResult(); + + $this->assertCount(2,$result); + + $this->assertInstanceOf('DateTime', $result[0]['time']); + $this->assertInstanceOf('DateTime', $result[0]['date']); + $this->assertInstanceOf('DateTime', $result[0]['datetime']); + + $this->assertEquals('2010-01-01 11:11:11', $result[0]['datetime']->format('Y-m-d G:i:s')); + + $this->assertInstanceOf('DateTime', $result[1]['time']); + $this->assertInstanceOf('DateTime', $result[1]['date']); + $this->assertInstanceOf('DateTime', $result[1]['datetime']); + + $this->assertEquals('2010-02-02 12:12:12', $result[1]['datetime']->format('Y-m-d G:i:s')); + } + + public function loadFixtures() + { + $timezone = new \DateTimeZone('America/Sao_Paulo'); + + $dateTime1 = new DateTimeModel(); + $dateTime2 = new DateTimeModel(); + + $dateTime1->date = new \DateTime('2010-01-01', $timezone); + $dateTime1->time = new \DateTime('2010-01-01 11:11:11', $timezone); + $dateTime1->datetime= new \DateTime('2010-01-01 11:11:11', $timezone); + + $dateTime2->date = new \DateTime('2010-02-02', $timezone); + $dateTime2->time = new \DateTime('2010-02-02 12:12:12', $timezone); + $dateTime2->datetime= new \DateTime('2010-02-02 12:12:12', $timezone); + + $this->_em->persist($dateTime1); + $this->_em->persist($dateTime2); + + $this->_em->flush(); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC698Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC698Test.php new file mode 100644 index 0000000..4786cc1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC698Test.php @@ -0,0 +1,107 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC698Role'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC698Privilege') + )); + } catch(\Exception $e) { + + } + } + + public function testTicket() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('p', 'r') + ->from(__NAMESPACE__ . '\DDC698Privilege', 'p') + ->leftJoin('p.roles', 'r'); + + $sql = $qb->getQuery()->getSQL(); + + $this->assertEquals( + strtolower('SELECT p0_.privilegeID AS privilegeID0, p0_.name AS name1, r1_.roleID AS roleID2, r1_.name AS name3, r1_.shortName AS shortName4 FROM Privileges p0_ LEFT JOIN RolePrivileges r2_ ON p0_.privilegeID = r2_.privilegeID LEFT JOIN Roles r1_ ON r1_.roleID = r2_.roleID'), + strtolower($sql) + ); + } +} + +/** + * + * @Table(name="Roles") + * @Entity + */ +class DDC698Role +{ + /** + * @Id @Column(name="roleID", type="integer") + * @GeneratedValue(strategy="AUTO") + * + */ + protected $roleID; + + /** + * @Column(name="name", type="string", length=45) + * + * + */ + protected $name; + + /** + * @Column(name="shortName", type="string", length=45) + * + * + */ + protected $shortName; + + + + /** + * @ManyToMany(targetEntity="DDC698Privilege", inversedBy="roles") + * @JoinTable(name="RolePrivileges", + * joinColumns={@JoinColumn(name="roleID", referencedColumnName="roleID")}, + * inverseJoinColumns={@JoinColumn(name="privilegeID", referencedColumnName="privilegeID")} + * ) + */ + protected $privilege; + +} + + +/** + * + * @Table(name="Privileges") + * @Entity() + */ +class DDC698Privilege +{ + /** + * @Id @Column(name="privilegeID", type="integer") + * @GeneratedValue(strategy="AUTO") + * + */ + protected $privilegeID; + + /** + * @Column(name="name", type="string", length=45) + * + * + */ + protected $name; + + /** + * @ManyToMany(targetEntity="DDC698Role", mappedBy="privilege") + */ + protected $roles; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php new file mode 100644 index 0000000..6bd18ef --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC719Test.php @@ -0,0 +1,112 @@ +_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC719Group'), + )); + } + + public function testIsEmptySqlGeneration() + { + $q = $this->_em->createQuery('SELECT g, c FROM Doctrine\Tests\ORM\Functional\Ticket\DDC719Group g LEFT JOIN g.children c WHERE g.parents IS EMPTY'); + + $this->assertEquals( + strtolower('SELECT g0_.name AS name0, g0_.description AS description1, g0_.id AS id2, g1_.name AS name3, g1_.description AS description4, g1_.id AS id5 FROM groups g0_ LEFT JOIN groups_groups g2_ ON g0_.id = g2_.parent_id LEFT JOIN groups g1_ ON g1_.id = g2_.child_id WHERE (SELECT COUNT(*) FROM groups_groups g3_ WHERE g3_.child_id = g0_.id) = 0'), + strtolower($q->getSQL()) + ); + } +} + +/** + * @MappedSuperclass + */ +class Entity +{ + /** + * @Id @GeneratedValue + * @Column(type="integer") + */ + protected $id; + + public function getId() { return $this->id; } +} + +/** + * @Entity + * @Table(name="groups") + */ +class DDC719Group extends Entity { + /** @Column(type="string", nullable=false) */ + protected $name; + + /** @Column(type="string", nullable=true) */ + protected $description; + + /** + * @ManyToMany(targetEntity="DDC719Group", inversedBy="parents") + * @JoinTable(name="groups_groups", + * joinColumns={@JoinColumn(name="parent_id", referencedColumnName="id")}, + * inverseJoinColumns={@JoinColumn(name="child_id", referencedColumnName="id")} + * ) + */ + protected $children = NULL; + + /** + * @ManyToMany(targetEntity="DDC719Group", mappedBy="children") + */ + protected $parents = NULL; + + /** + * construct + */ + public function __construct() { + parent::__construct(); + + $this->channels = new ArrayCollection(); + $this->children = new ArrayCollection(); + $this->parents = new ArrayCollection(); + } + + /** + * adds group as new child + * + * @param Group $child + */ + public function addGroup(Group $child) { + if ( ! $this->children->contains($child)) { + $this->children->add($child); + $child->addGroup($this); + } + } + + /** + * adds channel as new child + * + * @param Channel $child + */ + public function addChannel(Channel $child) { + if ( ! $this->channels->contains($child)) { + $this->channels->add($child); + } + } + + /** + * getter & setter + */ + public function getName() { return $this->name; } + public function setName($name) { $this->name = $name; } + public function getDescription() { return $this->description; } + public function setDescription($description) { $this->description = $description; } + public function getChildren() { return $this->children; } + public function getParents() { return $this->parents; } + public function getChannels() { return $this->channels; } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC729Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC729Test.php new file mode 100644 index 0000000..3762497 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC729Test.php @@ -0,0 +1,182 @@ +_em); + $schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC729A'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC729B'), + )); + } catch(\Exception $e) { + + } + } + + public function testMergeManyToMany() + { + $a = new DDC729A(); + $b = new DDC729B(); + $a->related[] = $b; + + $this->_em->persist($a); + $this->_em->persist($b); + $this->_em->flush(); + $this->_em->clear(); + $aId = $a->id; + + $a = new DDC729A(); + $a->id = $aId; + + $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $a->related); + + $a = $this->_em->merge($a); + + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $a->related); + + $this->assertFalse($a->related->isInitialized(), "Collection should not be marked initialized."); + $this->assertFalse($a->related->isDirty(), "Collection should not be marked as dirty."); + + $this->_em->flush(); + $this->_em->clear(); + + $a = $this->_em->find(__NAMESPACE__ . '\DDC729A', $aId); + $this->assertEquals(1, count($a->related)); + } + + public function testUnidirectionalMergeManyToMany() + { + $a = new DDC729A(); + $b1 = new DDC729B(); + $b2 = new DDC729B(); + $a->related[] = $b1; + + $this->_em->persist($a); + $this->_em->persist($b1); + $this->_em->persist($b2); + $this->_em->flush(); + $this->_em->clear(); + $aId = $a->id; + + $a = new DDC729A(); + $a->id = $aId; + + $a = $this->_em->merge($a); + + $a->related->set(0, $this->_em->merge($b1)); + + $a->related->set(1, $this->_em->merge($b2)); + + $this->_em->flush(); + $this->_em->clear(); + + $a = $this->_em->find(__NAMESPACE__ . '\DDC729A', $aId); + $this->assertEquals(2, count($a->related)); + } + + public function testBidirectionalMergeManyToMany() + { + $a = new DDC729A(); + $b1 = new DDC729B(); + $b2 = new DDC729B(); + $a->related[] = $b1; + + $this->_em->persist($a); + $this->_em->persist($b1); + $this->_em->persist($b2); + $this->_em->flush(); + $this->_em->clear(); + $aId = $a->id; + + $a = new DDC729A(); + $a->id = $aId; + + $a = $this->_em->merge($a); + + $a->related->set(0, $this->_em->merge($b1)); + $b1->related->set(0, $a); + + $a->related->set(1, $this->_em->merge($b2)); + $b2->related->set(0, $a); + + $this->_em->flush(); + $this->_em->clear(); + + $a = $this->_em->find(__NAMESPACE__ . '\DDC729A', $aId); + $this->assertEquals(2, count($a->related)); + } + + public function testBidirectionalMultiMergeManyToMany() + { + $a = new DDC729A(); + $b1 = new DDC729B(); + $b2 = new DDC729B(); + $a->related[] = $b1; + + $this->_em->persist($a); + $this->_em->persist($b1); + $this->_em->persist($b2); + $this->_em->flush(); + $this->_em->clear(); + $aId = $a->id; + + $a = new DDC729A(); + $a->id = $aId; + + $a = $this->_em->merge($a); + + $a->related->set(0, $this->_em->merge($b1)); + $b1->related->set(0, $this->_em->merge($a)); + + $a->related->set(1, $this->_em->merge($b2)); + $b2->related->set(0, $this->_em->merge($a)); + + $this->_em->flush(); + $this->_em->clear(); + + $a = $this->_em->find(__NAMESPACE__ . '\DDC729A', $aId); + $this->assertEquals(2, count($a->related)); + } +} + +/** + * @Entity + */ +class DDC729A +{ + /** @Id @GeneratedValue @Column(type="integer") */ + public $id; + + /** @ManyToMany(targetEntity="DDC729B", inversedBy="related") */ + public $related; + + public function __construct() + { + $this->related = new \Doctrine\Common\Collections\ArrayCollection(); + } +} + +/** + * @Entity + */ +class DDC729B +{ + /** @Id @GeneratedValue @Column(type="integer") */ + public $id; + + /** @ManyToMany(targetEntity="DDC729B", mappedBy="related") */ + public $related; + + public function __construct() + { + $this->related = new \Doctrine\Common\Collections\ArrayCollection(); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC735Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC735Test.php new file mode 100644 index 0000000..77ef6e1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC735Test.php @@ -0,0 +1,122 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC735Product'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC735Review') + )); + } catch(\Exception $e) { + + } + } + + public function testRemoveElement_AppliesOrphanRemoval() + { + // Create a product and its first review + $product = new DDC735Product; + $review = new DDC735Review($product); + + // Persist and flush + $this->_em->persist($product); + $this->_em->flush(); + + // Now you see it + $this->assertEquals(1, count($product->getReviews())); + + // Remove the review + $reviewId = $review->getId(); + $product->removeReview($review); + $this->_em->flush(); + + // Now you don't + $this->assertEquals(0, count($product->getReviews()), 'count($reviews) should be 0 after removing its only Review'); + + // Refresh + $this->_em->refresh($product); + + // It should still be 0 + $this->assertEquals(0, count($product->getReviews()), 'count($reviews) should still be 0 after the refresh'); + + // Review should also not be available anymore + $this->assertNull($this->_em->find(__NAMESPACE__.'\DDC735Review', $reviewId)); + } +} + +/** + * @Entity + */ +class DDC735Product +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + protected $id; + + /** + * @OneToMany( + * targetEntity="DDC735Review", + * mappedBy="product", + * cascade={"persist"}, + * orphanRemoval=true + * ) + */ + protected $reviews; + + public function __construct() + { + $this->reviews = new ArrayCollection; + } + + public function getReviews() + { + return $this->reviews; + } + + public function addReview(DDC735Review $review) + { + $this->reviews->add($review); + } + + public function removeReview(DDC735Review $review) + { + $this->reviews->removeElement($review); + } +} + +/** + * @Entity + */ +class DDC735Review +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + protected $id; + + /** + * @ManyToOne(targetEntity="DDC735Product", inversedBy="reviews") + */ + protected $product; + + public function __construct(DDC735Product $product) + { + $this->product = $product; + $product->addReview($this); + } + + public function getId() + { + return $this->id; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC736Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC736Test.php new file mode 100644 index 0000000..2dfeeec --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC736Test.php @@ -0,0 +1,100 @@ +useModelSet('ecommerce'); + parent::setUp(); + } + + /** + * @group DDC-736 + */ + public function testReorderEntityFetchJoinForHydration() + { + $cust = new ECommerceCustomer; + $cust->setName('roman'); + + $cart = new ECommerceCart; + $cart->setPayment('cash'); + $cart->setCustomer($cust); + + $this->_em->persist($cust); + $this->_em->persist($cart); + $this->_em->flush(); + $this->_em->clear(); + + $result = $this->_em->createQuery("select c, c.name, ca, ca.payment from Doctrine\Tests\Models\ECommerce\ECommerceCart ca join ca.customer c") + ->getSingleResult(/*\Doctrine\ORM\Query::HYDRATE_ARRAY*/); + + $cart2 = $result[0]; + unset($result[0]); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCart', $cart2); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $cart2->getCustomer()); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceCustomer', $cart2->getCustomer()); + $this->assertEquals(array('name' => 'roman', 'payment' => 'cash'), $result); + } + + /** + * @group DDC-736 + * @group DDC-925 + * @group DDC-915 + */ + public function testDqlTreeWalkerReordering() + { + $cust = new ECommerceCustomer; + $cust->setName('roman'); + + $cart = new ECommerceCart; + $cart->setPayment('cash'); + $cart->setCustomer($cust); + + $this->_em->persist($cust); + $this->_em->persist($cart); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "select c, c.name, ca, ca.payment from Doctrine\Tests\Models\ECommerce\ECommerceCart ca join ca.customer c"; + $result = $this->_em->createQuery($dql) + ->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\Tests\ORM\Functional\Ticket\DisableFetchJoinTreeWalker')) + ->getResult(); + + /* @var $cart2 Doctrine\Tests\Models\ECommerce\ECommerceCart */ + $cart2 = $result[0][0]; + $this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $cart2->getCustomer()); + } +} + +class DisableFetchJoinTreeWalker extends \Doctrine\ORM\Query\TreeWalkerAdapter +{ + public function walkSelectStatement(AST\SelectStatement $AST) + { + $this->walkSelectClause($AST->selectClause); + } + + /** + * @param \Doctrine\ORM\Query\AST\SelectClause $selectClause + */ + public function walkSelectClause($selectClause) + { + foreach ($selectClause->selectExpressions AS $key => $selectExpr) { + /* @var $selectExpr \Doctrine\ORM\Query\AST\SelectExpression */ + if ($selectExpr->expression == "c") { + unset($selectClause->selectExpressions[$key]); + break; + } + } + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC742Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC742Test.php new file mode 100644 index 0000000..7e6e200 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC742Test.php @@ -0,0 +1,130 @@ +addServer('localhost'); + $memcache->flush(); + + $cacheDriver = new \Doctrine\Common\Cache\MemcacheCache(); + $cacheDriver->setMemcache($memcache); + + $this->_em->getMetadataFactory()->setCacheDriver($cacheDriver); + } else if (\extension_loaded('apc')) { + $this->_em->getMetadataFactory()->setCacheDriver(new \Doctrine\Common\Cache\ApcCache()); + } + + try { + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC742User'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC742Comment') + )); + } catch(\Exception $e) { + + } + + // make sure classes will be deserialized from caches + $this->_em->getMetadataFactory()->setMetadataFor(__NAMESPACE__ . '\DDC742User', null); + $this->_em->getMetadataFactory()->setMetadataFor(__NAMESPACE__ . '\DDC742Comment', null); + } + + public function testIssue() + { + $user = new DDC742User(); + $user->title = "Foo"; + $user->favoriteComments = new ArrayCollection(); + + $comment1 = new DDC742Comment(); + $comment1->content = "foo"; + + $comment2 = new DDC742Comment(); + $comment2->content = "bar"; + + $comment3 = new DDC742Comment(); + $comment3->content = "baz"; + + $user->favoriteComments->add($comment1); + $user->favoriteComments->add($comment2); + + $this->_em->persist($user); + $this->_em->persist($comment1); + $this->_em->persist($comment2); + $this->_em->persist($comment3); + $this->_em->flush(); + $this->_em->clear(); + + $user = $this->_em->find(get_class($user), $user->id); + $comment3 = $this->_em->find(get_class($comment3), $comment3->id); + $user->favoriteComments->add($comment3); + $this->_em->flush(); + } +} + +/** + * @Entity + * @Table(name="users") + */ +class DDC742User +{ + /** + * User Id + * + * @Id + * @GeneratedValue(strategy="AUTO") + * @Column(type="integer") + * @var integer + */ + public $id; + /** + * @Column(length=100, type="string") + * @var string + */ + public $title; + /** + * @ManyToMany(targetEntity="DDC742Comment", cascade={"persist"}, fetch="EAGER") + * @JoinTable( + * name="user_comments", + * joinColumns={@JoinColumn(name="user_id",referencedColumnName="id")}, + * inverseJoinColumns={@JoinColumn(name="comment_id", referencedColumnName="id")} + * ) + * + * @var Doctrine\ORM\PersistentCollection + */ + public $favoriteComments; +} + +/** + * @Entity + * @Table(name="comments") + */ +class DDC742Comment +{ + /** + * User Id + * + * @Id + * @GeneratedValue(strategy="AUTO") + * @Column(type="integer") + * @var integer + */ + public $id; + /** + * @Column(length=100, type="string") + * @var string + */ + public $content; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC748Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC748Test.php new file mode 100644 index 0000000..9954a69 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC748Test.php @@ -0,0 +1,64 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testRefreshWithManyToOne() + { + $user = new CmsUser(); + $user->name = "beberlei"; + $user->status = "active"; + $user->username = "beberlei"; + + $article = new CmsArticle(); + $article->setAuthor($user); + $article->text = "foo"; + $article->topic = "bar"; + + $this->_em->persist($user); + $this->_em->persist($article); + $this->_em->flush(); + + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $user->articles); + $this->_em->refresh($article); + $this->assertTrue($article !== $user->articles, "The article should not be replaced on the inverse side of the relation."); + $this->assertInstanceOf('Doctrine\Common\Collections\Collection', $user->articles); + } + + public function testRefreshOneToOne() + { + $user = new CmsUser(); + $user->name = "beberlei"; + $user->status = "active"; + $user->username = "beberlei"; + + $address = new CmsAddress(); + $address->city = "Bonn"; + $address->country = "Germany"; + $address->street = "A street"; + $address->zip = 12345; + $address->setUser($user); + + $this->_em->persist($user); + $this->_em->persist($address); + $this->_em->flush(); + + $this->_em->refresh($address); + $this->assertSame($user, $address->user); + $this->assertSame($user->address, $address); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC758Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC758Test.php new file mode 100644 index 0000000..76bb3bb --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC758Test.php @@ -0,0 +1,185 @@ +markTestSkipped('Destroys testsuite'); + $this->useModelSet("cms"); + + parent::setUp(); + } + + /** + * Helper method to set cascade to merge only + */ + private function setCascadeMergeFor($class) + { + $metadata = $this->_em->getMetadataFactory()->getMetaDataFor($class); + foreach ($metadata->associationMappings as $key => $associationMapping) { + $metadata->associationMappings[$key]["isCascadePersist"] = false; + $metadata->associationMappings[$key]["isCascadeMerge"] = true; + $metadata->associationMappings[$key]["isCascadeRemove"] = false; + $metadata->associationMappings[$key]["isCascadeDetach"] = false; + } + } + + /** + * Test that changing associations on detached entities and then cascade merging them + * causes the database to be updated with the new associations. + * This specifically tests adding new associations. + */ + public function testManyToManyMergeAssociationAdds() + { + $this->setCascadeMergeFor('Doctrine\Tests\Models\CMS\CmsUser'); + $this->setCascadeMergeFor('Doctrine\Tests\Models\CMS\CmsGroup'); + + // Put entities in the database + $cmsUser = new CmsUser(); + $cmsUser->username = "dave"; + $cmsUser->name = "Dave Keen"; + $cmsUser->status = "testing"; + + $group1 = new CmsGroup(); + $group1->name = "Group 1"; + + $group2 = new CmsGroup(); + $group2->name = "Group 2"; + + $this->_em->persist($cmsUser); + $this->_em->persist($group1); + $this->_em->persist($group2); + $this->_em->flush(); + + $cmsUserId = $cmsUser->id; + $group1Id = $group1->id; + $group2Id = $group2->id; + + $this->_em->clear(); + + // Now create detached versions of the entities with some new associations. + $cmsUser = new CmsUser(); + $cmsUser->id = $cmsUserId; + $cmsUser->username = "dave"; + $cmsUser->name = "Dave Keen"; + $cmsUser->status = "testing"; + $cmsUser->groups = new ArrayCollection(); + + $group1 = new CmsGroup(); + $group1->id = $group1Id; + $group1->name = "Group 1"; + $group1->users = new ArrayCollection(); + + $group2 = new CmsGroup(); + $group2->id = $group2Id; + $group2->name = "Group 2"; + $group2->users = new ArrayCollection(); + + $cmsUser->addGroup($group1); + $cmsUser->addGroup($group2); + + // Cascade merge of cmsUser followed by a flush should add in the birectional new many-to-many associations between the user and the groups + $this->_em->merge($cmsUser); + $this->_em->flush(); + + $this->_em->clear(); + + $cmsUsers = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->findAll(); + $cmsGroups = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll(); + + // Check the entities are in the database + $this->assertEquals(1, sizeof($cmsUsers)); + $this->assertEquals(2, sizeof($cmsGroups)); + + // Check the associations between the entities are now in the database + $this->assertEquals(2, sizeof($cmsUsers[0]->groups)); + $this->assertEquals(1, sizeof($cmsGroups[0]->users)); + $this->assertEquals(1, sizeof($cmsGroups[1]->users)); + + $this->assertSame($cmsUsers[0]->groups[0], $cmsGroups[0]); + $this->assertSame($cmsUsers[0]->groups[1], $cmsGroups[1]); + $this->assertSame($cmsGroups[0]->users[0], $cmsUsers[0]); + $this->assertSame($cmsGroups[1]->users[0], $cmsUsers[0]); + } + + /** + * Test that changing associations on detached entities and then cascade merging them causes the + * database to be updated with the new associations. + */ + public function testManyToManyMergeAssociationRemoves() + { + $this->setCascadeMergeFor('Doctrine\Tests\Models\CMS\CmsUser'); + $this->setCascadeMergeFor('Doctrine\Tests\Models\CMS\CmsGroup'); + + $cmsUser = new CmsUser(); + $cmsUser->username = "dave"; + $cmsUser->name = "Dave Keen"; + $cmsUser->status = "testing"; + + $group1 = new CmsGroup(); + $group1->name = "Group 1"; + + $group2 = new CmsGroup(); + $group2->name = "Group 2"; + + $cmsUser->addGroup($group1); + $cmsUser->addGroup($group2); + + $this->_em->persist($cmsUser); + $this->_em->persist($group1); + $this->_em->persist($group2); + $this->_em->flush(); + + $cmsUserId = $cmsUser->id; + $group1Id = $group1->id; + $group2Id = $group2->id; + + $this->_em->clear(); + + // Now create detached versions of the entities with NO associations. + $cmsUser = new CmsUser(); + $cmsUser->id = $cmsUserId; + $cmsUser->username = "dave"; + $cmsUser->name = "Dave Keen"; + $cmsUser->status = "testing"; + $cmsUser->groups = new ArrayCollection(); + + $group1 = new CmsGroup(); + $group1->id = $group1Id; + $group1->name = "Group 1"; + $group1->users = new ArrayCollection(); + + $group2 = new CmsGroup(); + $group2->id = $group2Id; + $group2->name = "Group 2"; + $group2->users = new ArrayCollection(); + + // Cascade merge of cmsUser followed by a flush should result in the association array collection being empty + $this->_em->merge($cmsUser); + $this->_em->flush(); + + $this->_em->clear(); + + $cmsUsers = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->findAll(); + $cmsGroups = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll(); + + // Check the entities are in the database + $this->assertEquals(1, sizeof($cmsUsers)); + $this->assertEquals(2, sizeof($cmsGroups)); + + // Check the associations between the entities are now in the database + $this->assertEquals(0, sizeof($cmsUsers[0]->groups)); + $this->assertEquals(0, sizeof($cmsGroups[0]->users)); + $this->assertEquals(0, sizeof($cmsGroups[1]->users)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC767Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC767Test.php new file mode 100644 index 0000000..7ba337e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC767Test.php @@ -0,0 +1,74 @@ +useModelSet('cms'); + parent::setUp(); + } + + /** + * @group DDC-767 + */ + public function testCollectionChangesInsideTransaction() + { + $user = new CmsUser(); + $user->name = "beberlei"; + $user->status = "active"; + $user->username = "beberlei"; + + $group1 = new CmsGroup(); + $group1->name = "foo"; + + $group2 = new CmsGroup(); + $group2->name = "bar"; + + $group3 = new CmsGroup(); + $group3->name = "baz"; + + $user->addGroup($group1); + $user->addGroup($group2); + + $this->_em->persist($user); + $this->_em->persist($group1); + $this->_em->persist($group2); + $this->_em->persist($group3); + + $this->_em->flush(); + $this->_em->clear(); + + /* @var $pUser CmsUser */ + $pUser = $this->_em->find(get_class($user), $user->id); + + $this->assertNotNull($pUser, "User not retrieved from database."); + + $groups = array(2, 3); + + try { + $this->_em->beginTransaction(); + + $pUser->groups->clear(); + + $this->_em->flush(); + + // Add new + foreach ($groups as $groupId) { + $pUser->addGroup($this->_em->find(get_class($group1), $groupId)); + } + + $this->_em->flush(); + $this->_em->commit(); + } catch(\Exception $e) { + $this->_em->rollback(); + } + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC809Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC809Test.php new file mode 100644 index 0000000..c586afa --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC809Test.php @@ -0,0 +1,109 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC809Variant'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC809SpecificationValue') + )); + + $conn = $this->_em->getConnection(); + $conn->insert('specification_value_test', array('specification_value_id' => 94589)); + $conn->insert('specification_value_test', array('specification_value_id' => 94593)); + $conn->insert('specification_value_test', array('specification_value_id' => 94606)); + $conn->insert('specification_value_test', array('specification_value_id' => 94607)); + $conn->insert('specification_value_test', array('specification_value_id' => 94609)); + $conn->insert('specification_value_test', array('specification_value_id' => 94711)); + + $conn->insert('variant_test', array('variant_id' => 545208)); + $conn->insert('variant_test', array('variant_id' => 545209)); + + $conn->insert('var_spec_value_test', array('variant_id' => 545208, 'specification_value_id' => 94606)); + $conn->insert('var_spec_value_test', array('variant_id' => 545208, 'specification_value_id' => 94607)); + $conn->insert('var_spec_value_test', array('variant_id' => 545208, 'specification_value_id' => 94609)); + $conn->insert('var_spec_value_test', array('variant_id' => 545208, 'specification_value_id' => 94711)); + + $conn->insert('var_spec_value_test', array('variant_id' => 545209, 'specification_value_id' => 94589)); + $conn->insert('var_spec_value_test', array('variant_id' => 545209, 'specification_value_id' => 94593)); + $conn->insert('var_spec_value_test', array('variant_id' => 545209, 'specification_value_id' => 94606)); + $conn->insert('var_spec_value_test', array('variant_id' => 545209, 'specification_value_id' => 94607)); + } + + /** + * @group DDC-809 + */ + public function testIssue() + { + $result = $this->_em->createQueryBuilder() + ->select('Variant, SpecificationValue') + ->from('Doctrine\Tests\ORM\Functional\Ticket\DDC809Variant', 'Variant') + ->leftJoin('Variant.SpecificationValues', 'SpecificationValue') + ->getQuery() + ->getResult(); + + $this->assertEquals(4, count($result[0]->getSpecificationValues()), "Works in test-setup."); + $this->assertEquals(4, count($result[1]->getSpecificationValues()), "Only returns 2 in the case of the hydration bug."); + } +} + +/** + * @Table(name="variant_test") + * @Entity + */ +class DDC809Variant +{ + /** + * @Column(name="variant_id", type="integer") + * @Id + */ + protected $variantId; + + /** + * @ManyToMany(targetEntity="DDC809SpecificationValue", inversedBy="Variants") + * @JoinTable(name="var_spec_value_test", + * joinColumns={ + * @JoinColumn(name="variant_id", referencedColumnName="variant_id") + * }, + * inverseJoinColumns={ + * @JoinColumn(name="specification_value_id", referencedColumnName="specification_value_id") + * } + * ) + */ + protected $SpecificationValues; + + public function getSpecificationValues() + { + return $this->SpecificationValues; + } +} + +/** + * @Table(name="specification_value_test") + * @Entity + */ +class DDC809SpecificationValue +{ + /** + * @Column(name="specification_value_id", type="integer") + * @Id + */ + protected $specificationValueId; + + /** + * @var Variant + * + * @ManyToMany(targetEntity="DDC809Variant", mappedBy="SpecificationValues") + */ + protected $Variants; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC812Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC812Test.php new file mode 100644 index 0000000..4a80358 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC812Test.php @@ -0,0 +1,48 @@ +useModelSet('cms'); + parent::setUp(); + } + + /** + * @group DDC-812 + */ + public function testFetchJoinInitializesPreviouslyUninitializedCollectionOfManagedEntity() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + $article = new CmsArticle; + $article->topic = "hello"; + $article->text = "talk talk talk"; + + $comment = new CmsComment; + $comment->topic = "good!"; + $comment->text = "stuff!"; + $comment->article = $article; + + $this->_em->persist($article); + $this->_em->persist($comment); + $this->_em->flush(); + $this->_em->clear(); + + $article2 = $this->_em->find(get_class($article), $article->id); + + $article2Again = $this->_em->createQuery( + "select a, c from Doctrine\Tests\Models\CMS\CmsArticle a join a.comments c where a.id = ?1") + ->setParameter(1, $article->id) + ->getSingleResult(); + + $this->assertTrue($article2Again === $article2); + $this->assertTrue($article2Again->comments->isInitialized()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC832Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC832Test.php new file mode 100644 index 0000000..599218b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC832Test.php @@ -0,0 +1,194 @@ +_em->getConnection()->getDatabasePlatform(); + if ($platform->getName() == "oracle") { + $this->markTestSkipped('Doesnt run on Oracle.'); + } + + $this->_em->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger()); + try { + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC832JoinedIndex'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC832JoinedTreeIndex'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC832Like'), + )); + } catch(\Exception $e) { + + } + } + + public function tearDown() + { + /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ + $platform = $this->_em->getConnection()->getDatabasePlatform(); + $sm = $this->_em->getConnection()->getSchemaManager(); + $sm->dropTable($platform->quoteIdentifier('TREE_INDEX')); + $sm->dropTable($platform->quoteIdentifier('INDEX')); + $sm->dropTable($platform->quoteIdentifier('LIKE')); + } + + /** + * @group DDC-832 + */ + public function testQuotedTableBasicUpdate() + { + $like = new DDC832Like("test"); + $this->_em->persist($like); + $this->_em->flush(); + + $like->word = "test2"; + $this->_em->flush(); + } + + /** + * @group DDC-832 + */ + public function testQuotedTableBasicRemove() + { + $like = new DDC832Like("test"); + $this->_em->persist($like); + $this->_em->flush(); + + $this->_em->remove($like); + $this->_em->flush(); + } + + /** + * @group DDC-832 + */ + public function testQuotedTableJoinedUpdate() + { + $index = new DDC832JoinedIndex("test"); + $this->_em->persist($index); + $this->_em->flush(); + + $index->name = "asdf"; + $this->_em->flush(); + } + + /** + * @group DDC-832 + */ + public function testQuotedTableJoinedRemove() + { + $index = new DDC832JoinedIndex("test"); + $this->_em->persist($index); + $this->_em->flush(); + + $this->_em->remove($index); + $this->_em->flush(); + } + + /** + * @group DDC-832 + */ + public function testQuotedTableJoinedChildUpdate() + { + $index = new DDC832JoinedTreeIndex("test", 1, 2); + $this->_em->persist($index); + $this->_em->flush(); + + $index->name = "asdf"; + $this->_em->flush(); + } + + /** + * @group DDC-832 + */ + public function testQuotedTableJoinedChildRemove() + { + $index = new DDC832JoinedTreeIndex("test", 1, 2); + $this->_em->persist($index); + $this->_em->flush(); + + $this->_em->remove($index); + $this->_em->flush(); + } +} + +/** + * @Entity + * @Table(name="`LIKE`") + */ +class DDC832Like +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + public $id; + + /** @Column(type="string") */ + public $word; + + /** + * @version + * @Column(type="integer") + */ + public $version; + + public function __construct($word) + { + $this->word = $word; + } +} + +/** + * @Entity + * @Table(name="`INDEX`") + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"like" = "DDC832JoinedIndex", "fuzzy" = "DDC832JoinedTreeIndex"}) + */ +class DDC832JoinedIndex +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + public $id; + + /** @Column(type="string") */ + public $name; + + /** + * @version + * @Column(type="integer") + */ + public $version; + + public function __construct($name) + { + $this->name = $name; + } +} + +/** + * @Entity + * @Table(name="`TREE_INDEX`") + */ +class DDC832JoinedTreeIndex extends DDC832JoinedIndex +{ + /** @Column(type="integer") */ + public $lft; + /** @Column(type="integer") */ + public $rgt; + + public function __construct($name, $lft, $rgt) + { + $this->name = $name; + $this->lft = $lft; + $this->rgt = $rgt; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC837Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC837Test.php new file mode 100644 index 0000000..d44c3af --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC837Test.php @@ -0,0 +1,198 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC837Super'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC837Class1'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC837Class2'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC837Class3'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC837Aggregate'), + )); + } + + /** + * @group DDC-837 + */ + public function testIssue() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $c1 = new DDC837Class1(); + $c1->title = "Foo"; + $c1->description = "Foo"; + $aggregate1 = new DDC837Aggregate('test1'); + $c1->aggregate = $aggregate1; + + $c2 = new DDC837Class2(); + $c2->title = "Bar"; + $c2->description = "Bar"; + $c2->text = "Bar"; + $aggregate2 = new DDC837Aggregate('test2'); + $c2->aggregate = $aggregate2; + + $c3 = new DDC837Class3(); + $c3->apples = "Baz"; + $c3->bananas = "Baz"; + + $this->_em->persist($c1); + $this->_em->persist($aggregate1); + $this->_em->persist($c2); + $this->_em->persist($aggregate2); + $this->_em->persist($c3); + $this->_em->flush(); + $this->_em->clear(); + + // Test Class1 + $e1 = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC837Super', $c1->id); + + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC837Class1', $e1); + $this->assertEquals('Foo', $e1->title); + $this->assertEquals('Foo', $e1->description); + $this->assertInstanceOf(__NAMESPACE__ . '\DDC837Aggregate', $e1->aggregate); + $this->assertEquals('test1', $e1->aggregate->getSysname()); + + // Test Class 2 + $e2 = $this->_em->find('Doctrine\Tests\ORM\Functional\Ticket\DDC837Super', $c2->id); + + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\DDC837Class2', $e2); + $this->assertEquals('Bar', $e2->title); + $this->assertEquals('Bar', $e2->description); + $this->assertEquals('Bar', $e2->text); + $this->assertInstanceOf(__NAMESPACE__ . '\DDC837Aggregate', $e2->aggregate); + $this->assertEquals('test2', $e2->aggregate->getSysname()); + + $all = $this->_em->getRepository(__NAMESPACE__.'\DDC837Super')->findAll(); + + foreach ($all as $obj) { + if ($obj instanceof DDC837Class1) { + $this->assertEquals('Foo', $obj->title); + $this->assertEquals('Foo', $obj->description); + } else if ($obj instanceof DDC837Class2) { + $this->assertTrue($e2 === $obj); + $this->assertEquals('Bar', $obj->title); + $this->assertEquals('Bar', $obj->description); + $this->assertEquals('Bar', $obj->text); + } else if ($obj instanceof DDC837Class3) { + $this->assertEquals('Baz', $obj->apples); + $this->assertEquals('Baz', $obj->bananas); + } else { + $this->fail('Instance of DDC837Class1, DDC837Class2 or DDC837Class3 expected.'); + } + } + } +} + +/** + * @Entity + * @Table(name="DDC837Super") + * @InheritanceType("JOINED") + * @DiscriminatorColumn(name="type", type="string") + * @DiscriminatorMap({"class1" = "DDC837Class1", "class2" = "DDC837Class2", "class3"="DDC837Class3"}) + */ +abstract class DDC837Super +{ + /** + * @Id @Column(name="id", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; +} + +/** + * @Entity + */ +class DDC837Class1 extends DDC837Super +{ + /** + * @Column(name="title", type="string", length=150) + */ + public $title; + + /** + * @Column(name="content", type="string", length=500) + */ + public $description; + + /** + * @OneToOne(targetEntity="DDC837Aggregate") + */ + public $aggregate; +} + +/** + * @Entity + */ +class DDC837Class2 extends DDC837Super +{ + /** + * @Column(name="title", type="string", length=150) + */ + public $title; + + /** + * @Column(name="content", type="string", length=500) + */ + public $description; + + /** + * @Column(name="text", type="text") + */ + public $text; + + /** + * @OneToOne(targetEntity="DDC837Aggregate") + */ + public $aggregate; +} + +/** + * An extra class to demonstrate why title and description aren't in Super + * + * @Entity + */ +class DDC837Class3 extends DDC837Super +{ + /** + * @Column(name="title", type="string", length=150) + */ + public $apples; + + /** + * @Column(name="content", type="string", length=500) + */ + public $bananas; +} + +/** + * @Entity + */ +class DDC837Aggregate +{ + /** + * @Id @Column(name="id", type="integer") + * @GeneratedValue + */ + public $id; + + /** + * @Column(name="sysname", type="string") + */ + protected $sysname; + + public function __construct($sysname) + { + $this->sysname = $sysname; + } + + public function getSysname() + { + return $this->sysname; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC849Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC849Test.php new file mode 100644 index 0000000..b17e605 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC849Test.php @@ -0,0 +1,84 @@ +useModelSet('cms'); + parent::setUp(); + + $this->user = new CmsUser(); + $this->user->username = "beberlei"; + $this->user->name = "Benjamin"; + $this->user->status = "active"; + + $this->group1 = new CmsGroup(); + $this->group1->name = "Group 1"; + $this->group2 = new CmsGroup(); + $this->group2->name = "Group 2"; + + $this->user->addGroup($this->group1); + $this->user->addGroup($this->group2); + + $this->_em->persist($this->user); + $this->_em->persist($this->group1); + $this->_em->persist($this->group2); + + $this->_em->flush(); + $this->_em->clear(); + + $this->user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->user->getId()); + } + + public function testRemoveContains() + { + $group1 = $this->user->groups[0]; + $group2 = $this->user->groups[1]; + + $this->assertTrue($this->user->groups->contains($group1)); + $this->assertTrue($this->user->groups->contains($group2)); + + $this->user->groups->removeElement($group1); + $this->user->groups->remove(1); + + $this->assertFalse($this->user->groups->contains($group1)); + $this->assertFalse($this->user->groups->contains($group2)); + } + + public function testClearCount() + { + $this->user->addGroup(new CmsGroup); + $this->assertEquals(3, count($this->user->groups)); + + $this->user->groups->clear(); + + $this->assertEquals(0, $this->user->groups->count()); + $this->assertEquals(0, count($this->user->groups)); + } + + public function testClearContains() + { + $group1 = $this->user->groups[0]; + $group2 = $this->user->groups[1]; + + $this->assertTrue($this->user->groups->contains($group1)); + $this->assertTrue($this->user->groups->contains($group2)); + + $this->user->groups->clear(); + + $this->assertFalse($this->user->groups->contains($group1)); + $this->assertFalse($this->user->groups->contains($group2)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC881Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC881Test.php new file mode 100644 index 0000000..4ef3c08 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC881Test.php @@ -0,0 +1,215 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC881User'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC881Phonenumber'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC881Phonecall'), + )); + } catch (\Exception $e) { + + } + } + + /** + * @group DDC-117 + * @group DDC-881 + */ + public function testIssue() + { + /* Create two test users: albert and alfons */ + $albert = new DDC881User; + $albert->setName("albert"); + $this->_em->persist($albert); + + $alfons = new DDC881User; + $alfons->setName("alfons"); + $this->_em->persist($alfons); + + $this->_em->flush(); + + /* Assign two phone numbers to each user */ + $phoneAlbert1 = new DDC881PhoneNumber(); + $phoneAlbert1->setUser($albert); + $phoneAlbert1->setId(1); + $phoneAlbert1->setPhoneNumber("albert home: 012345"); + $this->_em->persist($phoneAlbert1); + + $phoneAlbert2 = new DDC881PhoneNumber(); + $phoneAlbert2->setUser($albert); + $phoneAlbert2->setId(2); + $phoneAlbert2->setPhoneNumber("albert mobile: 67890"); + $this->_em->persist($phoneAlbert2); + + $phoneAlfons1 = new DDC881PhoneNumber(); + $phoneAlfons1->setId(1); + $phoneAlfons1->setUser($alfons); + $phoneAlfons1->setPhoneNumber("alfons home: 012345"); + $this->_em->persist($phoneAlfons1); + + $phoneAlfons2 = new DDC881PhoneNumber(); + $phoneAlfons2->setId(2); + $phoneAlfons2->setUser($alfons); + $phoneAlfons2->setPhoneNumber("alfons mobile: 67890"); + $this->_em->persist($phoneAlfons2); + + /* We call alfons and albert once on their mobile numbers */ + $call1 = new DDC881PhoneCall(); + $call1->setPhoneNumber($phoneAlfons2); + $this->_em->persist($call1); + + $call2 = new DDC881PhoneCall(); + $call2->setPhoneNumber($phoneAlbert2); + $this->_em->persist($call2); + + $this->_em->flush(); + $this->_em->clear(); + + // fetch-join that foreign-key/primary-key entity association + $dql = "SELECT c, p FROM " . __NAMESPACE__ . "\DDC881PhoneCall c JOIN c.phonenumber p"; + $calls = $this->_em->createQuery($dql)->getResult(); + + $this->assertEquals(2, count($calls)); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $calls[0]->getPhoneNumber()); + $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $calls[1]->getPhoneNumber()); + + $dql = "SELECT p, c FROM " . __NAMESPACE__ . "\DDC881PhoneNumber p JOIN p.calls c"; + $numbers = $this->_em->createQuery($dql)->getResult(); + + $this->assertEquals(2, count($numbers)); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $numbers[0]->getCalls()); + $this->assertTrue($numbers[0]->getCalls()->isInitialized()); + } + +} + +/** + * @Entity + */ +class DDC881User +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + /** + * @Column(type="string") + */ + private $name; + /** + * @OneToMany(targetEntity="DDC881PhoneNumber",mappedBy="id") + */ + private $phoneNumbers; + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + } +} + +/** + * @Entity + */ +class DDC881PhoneNumber +{ + + /** + * @Id + * @Column(type="integer") + */ + private $id; + /** + * @Id + * @ManyToOne(targetEntity="DDC881User",cascade={"all"}) + */ + private $user; + /** + * @Column(type="string") + */ + private $phonenumber; + + /** + * @OneToMany(targetEntity="DDC881PhoneCall", mappedBy="phonenumber") + */ + private $calls; + + public function __construct() + { + $this->calls = new \Doctrine\Common\Collections\ArrayCollection(); + } + + public function setId($id) + { + $this->id = $id; + } + + public function setUser(DDC881User $user) + { + $this->user = $user; + } + + public function setPhoneNumber($phoneNumber) + { + $this->phonenumber = $phoneNumber; + } + + public function getCalls() + { + return $this->calls; + } +} + +/** + * @Entity + */ +class DDC881PhoneCall +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + /** + * @ManyToOne(targetEntity="DDC881PhoneNumber", inversedBy="calls", cascade={"all"}) + * @JoinColumns({ + * @JoinColumn(name="phonenumber_id", referencedColumnName="id"), + * @JoinColumn(name="user_id", referencedColumnName="user_id") + * }) + */ + private $phonenumber; + /** + * @Column(type="string",nullable=true) + */ + private $callDate; + + public function setPhoneNumber(DDC881PhoneNumber $phoneNumber) + { + $this->phonenumber = $phoneNumber; + } + + public function getPhoneNumber() + { + return $this->phonenumber; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC933Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC933Test.php new file mode 100644 index 0000000..cd2b584 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC933Test.php @@ -0,0 +1,39 @@ +useModelSet('company'); + parent::setUp(); + } + + /** + * @group DDC-933 + */ + public function testLockCTIClass() + { + //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger()); + + $manager = new \Doctrine\Tests\Models\Company\CompanyManager(); + $manager->setName('beberlei'); + $manager->setSalary(1234); + $manager->setTitle('Vice Precident of This Test'); + $manager->setDepartment("Foo"); + + $this->_em->persist($manager); + $this->_em->flush(); + + $this->_em->beginTransaction(); + $this->_em->lock($manager, \Doctrine\DBAL\LockMode::PESSIMISTIC_READ); + $this->_em->rollback(); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC949Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC949Test.php new file mode 100644 index 0000000..a3734b7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC949Test.php @@ -0,0 +1,43 @@ +useModelSet('generic'); + parent::setUp(); + } + + /** + * @group DDC-949 + */ + public function testBooleanThroughRepository() + { + $true = new BooleanModel(); + $true->booleanField = true; + + $false = new BooleanModel(); + $false->booleanField = false; + + $this->_em->persist($true); + $this->_em->persist($false); + $this->_em->flush(); + $this->_em->clear(); + + $true = $this->_em->getRepository('Doctrine\Tests\Models\Generic\BooleanModel')->findOneBy(array('booleanField' => true)); + $false = $this->_em->getRepository('Doctrine\Tests\Models\Generic\BooleanModel')->findOneBy(array('booleanField' => false)); + + $this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $true, "True model not found"); + $this->assertTrue($true->booleanField, "True Boolean Model should be true."); + + $this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $false, "False model not found"); + $this->assertFalse($false->booleanField, "False Boolean Model should be false."); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC960Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC960Test.php new file mode 100644 index 0000000..99a29a5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC960Test.php @@ -0,0 +1,92 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC960Root'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC960Child') + )); + } catch(\Exception $e) { + + } + } + + /** + * @group DDC-960 + */ + public function testUpdateRootVersion() + { + $child = new DDC960Child('Test'); + $this->_em->persist($child); + $this->_em->flush(); + + $child->setName("Test2"); + + $this->_em->flush(); + + $this->assertEquals(2, $child->getVersion()); + } +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorMap({ + * "root" = "DDC960Root", + * "child" = "DDC960Child" + * }) + */ +class DDC960Root +{ + /** + * @Id @GeneratedValue @Column(type="integer") + */ + private $id; + + /** + * @Column(type="integer") @Version + */ + private $version; + + public function getId() + { + return $this->id; + } + + public function getVersion() + { + return $this->version; + } +} + +/** + * @Entity + */ +class DDC960Child extends DDC960Root +{ + /** + * @column(type="string") + * @var string + */ + private $name; + + public function __construct($name) + { + $this->name = $name; + } + + public function setName($name) + { + $this->name = $name; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC992Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC992Test.php new file mode 100644 index 0000000..001e380 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC992Test.php @@ -0,0 +1,147 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC992Role'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC992Parent'), + $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC992Child'), + )); + } catch(\Exception $e) { + + } + } + + public function testIssue() + { + $role = new DDC992Role(); + $role->name = "Parent"; + $child = new DDC992Role(); + $child->name = "child"; + + $role->extendedBy[] = $child; + $child->extends[] = $role; + + $this->_em->persist($role); + $this->_em->persist($child); + $this->_em->flush(); + $this->_em->clear(); + + $child = $this->_em->getRepository(get_class($role))->find($child->roleID); + $parents = count($child->extends); + $this->assertEquals(1, $parents); + foreach ($child->extends AS $parent) { + $this->assertEquals($role->getRoleID(), $parent->getRoleID()); + } + } + + public function testOneToManyChild() + { + $parent = new DDC992Parent(); + $child = new DDC992Child(); + $child->parent = $parent; + $parent->childs[] = $child; + + $this->_em->persist($parent); + $this->_em->persist($child); + $this->_em->flush(); + $this->_em->clear(); + + $parentRepository = $this->_em->getRepository(get_class($parent)); + $childRepository = $this->_em->getRepository(get_class($child)); + + $parent = $parentRepository->find($parent->id); + $this->assertEquals(1, count($parent->childs)); + $this->assertEquals(0, count($parent->childs[0]->childs())); + + $child = $parentRepository->findOneBy(array("id" => $child->id)); + $this->assertSame($parent->childs[0], $child); + + $this->_em->clear(); + + $child = $parentRepository->find($child->id); + $this->assertEquals(0, count($child->childs)); + + $this->_em->clear(); + + $child = $childRepository->find($child->id); + $this->assertEquals(0, count($child->childs)); + } +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorMap({"child" = "DDC992Child", "parent" = "DDC992Parent"}) + */ +class DDC992Parent +{ + /** @Id @GeneratedValue @Column(type="integer") */ + public $id; + /** @ManyToOne(targetEntity="DDC992Parent", inversedBy="childs") */ + public $parent; + /** @OneToMany(targetEntity="DDC992Child", mappedBy="parent") */ + public $childs; +} + +/** + * @Entity + */ +class DDC992Child extends DDC992Parent +{ + public function childs() + { + return $this->childs; + } +} + +/** + * @Entity + */ +class DDC992Role +{ + public function getRoleID() + { + return $this->roleID; + } + + /** + * @Id @Column(name="roleID", type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $roleID; + /** + * @Column (name="name", type="string", length=45) + */ + public $name; + /** + * @ManyToMany (targetEntity="DDC992Role", mappedBy="extends") + */ + public $extendedBy; + /** + * @ManyToMany (targetEntity="DDC992Role", inversedBy="extendedBy") + * @JoinTable (name="RoleRelations", + * joinColumns={@JoinColumn(name="roleID", referencedColumnName="roleID")}, + * inverseJoinColumns={@JoinColumn(name="extendsRoleID", referencedColumnName="roleID")} + * ) + */ + public $extends; + + public function __construct() { + $this->extends = new ArrayCollection; + $this->extendedBy = new ArrayCollection; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket2481Test.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket2481Test.php new file mode 100644 index 0000000..e183102 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket2481Test.php @@ -0,0 +1,44 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\Ticket2481Product') + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + $this->_conn = $this->_em->getConnection(); + } + + public function testEmptyInsert() + { + $test = new Ticket2481Product(); + $this->_em->persist($test); + $this->_em->flush(); + + $this->assertTrue($test->id > 0); + } +} + +/** + * @Entity + * @Table(name="ticket_2481_products") + */ +class Ticket2481Product +{ + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + public $id; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket69.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket69.php new file mode 100644 index 0000000..1ca3511 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/Ticket/Ticket69.php @@ -0,0 +1,427 @@ +_schemaTool->createSchema(array( + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\Lemma'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\Relation'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\Ticket\RelationType') + )); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + + public function testIssue() + { + //setup + $lemma1 = new Lemma; + $lemma1->setLemma('foo'); + + $lemma2 = new Lemma; + $lemma2->setLemma('bar'); + + $lemma3 = new Lemma; + $lemma3->setLemma('batz'); + + $lemma4 = new Lemma; + $lemma4->setLemma('bla'); + + $type1 = new RelationType; + $type1->setType('nonsense'); + $type1->setAbbreviation('non'); + + $type2 = new RelationType; + $type2->setType('quatsch'); + $type2->setAbbreviation('qu'); + + $relation1 = new Relation; + $relation1->setParent($lemma1); + $relation1->setChild($lemma2); + $relation1->setType($type1); + + $relation2 = new Relation; + $relation2->setParent($lemma1); + $relation2->setChild($lemma3); + $relation2->setType($type1); + + $relation3 = new Relation; + $relation3->setParent($lemma1); + $relation3->setChild($lemma4); + $relation3->setType($type2); + + $lemma1->addRelation($relation1); + $lemma1->addRelation($relation2); + $lemma1->addRelation($relation3); + + $this->_em->persist($type1); + $this->_em->persist($type2); + $this->_em->persist($lemma1); + $this->_em->persist($lemma2); + $this->_em->persist($lemma3); + $this->_em->persist($lemma4); + + $this->_em->flush(); + $this->_em->clear(); + //end setup + + // test One To Many + $query = $this->_em->createQuery("SELECT l FROM Doctrine\Tests\ORM\Functional\Ticket\Lemma l Where l.lemma = 'foo'"); + $res = $query->getResult(); + $lemma = $res[0]; + + $this->assertEquals('foo', $lemma->getLemma()); + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\Lemma', $lemma); + $relations = $lemma->getRelations(); + + foreach($relations as $relation) { + $this->assertInstanceOf('Doctrine\Tests\ORM\Functional\Ticket\Relation', $relation); + $this->assertTrue($relation->getType()->getType() != ''); + } + + $this->_em->clear(); + + } +} + +/** + * @Entity + * @Table(name="lemma") + */ +class Lemma { + + const CLASS_NAME = __CLASS__; + + /** + * @var int + * @Id + * @Column(type="integer", name="lemma_id") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * + * @var string + * @Column(type="string", name="lemma_name", unique=true, length=255) + */ + private $lemma; + + + /** + * @var kateglo\application\utilities\collections\ArrayCollection + * @OneToMany(targetEntity="Relation", mappedBy="parent", cascade={"persist"}) + */ + private $relations; + + public function __construct() { + $this->types = new \Doctrine\Common\Collections\ArrayCollection(); + $this->relations = new \Doctrine\Common\Collections\ArrayCollection(); + } + + + /** + * + * @return int + */ + public function getId() { + return $this->id; + } + + /** + * + * @param string $lemma + * @return void + */ + public function setLemma($lemma) { + $this->lemma = $lemma; + } + + /** + * + * @return string + */ + public function getLemma() { + return $this->lemma; + } + + + /** + * + * @param Relation $relation + * @return void + */ + public function addRelation(Relation $relation) { + $this->relations[] = $relation; + $relation->setParent($this); + } + + /** + * + * @param Relation $relation + * @return void + */ + public function removeRelation(Relation $relation) { + /*@var $removed Relation */ + $removed = $this->relations->removeElement($relation); + if ($removed !== null) { + $removed->removeParent(); + } + } + + /** + * + * @return kateglo\application\utilities\collections\ArrayCollection + */ + public function getRelations() { + return $this->relations; + } + +} + +/** + * + * @Entity + * @Table(name="relation") + */ +class Relation { + + const CLASS_NAME = __CLASS__; + + /** + * @var int + * @Id + * @Column(type="integer", name="relation_id") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @var Lemma + * @ManyToOne(targetEntity="Lemma", inversedBy="relations") + * @JoinColumn(name="relation_parent_id", referencedColumnName="lemma_id") + */ + private $parent; + + /** + * @var Lemma + * @OneToOne(targetEntity="Lemma") + * @JoinColumn(name="relation_child_id", referencedColumnName="lemma_id") + */ + private $child; + + /** + * @var RelationType + * @ManyToOne(targetEntity="RelationType", inversedBy="relations") + * @JoinColumn(name="relation_type_id", referencedColumnName="relation_type_id") + */ + private $type; + + /** + * + * @param Lemma $parent + * @return void + */ + public function setParent(Lemma $parent) { + $this->parent = $parent; + } + + /** + * + * @return Phrase + */ + public function getParent() { + return $this->parent; + } + + /** + * + * @return void + */ + public function removeParent() { + if ($this->lemma !== null) { + /*@var $phrase Lemma */ + $lemma = $this->parent; + $this->parent = null; + $lemma->removeRelation($this); + } + } + + /** + * + * @param Lemma $child + * @return void + */ + public function setChild(Lemma $child) { + $this->child = $child; + } + + /** + * + * @return Lemma + */ + public function getChild() { + return $this->child; + } + + /** + * + * @param RelationType $type + * @return void + */ + public function setType(RelationType $type) { + $this->type = $type; + } + + /** + * + * @return RelationType + */ + public function getType() { + return $this->type; + } + + /** + * + * @return void + */ + public function removeType() { + if ($this->type !== null) { + /*@var $phrase RelationType */ + $type = $this->type; + $this->type = null; + $type->removeRelation($this); + } + } +} + +/** + * + * @Entity + * @Table(name="relation_type") + */ +class RelationType { + + const CLASS_NAME = __CLASS__; + + /** + * + * @var int + * @Id + * @Column(type="integer", name="relation_type_id") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * + * @var string + * @Column(type="string", name="relation_type_name", unique=true, length=255) + */ + private $type; + + /** + * + * @var string + * @Column(type="string", name="relation_type_abbreviation", unique=true, length=255) + */ + private $abbreviation; + + /** + * @var kateglo\application\utilities\collections\ArrayCollection + * @OneToMany(targetEntity="Relation", mappedBy="type", cascade={"persist"}) + */ + private $relations; + + public function __construct() { + $relations = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * + * @return int + */ + public function getId() { + return $this->id; + } + + /** + * + * @param string $type + * @return void + */ + public function setType($type) { + $this->type = $type; + } + + /** + * + * @return string + */ + public function getType() { + return $this->type; + } + + /** + * + * @param string $abbreviation + * @return void + */ + public function setAbbreviation($abbreviation) { + $this->abbreviation = $abbreviation; + } + + /** + * + * @return string + */ + public function getAbbreviation() { + return $this->abbreviation; + } + + /** + * + * @param Relation $relation + * @return void + */ + public function addRelation(Relation $relation) { + $this->relations[] = $relation; + $relation->setType($this); + } + + /** + * + * @param Relation $relation + * @return void + */ + public function removeRelation(Relation $relation) { + /*@var $removed Relation */ + $removed = $this->relations->removeElement($relation); + if ($removed !== null) { + $removed->removeLemma(); + } + } + + /** + * + * @return kateglo\application\utilities\collections\ArrayCollection + */ + public function getRelations() { + return $this->relations; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/TypeTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/TypeTest.php new file mode 100644 index 0000000..9ed8cf0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/TypeTest.php @@ -0,0 +1,182 @@ +useModelSet('generic'); + parent::setUp(); + } + + public function testDecimal() + { + $decimal = new DecimalModel(); + $decimal->decimal = 0.15; + $decimal->highScale = 0.1515; + + $this->_em->persist($decimal); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT d FROM Doctrine\Tests\Models\Generic\DecimalModel d"; + $decimal = $this->_em->createQuery($dql)->getSingleResult(); + + $this->assertEquals(0.15, $decimal->decimal); + $this->assertEquals(0.1515, $decimal->highScale); + } + + /** + * @group DDC-1394 + * @return void + */ + public function testBoolean() + { + $bool = new BooleanModel(); + $bool->booleanField = true; + + $this->_em->persist($bool); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = true"; + $bool = $this->_em->createQuery($dql)->getSingleResult(); + + $this->assertTrue($bool->booleanField); + + $bool->booleanField = false; + + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = false"; + $bool = $this->_em->createQuery($dql)->getSingleResult(); + + $this->assertFalse($bool->booleanField); + } + + public function testArray() + { + $serialize = new SerializationModel(); + $serialize->array["foo"] = "bar"; + $serialize->array["bar"] = "baz"; + + $this->_em->persist($serialize); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT s FROM Doctrine\Tests\Models\Generic\SerializationModel s"; + $serialize = $this->_em->createQuery($dql)->getSingleResult(); + + $this->assertEquals(array("foo" => "bar", "bar" => "baz"), $serialize->array); + } + + public function testObject() + { + $serialize = new SerializationModel(); + $serialize->object = new \stdClass(); + + $this->_em->persist($serialize); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT s FROM Doctrine\Tests\Models\Generic\SerializationModel s"; + $serialize = $this->_em->createQuery($dql)->getSingleResult(); + + $this->assertInstanceOf('stdClass', $serialize->object); + } + + public function testDate() + { + $dateTime = new DateTimeModel(); + $dateTime->date = new \DateTime('2009-10-01', new \DateTimeZone('Europe/Berlin')); + + $this->_em->persist($dateTime); + $this->_em->flush(); + $this->_em->clear(); + + $dateTimeDb = $this->_em->find('Doctrine\Tests\Models\Generic\DateTimeModel', $dateTime->id); + + $this->assertInstanceOf('DateTime', $dateTimeDb->date); + $this->assertEquals('2009-10-01', $dateTimeDb->date->format('Y-m-d')); + } + + public function testDateTime() + { + $dateTime = new DateTimeModel(); + $dateTime->datetime = new \DateTime('2009-10-02 20:10:52', new \DateTimeZone('Europe/Berlin')); + + $this->_em->persist($dateTime); + $this->_em->flush(); + $this->_em->clear(); + + $dateTimeDb = $this->_em->find('Doctrine\Tests\Models\Generic\DateTimeModel', $dateTime->id); + + $this->assertInstanceOf('DateTime', $dateTimeDb->datetime); + $this->assertEquals('2009-10-02 20:10:52', $dateTimeDb->datetime->format('Y-m-d H:i:s')); + + $articles = $this->_em->getRepository( 'Doctrine\Tests\Models\Generic\DateTimeModel' )->findBy( array( 'datetime' => new \DateTime( "now" ) ) ); + $this->assertEquals( 0, count( $articles ) ); + } + + public function testDqlQueryBindDateTimeInstance() + { + $date = new \DateTime('2009-10-02 20:10:52', new \DateTimeZone('Europe/Berlin')); + + $dateTime = new DateTimeModel(); + $dateTime->datetime = $date; + + $this->_em->persist($dateTime); + $this->_em->flush(); + $this->_em->clear(); + + $dateTimeDb = $this->_em->createQuery('SELECT d FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime = ?1') + ->setParameter(1, $date, DBALType::DATETIME) + ->getSingleResult(); + } + + public function testDqlQueryBuilderBindDateTimeInstance() + { + $date = new \DateTime('2009-10-02 20:10:52', new \DateTimeZone('Europe/Berlin')); + + $dateTime = new DateTimeModel(); + $dateTime->datetime = $date; + + $this->_em->persist($dateTime); + $this->_em->flush(); + $this->_em->clear(); + + $dateTimeDb = $this->_em->createQueryBuilder() + ->select('d') + ->from('Doctrine\Tests\Models\Generic\DateTimeModel', 'd') + ->where('d.datetime = ?1') + ->setParameter(1, $date, DBALType::DATETIME) + ->getQuery()->getSingleResult(); + } + + public function testTime() + { + $dateTime = new DateTimeModel(); + $dateTime->time = new \DateTime('2010-01-01 19:27:20'); + + $this->_em->persist($dateTime); + $this->_em->flush(); + $this->_em->clear(); + + $dateTimeDb = $this->_em->find('Doctrine\Tests\Models\Generic\DateTimeModel', $dateTime->id); + + $this->assertInstanceOf('DateTime', $dateTime->time); + $this->assertEquals('19:27:20', $dateTime->time->format('H:i:s')); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php new file mode 100644 index 0000000..537f238 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php @@ -0,0 +1,142 @@ +useModelSet('customtype'); + parent::setUp(); + } + + public function testUpperCaseStringType() + { + $entity = new CustomTypeUpperCase(); + $entity->lowerCaseString = 'foo'; + + $this->_em->persist($entity); + $this->_em->flush(); + + $id = $entity->id; + + $this->_em->clear(); + + $entity = $this->_em->find('\Doctrine\Tests\Models\CustomType\CustomTypeUpperCase', $id); + + $this->assertEquals('foo', $entity->lowerCaseString, 'Entity holds lowercase string'); + $this->assertEquals('FOO', $this->_em->getConnection()->fetchColumn("select lowerCaseString from customtype_uppercases where id=".$entity->id.""), 'Database holds uppercase string'); + } + + /** + * @group DDC-1642 + */ + public function testUpperCaseStringTypeWhenColumnNameIsDefined() + { + + $entity = new CustomTypeUpperCase(); + $entity->lowerCaseString = 'Some Value'; + $entity->namedLowerCaseString = 'foo'; + + $this->_em->persist($entity); + $this->_em->flush(); + + $id = $entity->id; + + $this->_em->clear(); + + $entity = $this->_em->find('\Doctrine\Tests\Models\CustomType\CustomTypeUpperCase', $id); + $this->assertEquals('foo', $entity->namedLowerCaseString, 'Entity holds lowercase string'); + $this->assertEquals('FOO', $this->_em->getConnection()->fetchColumn("select named_lower_case_string from customtype_uppercases where id=".$entity->id.""), 'Database holds uppercase string'); + + + $entity->namedLowerCaseString = 'bar'; + + $this->_em->persist($entity); + $this->_em->flush(); + + $id = $entity->id; + + $this->_em->clear(); + + + $entity = $this->_em->find('\Doctrine\Tests\Models\CustomType\CustomTypeUpperCase', $id); + $this->assertEquals('bar', $entity->namedLowerCaseString, 'Entity holds lowercase string'); + $this->assertEquals('BAR', $this->_em->getConnection()->fetchColumn("select named_lower_case_string from customtype_uppercases where id=".$entity->id.""), 'Database holds uppercase string'); + } + + public function testTypeValueSqlWithAssociations() + { + $parent = new CustomTypeParent(); + $parent->customInteger = -1; + $parent->child = new CustomTypeChild(); + + $friend1 = new CustomTypeParent(); + $friend2 = new CustomTypeParent(); + + $parent->addMyFriend($friend1); + $parent->addMyFriend($friend2); + + $this->_em->persist($parent); + $this->_em->persist($friend1); + $this->_em->persist($friend2); + $this->_em->flush(); + + $parentId = $parent->id; + + $this->_em->clear(); + + $entity = $this->_em->find('Doctrine\Tests\Models\CustomType\CustomTypeParent', $parentId); + + $this->assertTrue($entity->customInteger < 0, 'Fetched customInteger negative'); + $this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select customInteger from customtype_parents where id=".$entity->id.""), 'Database has stored customInteger positive'); + + $this->assertNotNull($parent->child, 'Child attached'); + $this->assertCount(2, $entity->getMyFriends(), '2 friends attached'); + } + + public function testSelectDQL() + { + $parent = new CustomTypeParent(); + $parent->customInteger = -1; + $parent->child = new CustomTypeChild(); + + $this->_em->persist($parent); + $this->_em->flush(); + + $parentId = $parent->id; + + $this->_em->clear(); + + $query = $this->_em->createQuery("SELECT p, p.customInteger, c from Doctrine\Tests\Models\CustomType\CustomTypeParent p JOIN p.child c where p.id = " . $parentId); + + $result = $query->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CustomType\CustomTypeParent', $result[0][0]); + $this->assertEquals(-1, $result[0][0]->customInteger); + + $this->assertEquals(-1, $result[0]['customInteger']); + + $this->assertEquals('foo', $result[0][0]->child->lowerCaseString); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/UUIDGeneratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/UUIDGeneratorTest.php new file mode 100644 index 0000000..5fa237e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/UUIDGeneratorTest.php @@ -0,0 +1,48 @@ +_em->getConnection()->getDatabasePlatform()->getName() != 'mysql') { + $this->markTestSkipped('Currently restricted to MySQL platform.'); + } + + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(__NAMESPACE__ . '\\UUIDEntity') + )); + } + + public function testGenerateUUID() + { + $entity = new UUIDEntity(); + + $this->_em->persist($entity); + $this->assertNotNull($entity->getId()); + $this->assertTrue(strlen($entity->getId()) > 0); + } +} + +/** + * @Entity + */ +class UUIDEntity +{ + /** @Id @Column(type="string") @GeneratedValue(strategy="UUID") */ + private $id; + /** + * Get id. + * + * @return id. + */ + public function getId() + { + return $this->id; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/UnitOfWorkLifecycleTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/UnitOfWorkLifecycleTest.php new file mode 100644 index 0000000..08e3720 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Functional/UnitOfWorkLifecycleTest.php @@ -0,0 +1,71 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testScheduleInsertManaged() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin"; + $user->status = "active"; + $this->_em->persist($user); + $this->_em->flush(); + + $this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "A managed+dirty entity Doctrine\Tests\Models\CMS\CmsUser"); + $this->_em->getUnitOfWork()->scheduleForInsert($user); + } + + public function testScheduleInsertDeleted() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin"; + $user->status = "active"; + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->remove($user); + + $this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "Removed entity Doctrine\Tests\Models\CMS\CmsUser"); + $this->_em->getUnitOfWork()->scheduleForInsert($user); + } + + public function testScheduleInsertTwice() + { + $user = new CmsUser(); + $user->username = "beberlei"; + $user->name = "Benjamin"; + $user->status = "active"; + + $this->_em->getUnitOfWork()->scheduleForInsert($user); + + $this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "Entity Doctrine\Tests\Models\CMS\CmsUser"); + $this->_em->getUnitOfWork()->scheduleForInsert($user); + } + + public function testAddToIdentityMapWithoutIdentity() + { + $user = new CmsUser(); + + $this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "The given entity of type 'Doctrine\Tests\Models\CMS\CmsUser' (Doctrine\Tests\Models\CMS\CmsUser@"); + $this->_em->getUnitOfWork()->registerManaged($user, array(), array()); + } + + public function testMarkReadOnlyNonManaged() + { + $user = new CmsUser(); + + $this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "Only managed entities can be marked or checked as read only. But Doctrine\Tests\Models\CMS\CmsUser@"); + $this->_em->getUnitOfWork()->markReadOnly($user); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ArrayHydratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ArrayHydratorTest.php new file mode 100644 index 0000000..b72e361 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ArrayHydratorTest.php @@ -0,0 +1,1147 @@ +addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(2, count($result)); + + $this->assertTrue(is_array($result)); + + $this->assertEquals(1, $result[0]['id']); + $this->assertEquals('romanb', $result[0]['name']); + + $this->assertEquals(2, $result[1]['id']); + $this->assertEquals('jwage', $result[1]['name']); + } + + /** + * SELECT PARTIAL u.{id, name} AS user + * FROM Doctrine\Tests\Models\CMS\CmsUser u + */ + public function testSimpleEntityQueryWithAliasedUserEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(2, count($result)); + + $this->assertTrue(is_array($result)); + + $this->assertArrayHasKey('user', $result[0]); + $this->assertEquals(1, $result[0]['user']['id']); + $this->assertEquals('romanb', $result[0]['user']['name']); + + $this->assertArrayHasKey('user', $result[1]); + $this->assertEquals(2, $result[1]['user']['id']); + $this->assertEquals('jwage', $result[1]['user']['name']); + } + + /** + * SELECT PARTIAL u.{id, name}, PARTIAL a.{id, topic} + * FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a + */ + public function testSimpleMultipleRootEntityQuery() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(4, count($result)); + + $this->assertEquals(1, $result[0]['id']); + $this->assertEquals('romanb', $result[0]['name']); + + $this->assertEquals(1, $result[1]['id']); + $this->assertEquals('Cool things.', $result[1]['topic']); + + $this->assertEquals(2, $result[2]['id']); + $this->assertEquals('jwage', $result[2]['name']); + + $this->assertEquals(2, $result[3]['id']); + $this->assertEquals('Cool things II.', $result[3]['topic']); + } + + /** + * SELECT PARTIAL u.{id, name} AS user, PARTIAL a.{id, topic} + * FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a + */ + public function testSimpleMultipleRootEntityQueryWithAliasedUserEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(4, count($result)); + + $this->assertArrayHasKey('user', $result[0]); + $this->assertEquals(1, $result[0]['user']['id']); + $this->assertEquals('romanb', $result[0]['user']['name']); + + $this->assertArrayHasKey(0, $result[1]); + $this->assertEquals(1, $result[1][0]['id']); + $this->assertEquals('Cool things.', $result[1][0]['topic']); + + $this->assertArrayHasKey('user', $result[2]); + $this->assertEquals(2, $result[2]['user']['id']); + $this->assertEquals('jwage', $result[2]['user']['name']); + + $this->assertArrayHasKey(0, $result[3]); + $this->assertEquals(2, $result[3][0]['id']); + $this->assertEquals('Cool things II.', $result[3][0]['topic']); + } + + /** + * SELECT PARTIAL u.{id, name}, PARTIAL a.{id, topic} AS article + * FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a + */ + public function testSimpleMultipleRootEntityQueryWithAliasedArticleEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a', 'article'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(4, count($result)); + + $this->assertArrayHasKey(0, $result[0]); + $this->assertEquals(1, $result[0][0]['id']); + $this->assertEquals('romanb', $result[0][0]['name']); + + $this->assertArrayHasKey('article', $result[1]); + $this->assertEquals(1, $result[1]['article']['id']); + $this->assertEquals('Cool things.', $result[1]['article']['topic']); + + $this->assertArrayHasKey(0, $result[2]); + $this->assertEquals(2, $result[2][0]['id']); + $this->assertEquals('jwage', $result[2][0]['name']); + + $this->assertArrayHasKey('article', $result[3]); + $this->assertEquals(2, $result[3]['article']['id']); + $this->assertEquals('Cool things II.', $result[3]['article']['topic']); + } + + /** + * SELECT PARTIAL u.{id, name} AS user, PARTIAL a.{id, topic} AS article + * FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a + */ + public function testSimpleMultipleRootEntityQueryWithAliasedEntities() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a', 'article'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(4, count($result)); + + $this->assertArrayHasKey('user', $result[0]); + $this->assertEquals(1, $result[0]['user']['id']); + $this->assertEquals('romanb', $result[0]['user']['name']); + + $this->assertArrayHasKey('article', $result[1]); + $this->assertEquals(1, $result[1]['article']['id']); + $this->assertEquals('Cool things.', $result[1]['article']['topic']); + + $this->assertArrayHasKey('user', $result[2]); + $this->assertEquals(2, $result[2]['user']['id']); + $this->assertEquals('jwage', $result[2]['user']['name']); + + $this->assertArrayHasKey('article', $result[3]); + $this->assertEquals(2, $result[3]['article']['id']); + $this->assertEquals('Cool things II.', $result[3]['article']['topic']); + } + + /** + * SELECT PARTIAL u.{id, status}, COUNT(p.phonenumber) AS numPhones + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * JOIN u.phonenumbers p + * GROUP BY u.status, u.id + * + * @dataProvider provideDataForUserEntityResult + */ + public function testMixedQueryNormalJoin($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'numPhones'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => '2', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => '1', + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(2, count($result)); + $this->assertTrue(is_array($result)); + $this->assertTrue(is_array($result[0])); + $this->assertTrue(is_array($result[1])); + + // first user => 2 phonenumbers + $this->assertArrayHasKey($userEntityKey, $result[0]); + $this->assertEquals(2, $result[0]['numPhones']); + + // second user => 1 phonenumber + $this->assertArrayHasKey($userEntityKey, $result[1]); + $this->assertEquals(1, $result[1]['numPhones']); + } + + /** + * SELECT PARTIAL u.{id, status}, PARTIAL p.{phonenumber}, UPPER(u.name) AS nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * JOIN u.phonenumbers p + * + * @dataProvider provideDataForUserEntityResult + */ + public function testMixedQueryFetchJoin($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(2, count($result)); + + $this->assertTrue(is_array($result)); + $this->assertTrue(is_array($result[0])); + $this->assertTrue(is_array($result[1])); + + // first user => 2 phonenumbers + $this->assertEquals(2, count($result[0][$userEntityKey]['phonenumbers'])); + $this->assertEquals('ROMANB', $result[0]['nameUpper']); + + // second user => 1 phonenumber + $this->assertEquals(1, count($result[1][$userEntityKey]['phonenumbers'])); + $this->assertEquals('JWAGE', $result[1]['nameUpper']); + + $this->assertEquals(42, $result[0][$userEntityKey]['phonenumbers'][0]['phonenumber']); + $this->assertEquals(43, $result[0][$userEntityKey]['phonenumbers'][1]['phonenumber']); + $this->assertEquals(91, $result[1][$userEntityKey]['phonenumbers'][0]['phonenumber']); + } + + /** + * SELECT PARTIAL u.{id, status}, UPPER(u.name) nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * INDEX BY u.id + * JOIN u.phonenumbers p + * INDEX BY p.phonenumber + * + * @dataProvider provideDataForUserEntityResult + */ + public function testMixedQueryFetchJoinCustomIndex($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addIndexBy('u', 'id'); + $rsm->addIndexBy('p', 'phonenumber'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91' + ) + ); + + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(2, count($result)); + + $this->assertTrue(is_array($result)); + $this->assertTrue(is_array($result[1])); + $this->assertTrue(is_array($result[2])); + + // test the scalar values + $this->assertEquals('ROMANB', $result[1]['nameUpper']); + $this->assertEquals('JWAGE', $result[2]['nameUpper']); + + // first user => 2 phonenumbers. notice the custom indexing by user id + $this->assertEquals(2, count($result[1][$userEntityKey]['phonenumbers'])); + + // second user => 1 phonenumber. notice the custom indexing by user id + $this->assertEquals(1, count($result[2][$userEntityKey]['phonenumbers'])); + + // test the custom indexing of the phonenumbers + $this->assertTrue(isset($result[1][$userEntityKey]['phonenumbers']['42'])); + $this->assertTrue(isset($result[1][$userEntityKey]['phonenumbers']['43'])); + $this->assertTrue(isset($result[2][$userEntityKey]['phonenumbers']['91'])); + } + + /** + * select u.id, u.status, p.phonenumber, upper(u.name) nameUpper, a.id, a.topic + * from User u + * join u.phonenumbers p + * join u.articles a + * = + * select u.id, u.status, p.phonenumber, upper(u.name) as u__0, a.id, a.topic + * from USERS u + * inner join PHONENUMBERS p ON u.id = p.user_id + * inner join ARTICLES a ON u.id = a.user_id + */ + public function testMixedQueryMultipleFetchJoin() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsArticle', + 'a', + 'u', + 'articles' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + 'a__id' => '1', + 'a__topic' => 'Getting things done!' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + 'a__id' => '1', + 'a__topic' => 'Getting things done!' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + 'a__id' => '2', + 'a__topic' => 'ZendCon' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + 'a__id' => '2', + 'a__topic' => 'ZendCon' + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91', + 'a__id' => '3', + 'a__topic' => 'LINQ' + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91', + 'a__id' => '4', + 'a__topic' => 'PHP6' + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(2, count($result)); + $this->assertTrue(is_array($result)); + $this->assertTrue(is_array($result[0])); + $this->assertTrue(is_array($result[1])); + // first user => 2 phonenumbers, 2 articles + $this->assertEquals(2, count($result[0][0]['phonenumbers'])); + $this->assertEquals(2, count($result[0][0]['articles'])); + $this->assertEquals('ROMANB', $result[0]['nameUpper']); + // second user => 1 phonenumber, 2 articles + $this->assertEquals(1, count($result[1][0]['phonenumbers'])); + $this->assertEquals(2, count($result[1][0]['articles'])); + $this->assertEquals('JWAGE', $result[1]['nameUpper']); + + $this->assertEquals(42, $result[0][0]['phonenumbers'][0]['phonenumber']); + $this->assertEquals(43, $result[0][0]['phonenumbers'][1]['phonenumber']); + $this->assertEquals(91, $result[1][0]['phonenumbers'][0]['phonenumber']); + + $this->assertEquals('Getting things done!', $result[0][0]['articles'][0]['topic']); + $this->assertEquals('ZendCon', $result[0][0]['articles'][1]['topic']); + $this->assertEquals('LINQ', $result[1][0]['articles'][0]['topic']); + $this->assertEquals('PHP6', $result[1][0]['articles'][1]['topic']); + } + + /** + * select u.id, u.status, p.phonenumber, upper(u.name) nameUpper, a.id, a.topic, + * c.id, c.topic + * from User u + * join u.phonenumbers p + * join u.articles a + * left join a.comments c + * = + * select u.id, u.status, p.phonenumber, upper(u.name) as u__0, a.id, a.topic, + * c.id, c.topic + * from USERS u + * inner join PHONENUMBERS p ON u.id = p.user_id + * inner join ARTICLES a ON u.id = a.user_id + * left outer join COMMENTS c ON a.id = c.article_id + */ + public function testMixedQueryMultipleDeepMixedFetchJoin() + { + + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsArticle', + 'a', + 'u', + 'articles' + ); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsComment', + 'c', + 'a', + 'comments' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__topic', 'topic'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + 'a__id' => '1', + 'a__topic' => 'Getting things done!', + 'c__id' => '1', + 'c__topic' => 'First!' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + 'a__id' => '1', + 'a__topic' => 'Getting things done!', + 'c__id' => '1', + 'c__topic' => 'First!' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + 'a__id' => '2', + 'a__topic' => 'ZendCon', + 'c__id' => null, + 'c__topic' => null + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + 'a__id' => '2', + 'a__topic' => 'ZendCon', + 'c__id' => null, + 'c__topic' => null + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91', + 'a__id' => '3', + 'a__topic' => 'LINQ', + 'c__id' => null, + 'c__topic' => null + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91', + 'a__id' => '4', + 'a__topic' => 'PHP6', + 'c__id' => null, + 'c__topic' => null + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(2, count($result)); + $this->assertTrue(is_array($result)); + $this->assertTrue(is_array($result[0])); + $this->assertTrue(is_array($result[1])); + + // first user => 2 phonenumbers, 2 articles, 1 comment on first article + $this->assertEquals(2, count($result[0][0]['phonenumbers'])); + $this->assertEquals(2, count($result[0][0]['articles'])); + $this->assertEquals(1, count($result[0][0]['articles'][0]['comments'])); + $this->assertEquals('ROMANB', $result[0]['nameUpper']); + // second user => 1 phonenumber, 2 articles, no comments + $this->assertEquals(1, count($result[1][0]['phonenumbers'])); + $this->assertEquals(2, count($result[1][0]['articles'])); + $this->assertEquals('JWAGE', $result[1]['nameUpper']); + + $this->assertEquals(42, $result[0][0]['phonenumbers'][0]['phonenumber']); + $this->assertEquals(43, $result[0][0]['phonenumbers'][1]['phonenumber']); + $this->assertEquals(91, $result[1][0]['phonenumbers'][0]['phonenumber']); + + $this->assertEquals('Getting things done!', $result[0][0]['articles'][0]['topic']); + $this->assertEquals('ZendCon', $result[0][0]['articles'][1]['topic']); + $this->assertEquals('LINQ', $result[1][0]['articles'][0]['topic']); + $this->assertEquals('PHP6', $result[1][0]['articles'][1]['topic']); + + $this->assertEquals('First!', $result[0][0]['articles'][0]['comments'][0]['topic']); + + $this->assertTrue(isset($result[0][0]['articles'][0]['comments'])); + + // empty comment collections + $this->assertTrue(is_array($result[0][0]['articles'][1]['comments'])); + $this->assertEquals(0, count($result[0][0]['articles'][1]['comments'])); + $this->assertTrue(is_array($result[1][0]['articles'][0]['comments'])); + $this->assertEquals(0, count($result[1][0]['articles'][0]['comments'])); + $this->assertTrue(is_array($result[1][0]['articles'][1]['comments'])); + $this->assertEquals(0, count($result[1][0]['articles'][1]['comments'])); + } + + /** + * Tests that the hydrator does not rely on a particular order of the rows + * in the result set. + * + * DQL: + * select c.id, c.position, c.name, b.id, b.position + * from \Doctrine\Tests\Models\Forum\ForumCategory c inner join c.boards b + * order by c.position asc, b.position asc + * + * Checks whether the boards are correctly assigned to the categories. + * + * The 'evil' result set that confuses the object population is displayed below. + * + * c.id | c.position | c.name | boardPos | b.id | b.category_id (just for clarity) + * 1 | 0 | First | 0 | 1 | 1 + * 2 | 0 | Second | 0 | 2 | 2 <-- + * 1 | 0 | First | 1 | 3 | 1 + * 1 | 0 | First | 2 | 4 | 1 + */ + public function testEntityQueryCustomResultSetOrder() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\Forum\ForumCategory', 'c'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\Forum\ForumBoard', + 'b', + 'c', + 'boards' + ); + + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__position', 'position'); + $rsm->addFieldResult('c', 'c__name', 'name'); + $rsm->addFieldResult('b', 'b__id', 'id'); + $rsm->addFieldResult('b', 'b__position', 'position'); + + // Faked result set + $resultSet = array( + array( + 'c__id' => '1', + 'c__position' => '0', + 'c__name' => 'First', + 'b__id' => '1', + 'b__position' => '0', + //'b__category_id' => '1' + ), + array( + 'c__id' => '2', + 'c__position' => '0', + 'c__name' => 'Second', + 'b__id' => '2', + 'b__position' => '0', + //'b__category_id' => '2' + ), + array( + 'c__id' => '1', + 'c__position' => '0', + 'c__name' => 'First', + 'b__id' => '3', + 'b__position' => '1', + //'b__category_id' => '1' + ), + array( + 'c__id' => '1', + 'c__position' => '0', + 'c__name' => 'First', + 'b__id' => '4', + 'b__position' => '2', + //'b__category_id' => '1' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(2, count($result)); + $this->assertTrue(is_array($result)); + $this->assertTrue(is_array($result[0])); + $this->assertTrue(is_array($result[1])); + $this->assertTrue(isset($result[0]['boards'])); + $this->assertEquals(3, count($result[0]['boards'])); + $this->assertTrue(isset($result[1]['boards'])); + $this->assertEquals(1, count($result[1]['boards'])); + } + + /** + * SELECT PARTIAL u.{id,status}, a.id, a.topic, c.id as cid, c.topic as ctopic + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * LEFT JOIN u.articles a + * LEFT JOIN a.comments c + * + * @dataProvider provideDataForUserEntityResult + */ + public function testChainedJoinWithScalars($entityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $entityKey ?: null); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('a__id', 'id'); + $rsm->addScalarResult('a__topic', 'topic'); + $rsm->addScalarResult('c__id', 'cid'); + $rsm->addScalarResult('c__topic', 'ctopic'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'a__id' => '1', + 'a__topic' => 'The First', + 'c__id' => '1', + 'c__topic' => 'First Comment' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'a__id' => '1', + 'a__topic' => 'The First', + 'c__id' => '2', + 'c__topic' => 'Second Comment' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'a__id' => '42', + 'a__topic' => 'The Answer', + 'c__id' => null, + 'c__topic' => null + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(3, count($result)); + + $this->assertEquals(2, count($result[0][$entityKey])); // User array + $this->assertEquals(1, $result[0]['id']); + $this->assertEquals('The First', $result[0]['topic']); + $this->assertEquals(1, $result[0]['cid']); + $this->assertEquals('First Comment', $result[0]['ctopic']); + + $this->assertEquals(2, count($result[1][$entityKey])); // User array, duplicated + $this->assertEquals(1, $result[1]['id']); // duplicated + $this->assertEquals('The First', $result[1]['topic']); // duplicated + $this->assertEquals(2, $result[1]['cid']); + $this->assertEquals('Second Comment', $result[1]['ctopic']); + + $this->assertEquals(2, count($result[2][$entityKey])); // User array, duplicated + $this->assertEquals(42, $result[2]['id']); + $this->assertEquals('The Answer', $result[2]['topic']); + $this->assertNull($result[2]['cid']); + $this->assertNull($result[2]['ctopic']); + } + + /** + * SELECT PARTIAL u.{id, status} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + */ + public function testResultIteration() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $iterator = $hydrator->iterate($stmt, $rsm); + $rowNum = 0; + + while (($row = $iterator->next()) !== false) { + $this->assertEquals(1, count($row)); + $this->assertTrue(is_array($row[0])); + + if ($rowNum == 0) { + $this->assertEquals(1, $row[0]['id']); + $this->assertEquals('romanb', $row[0]['name']); + } else if ($rowNum == 1) { + $this->assertEquals(2, $row[0]['id']); + $this->assertEquals('jwage', $row[0]['name']); + } + + ++$rowNum; + } + } + + /** + * SELECT PARTIAL u.{id, status} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + */ + public function testResultIterationWithAliasedUserEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $iterator = $hydrator->iterate($stmt, $rsm); + $rowNum = 0; + + while (($row = $iterator->next()) !== false) { + $this->assertEquals(1, count($row)); + $this->assertArrayHasKey(0, $row); + $this->assertArrayHasKey('user', $row[0]); + + if ($rowNum == 0) { + $this->assertEquals(1, $row[0]['user']['id']); + $this->assertEquals('romanb', $row[0]['user']['name']); + } else if ($rowNum == 1) { + $this->assertEquals(2, $row[0]['user']['id']); + $this->assertEquals('jwage', $row[0]['user']['name']); + } + + ++$rowNum; + } + } + + /** + * SELECT PARTIAL u.{id, name} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * + * @group DDC-644 + */ + public function testSkipUnknownColumns() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'foo' => 'bar', // unknown! + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(1, count($result)); + $this->assertArrayHasKey('id', $result[0]); + $this->assertArrayHasKey('name', $result[0]); + $this->assertArrayNotHasKey('foo', $result[0]); + } + + /** + * SELECT PARTIAL u.{id, status}, UPPER(u.name) AS nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * + * @group DDC-1358 + * @dataProvider provideDataForUserEntityResult + */ + public function testMissingIdForRootEntity($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + ), + array( + 'u__id' => null, + 'u__status' => null, + 'sclr0' => 'ROMANB', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + ), + array( + 'u__id' => null, + 'u__status' => null, + 'sclr0' => 'JWAGE', + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(4, count($result), "Should hydrate four results."); + + $this->assertEquals('ROMANB', $result[0]['nameUpper']); + $this->assertEquals('ROMANB', $result[1]['nameUpper']); + $this->assertEquals('JWAGE', $result[2]['nameUpper']); + $this->assertEquals('JWAGE', $result[3]['nameUpper']); + + $this->assertEquals(array('id' => 1, 'status' => 'developer'), $result[0][$userEntityKey]); + $this->assertNull($result[1][$userEntityKey]); + $this->assertEquals(array('id' => 2, 'status' => 'developer'), $result[2][$userEntityKey]); + $this->assertNull($result[3][$userEntityKey]); + } + + /** + * SELECT PARTIAL u.{id, status}, UPPER(u.name) AS nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * INDEX BY u.id + * + * @group DDC-1385 + * @dataProvider provideDataForUserEntityResult + */ + public function testIndexByAndMixedResult($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addIndexBy('u', 'id'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(2, count($result)); + + $this->assertTrue(isset($result[1])); + $this->assertEquals(1, $result[1][$userEntityKey]['id']); + + $this->assertTrue(isset($result[2])); + $this->assertEquals(2, $result[2][$userEntityKey]['id']); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/CustomHydratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/CustomHydratorTest.php new file mode 100644 index 0000000..09be6bc --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/CustomHydratorTest.php @@ -0,0 +1,29 @@ +_getTestEntityManager(); + $config = $em->getConfiguration(); + $config->addCustomHydrationMode('CustomHydrator', 'Doctrine\Tests\ORM\Hydration\CustomHydrator'); + + $hydrator = $em->newHydrator('CustomHydrator'); + $this->assertInstanceOf('Doctrine\Tests\ORM\Hydration\CustomHydrator', $hydrator); + $this->assertNull($config->getCustomHydrationMode('does not exist')); + } +} + +class CustomHydrator extends AbstractHydrator +{ + protected function hydrateAllData() + { + return $this->_stmt->fetchAll(PDO::FETCH_ASSOC); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/HydrationTestCase.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/HydrationTestCase.php new file mode 100644 index 0000000..6602403 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/HydrationTestCase.php @@ -0,0 +1,30 @@ +_em = $this->_getTestEntityManager(); + } + + /** Helper method */ + protected function _createParserResult($resultSetMapping, $isMixedQuery = false) + { + $parserResult = new ParserResult; + $parserResult->setResultSetMapping($resultSetMapping); + //$parserResult->setDefaultQueryComponentAlias(key($queryComponents)); + //$parserResult->setTableAliasMap($tableToClassAliasMap); + $parserResult->setMixedQuery($isMixedQuery); + return $parserResult; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php new file mode 100644 index 0000000..33636b4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php @@ -0,0 +1,1931 @@ +addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1]); + + $this->assertEquals(1, $result[0]->id); + $this->assertEquals('romanb', $result[0]->name); + + $this->assertEquals(2, $result[1]->id); + $this->assertEquals('jwage', $result[1]->name); + } + + /** + * SELECT PARTIAL u.{id,name} AS user + * FROM Doctrine\Tests\Models\CMS\CmsUser u + */ + public function testSimpleEntityQueryWithAliasedUserEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertArrayHasKey('user', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]['user']); + + $this->assertArrayHasKey('user', $result[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1]['user']); + + $this->assertEquals(1, $result[0]['user']->id); + $this->assertEquals('romanb', $result[0]['user']->name); + + $this->assertEquals(2, $result[1]['user']->id); + $this->assertEquals('jwage', $result[1]['user']->name); + } + + /** + * SELECT PARTIAL u.{id, name}, PARTIAL a.{id, topic} + * FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a + */ + public function testSimpleMultipleRootEntityQuery() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(4, count($result)); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[2]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[3]); + + $this->assertEquals(1, $result[0]->id); + $this->assertEquals('romanb', $result[0]->name); + + $this->assertEquals(1, $result[1]->id); + $this->assertEquals('Cool things.', $result[1]->topic); + + $this->assertEquals(2, $result[2]->id); + $this->assertEquals('jwage', $result[2]->name); + + $this->assertEquals(2, $result[3]->id); + $this->assertEquals('Cool things II.', $result[3]->topic); + } + + /** + * SELECT PARTIAL u.{id, name} AS user, PARTIAL a.{id, topic} + * FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a + */ + public function testSimpleMultipleRootEntityQueryWithAliasedUserEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(4, count($result)); + + $this->assertArrayHasKey('user', $result[0]); + $this->assertArrayNotHasKey(0, $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]['user']); + $this->assertEquals(1, $result[0]['user']->id); + $this->assertEquals('romanb', $result[0]['user']->name); + + $this->assertArrayHasKey(0, $result[1]); + $this->assertArrayNotHasKey('user', $result[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[1][0]); + $this->assertEquals(1, $result[1][0]->id); + $this->assertEquals('Cool things.', $result[1][0]->topic); + + $this->assertArrayHasKey('user', $result[2]); + $this->assertArrayNotHasKey(0, $result[2]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[2]['user']); + $this->assertEquals(2, $result[2]['user']->id); + $this->assertEquals('jwage', $result[2]['user']->name); + + $this->assertArrayHasKey(0, $result[3]); + $this->assertArrayNotHasKey('user', $result[3]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[3][0]); + $this->assertEquals(2, $result[3][0]->id); + $this->assertEquals('Cool things II.', $result[3][0]->topic); + } + + /** + * SELECT PARTIAL u.{id, name}, PARTIAL a.{id, topic} AS article + * FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a + */ + public function testSimpleMultipleRootEntityQueryWithAliasedArticleEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a', 'article'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(4, count($result)); + + $this->assertArrayHasKey(0, $result[0]); + $this->assertArrayNotHasKey('article', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][0]); + $this->assertEquals(1, $result[0][0]->id); + $this->assertEquals('romanb', $result[0][0]->name); + + $this->assertArrayHasKey('article', $result[1]); + $this->assertArrayNotHasKey(0, $result[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[1]['article']); + $this->assertEquals(1, $result[1]['article']->id); + $this->assertEquals('Cool things.', $result[1]['article']->topic); + + $this->assertArrayHasKey(0, $result[2]); + $this->assertArrayNotHasKey('article', $result[2]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[2][0]); + $this->assertEquals(2, $result[2][0]->id); + $this->assertEquals('jwage', $result[2][0]->name); + + $this->assertArrayHasKey('article', $result[3]); + $this->assertArrayNotHasKey(0, $result[3]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[3]['article']); + $this->assertEquals(2, $result[3]['article']->id); + $this->assertEquals('Cool things II.', $result[3]['article']->topic); + } + + /** + * SELECT PARTIAL u.{id, name} AS user, PARTIAL a.{id, topic} AS article + * FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a + */ + public function testSimpleMultipleRootEntityQueryWithAliasedEntities() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsArticle', 'a', 'article'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'a__id' => '1', + 'a__topic' => 'Cool things.' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'a__id' => '2', + 'a__topic' => 'Cool things II.' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(4, count($result)); + + $this->assertArrayHasKey('user', $result[0]); + $this->assertArrayNotHasKey('article', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]['user']); + $this->assertEquals(1, $result[0]['user']->id); + $this->assertEquals('romanb', $result[0]['user']->name); + + $this->assertArrayHasKey('article', $result[1]); + $this->assertArrayNotHasKey('user', $result[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[1]['article']); + $this->assertEquals(1, $result[1]['article']->id); + $this->assertEquals('Cool things.', $result[1]['article']->topic); + + $this->assertArrayHasKey('user', $result[2]); + $this->assertArrayNotHasKey('article', $result[2]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[2]['user']); + $this->assertEquals(2, $result[2]['user']->id); + $this->assertEquals('jwage', $result[2]['user']->name); + + $this->assertArrayHasKey('article', $result[3]); + $this->assertArrayNotHasKey('user', $result[3]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[3]['article']); + $this->assertEquals(2, $result[3]['article']->id); + $this->assertEquals('Cool things II.', $result[3]['article']->topic); + } + + /** + * SELECT PARTIAL u.{id, status}, COUNT(p.phonenumber) numPhones + * FROM User u + * JOIN u.phonenumbers p + * GROUP BY u.id + * + * @dataProvider provideDataForUserEntityResult + */ + public function testMixedQueryNormalJoin($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'numPhones'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => '2', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => '1', + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInternalType('array', $result); + $this->assertInternalType('array', $result[0]); + $this->assertInternalType('array', $result[1]); + + // first user => 2 phonenumbers + $this->assertEquals(2, $result[0]['numPhones']); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][$userEntityKey]); + + // second user => 1 phonenumber + $this->assertEquals(1, $result[1]['numPhones']); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1][$userEntityKey]); + } + + /** + * SELECT PARTIAL u.{id, status}, PARTIAL p.{phonenumber}, UPPER(u.name) nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * JOIN u.phonenumbers p + * + * @dataProvider provideDataForUserEntityResult + */ + public function testMixedQueryFetchJoin($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'p__phonenumber' => '42', + 'sclr0' => 'ROMANB', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'p__phonenumber' => '43', + 'sclr0' => 'ROMANB', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'p__phonenumber' => '91', + 'sclr0' => 'JWAGE', + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInternalType('array', $result); + $this->assertInternalType('array', $result[0]); + $this->assertInternalType('array', $result[1]); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][$userEntityKey]); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0][$userEntityKey]->phonenumbers); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[0][$userEntityKey]->phonenumbers[0]); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1][$userEntityKey]); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[1][$userEntityKey]->phonenumbers); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[0][$userEntityKey]->phonenumbers[1]); + + // first user => 2 phonenumbers + $this->assertEquals(2, count($result[0][$userEntityKey]->phonenumbers)); + $this->assertEquals('ROMANB', $result[0]['nameUpper']); + + // second user => 1 phonenumber + $this->assertEquals(1, count($result[1][$userEntityKey]->phonenumbers)); + $this->assertEquals('JWAGE', $result[1]['nameUpper']); + + $this->assertEquals(42, $result[0][$userEntityKey]->phonenumbers[0]->phonenumber); + $this->assertEquals(43, $result[0][$userEntityKey]->phonenumbers[1]->phonenumber); + $this->assertEquals(91, $result[1][$userEntityKey]->phonenumbers[0]->phonenumber); + } + + /** + * SELECT u, p, UPPER(u.name) nameUpper + * FROM User u + * INDEX BY u.id + * JOIN u.phonenumbers p + * INDEX BY p.phonenumber + * + * @dataProvider provideDataForUserEntityResult + */ + public function testMixedQueryFetchJoinCustomIndex($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addIndexBy('u', 'id'); + $rsm->addIndexBy('p', 'phonenumber'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91' + ) + ); + + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInternalType('array', $result); + $this->assertInternalType('array', $result[1]); + $this->assertInternalType('array', $result[2]); + + // test the scalar values + $this->assertEquals('ROMANB', $result[1]['nameUpper']); + $this->assertEquals('JWAGE', $result[2]['nameUpper']); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1][$userEntityKey]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[2][$userEntityKey]); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[1][$userEntityKey]->phonenumbers); + + // first user => 2 phonenumbers. notice the custom indexing by user id + $this->assertEquals(2, count($result[1][$userEntityKey]->phonenumbers)); + + // second user => 1 phonenumber. notice the custom indexing by user id + $this->assertEquals(1, count($result[2][$userEntityKey]->phonenumbers)); + + // test the custom indexing of the phonenumbers + $this->assertTrue(isset($result[1][$userEntityKey]->phonenumbers['42'])); + $this->assertTrue(isset($result[1][$userEntityKey]->phonenumbers['43'])); + $this->assertTrue(isset($result[2][$userEntityKey]->phonenumbers['91'])); + } + + /** + * SELECT u, p, UPPER(u.name) nameUpper, a + * FROM User u + * JOIN u.phonenumbers p + * JOIN u.articles a + * + * @dataProvider provideDataForUserEntityResult + */ + public function testMixedQueryMultipleFetchJoin($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsArticle', + 'a', + 'u', + 'articles' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + 'a__id' => '1', + 'a__topic' => 'Getting things done!' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + 'a__id' => '1', + 'a__topic' => 'Getting things done!' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + 'a__id' => '2', + 'a__topic' => 'ZendCon' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + 'a__id' => '2', + 'a__topic' => 'ZendCon' + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91', + 'a__id' => '3', + 'a__topic' => 'LINQ' + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91', + 'a__id' => '4', + 'a__topic' => 'PHP6' + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertTrue(is_array($result)); + $this->assertTrue(is_array($result[0])); + $this->assertTrue(is_array($result[1])); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][$userEntityKey]); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0][$userEntityKey]->phonenumbers); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[0][$userEntityKey]->phonenumbers[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[0][$userEntityKey]->phonenumbers[1]); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0][$userEntityKey]->articles); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[0][$userEntityKey]->articles[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[0][$userEntityKey]->articles[1]); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1][$userEntityKey]); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[1][$userEntityKey]->phonenumbers); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[1][$userEntityKey]->phonenumbers[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[1][$userEntityKey]->articles[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[1][$userEntityKey]->articles[1]); + } + + /** + * SELECT u, p, UPPER(u.name) nameUpper, a, c + * FROM User u + * JOIN u.phonenumbers p + * JOIN u.articles a + * LEFT JOIN a.comments c + * + * @dataProvider provideDataForUserEntityResult + */ + public function testMixedQueryMultipleDeepMixedFetchJoin($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsArticle', + 'a', + 'u', + 'articles' + ); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsComment', + 'c', + 'a', + 'comments' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__topic', 'topic'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + 'a__id' => '1', + 'a__topic' => 'Getting things done!', + 'c__id' => '1', + 'c__topic' => 'First!' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + 'a__id' => '1', + 'a__topic' => 'Getting things done!', + 'c__id' => '1', + 'c__topic' => 'First!' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + 'a__id' => '2', + 'a__topic' => 'ZendCon', + 'c__id' => null, + 'c__topic' => null + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + 'a__id' => '2', + 'a__topic' => 'ZendCon', + 'c__id' => null, + 'c__topic' => null + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91', + 'a__id' => '3', + 'a__topic' => 'LINQ', + 'c__id' => null, + 'c__topic' => null + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91', + 'a__id' => '4', + 'a__topic' => 'PHP6', + 'c__id' => null, + 'c__topic' => null + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertTrue(is_array($result)); + $this->assertTrue(is_array($result[0])); + $this->assertTrue(is_array($result[1])); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][$userEntityKey]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1][$userEntityKey]); + + // phonenumbers + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0][$userEntityKey]->phonenumbers); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[0][$userEntityKey]->phonenumbers[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[0][$userEntityKey]->phonenumbers[1]); + + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[1][$userEntityKey]->phonenumbers); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[1][$userEntityKey]->phonenumbers[0]); + + // articles + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0][$userEntityKey]->articles); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[0][$userEntityKey]->articles[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[0][$userEntityKey]->articles[1]); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[1][$userEntityKey]->articles[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsArticle', $result[1][$userEntityKey]->articles[1]); + + // article comments + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0][$userEntityKey]->articles[0]->comments); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsComment', $result[0][$userEntityKey]->articles[0]->comments[0]); + + // empty comment collections + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0][$userEntityKey]->articles[1]->comments); + $this->assertEquals(0, count($result[0][$userEntityKey]->articles[1]->comments)); + + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[1][$userEntityKey]->articles[0]->comments); + $this->assertEquals(0, count($result[1][$userEntityKey]->articles[0]->comments)); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[1][$userEntityKey]->articles[1]->comments); + $this->assertEquals(0, count($result[1][$userEntityKey]->articles[1]->comments)); + } + + /** + * Tests that the hydrator does not rely on a particular order of the rows + * in the result set. + * + * DQL: + * select c, b from Doctrine\Tests\Models\Forum\ForumCategory c inner join c.boards b + * order by c.position asc, b.position asc + * + * Checks whether the boards are correctly assigned to the categories. + * + * The 'evil' result set that confuses the object population is displayed below. + * + * c.id | c.position | c.name | boardPos | b.id | b.category_id (just for clarity) + * 1 | 0 | First | 0 | 1 | 1 + * 2 | 0 | Second | 0 | 2 | 2 <-- + * 1 | 0 | First | 1 | 3 | 1 + * 1 | 0 | First | 2 | 4 | 1 + */ + public function testEntityQueryCustomResultSetOrder() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\Forum\ForumCategory', 'c'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\Forum\ForumBoard', + 'b', + 'c', + 'boards' + ); + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__position', 'position'); + $rsm->addFieldResult('c', 'c__name', 'name'); + $rsm->addFieldResult('b', 'b__id', 'id'); + $rsm->addFieldResult('b', 'b__position', 'position'); + + // Faked result set + $resultSet = array( + array( + 'c__id' => '1', + 'c__position' => '0', + 'c__name' => 'First', + 'b__id' => '1', + 'b__position' => '0', + //'b__category_id' => '1' + ), + array( + 'c__id' => '2', + 'c__position' => '0', + 'c__name' => 'Second', + 'b__id' => '2', + 'b__position' => '0', + //'b__category_id' => '2' + ), + array( + 'c__id' => '1', + 'c__position' => '0', + 'c__name' => 'First', + 'b__id' => '3', + 'b__position' => '1', + //'b__category_id' => '1' + ), + array( + 'c__id' => '1', + 'c__position' => '0', + 'c__name' => 'First', + 'b__id' => '4', + 'b__position' => '2', + //'b__category_id' => '1' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInstanceOf('Doctrine\Tests\Models\Forum\ForumCategory', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\Forum\ForumCategory', $result[1]); + + $this->assertTrue($result[0] !== $result[1]); + + $this->assertEquals(1, $result[0]->getId()); + $this->assertEquals(2, $result[1]->getId()); + + $this->assertTrue(isset($result[0]->boards)); + $this->assertEquals(3, count($result[0]->boards)); + + $this->assertTrue(isset($result[1]->boards)); + $this->assertEquals(1, count($result[1]->boards)); + } + + /** + * SELECT PARTIAL u.{id,name} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * + * @group DDC-644 + */ + public function testSkipUnknownColumns() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'foo' => 'bar', // unknown! + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + } + + /** + * SELECT u.id, u.name + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * + * @dataProvider provideDataForUserEntityResult + */ + public function testScalarQueryWithoutResultVariables($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addScalarResult('sclr0', 'id'); + $rsm->addScalarResult('sclr1', 'name'); + + // Faked result set + $resultSet = array( + array( + 'sclr0' => '1', + 'sclr1' => 'romanb' + ), + array( + 'sclr0' => '2', + 'sclr1' => 'jwage' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInternalType('array', $result[0]); + $this->assertInternalType('array', $result[1]); + + $this->assertEquals(1, $result[0]['id']); + $this->assertEquals('romanb', $result[0]['name']); + + $this->assertEquals(2, $result[1]['id']); + $this->assertEquals('jwage', $result[1]['name']); + } + + /** + * SELECT p + * FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p + */ + public function testCreatesProxyForLazyLoadingWithForeignKeys() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\ECommerce\ECommerceProduct', 'p'); + $rsm->addFieldResult('p', 'p__id', 'id'); + $rsm->addFieldResult('p', 'p__name', 'name'); + $rsm->addMetaResult('p', 'p__shipping_id', 'shipping_id'); + + // Faked result set + $resultSet = array( + array( + 'p__id' => '1', + 'p__name' => 'Doctrine Book', + 'p__shipping_id' => 42 + ) + ); + + $proxyInstance = new \Doctrine\Tests\Models\ECommerce\ECommerceShipping(); + + // mocking the proxy factory + $proxyFactory = $this->getMock('Doctrine\ORM\Proxy\ProxyFactory', array('getProxy'), array(), '', false, false, false); + $proxyFactory->expects($this->once()) + ->method('getProxy') + ->with($this->equalTo('Doctrine\Tests\Models\ECommerce\ECommerceShipping'), array('id' => 42)) + ->will($this->returnValue($proxyInstance)); + + $this->_em->setProxyFactory($proxyFactory); + + // configuring lazy loading + $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct'); + $metadata->associationMappings['shipping']['fetch'] = ClassMetadata::FETCH_LAZY; + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(1, count($result)); + + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $result[0]); + } + + /** + * SELECT p AS product + * FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p + */ + public function testCreatesProxyForLazyLoadingWithForeignKeysWithAliasedProductEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\ECommerce\ECommerceProduct', 'p', 'product'); + $rsm->addFieldResult('p', 'p__id', 'id'); + $rsm->addFieldResult('p', 'p__name', 'name'); + $rsm->addMetaResult('p', 'p__shipping_id', 'shipping_id'); + + // Faked result set + $resultSet = array( + array( + 'p__id' => '1', + 'p__name' => 'Doctrine Book', + 'p__shipping_id' => 42 + ) + ); + + $proxyInstance = new \Doctrine\Tests\Models\ECommerce\ECommerceShipping(); + + // mocking the proxy factory + $proxyFactory = $this->getMock('Doctrine\ORM\Proxy\ProxyFactory', array('getProxy'), array(), '', false, false, false); + $proxyFactory->expects($this->once()) + ->method('getProxy') + ->with($this->equalTo('Doctrine\Tests\Models\ECommerce\ECommerceShipping'), array('id' => 42)) + ->will($this->returnValue($proxyInstance)); + + $this->_em->setProxyFactory($proxyFactory); + + // configuring lazy loading + $metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct'); + $metadata->associationMappings['shipping']['fetch'] = ClassMetadata::FETCH_LAZY; + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertEquals(1, count($result)); + + $this->assertInternalType('array', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $result[0]['product']); + } + + /** + * SELECT PARTIAL u.{id, status}, PARTIAL a.{id, topic}, PARTIAL c.{id, topic} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * LEFT JOIN u.articles a + * LEFT JOIN a.comments c + */ + public function testChainedJoinWithEmptyCollections() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsArticle', + 'a', + 'u', + 'articles' + ); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsComment', + 'c', + 'a', + 'comments' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__topic', 'topic'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'a__id' => null, + 'a__topic' => null, + 'c__id' => null, + 'c__topic' => null + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'a__id' => null, + 'a__topic' => null, + 'c__id' => null, + 'c__topic' => null + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1]); + + $this->assertEquals(0, $result[0]->articles->count()); + $this->assertEquals(0, $result[1]->articles->count()); + } + + /** + * SELECT PARTIAL u.{id, status} AS user, PARTIAL a.{id, topic}, PARTIAL c.{id, topic} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * LEFT JOIN u.articles a + * LEFT JOIN a.comments c + */ + public function testChainedJoinWithEmptyCollectionsWithAliasedUserEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsArticle', + 'a', + 'u', + 'articles' + ); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsComment', + 'c', + 'a', + 'comments' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__topic', 'topic'); + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addFieldResult('c', 'c__topic', 'topic'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'a__id' => null, + 'a__topic' => null, + 'c__id' => null, + 'c__topic' => null + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'a__id' => null, + 'a__topic' => null, + 'c__id' => null, + 'c__topic' => null + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInternalType('array', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]['user']); + + $this->assertInternalType('array', $result[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1]['user']); + + $this->assertEquals(0, $result[0]['user']->articles->count()); + $this->assertEquals(0, $result[1]['user']->articles->count()); + } + + /** + * SELECT PARTIAL u.{id,status}, a.id, a.topic, c.id as cid, c.topic as ctopic + * FROM CmsUser u + * LEFT JOIN u.articles a + * LEFT JOIN a.comments c + * + * @group bubu + * @dataProvider provideDataForUserEntityResult + */ + /*public function testChainedJoinWithScalars($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('a__id', 'id'); + $rsm->addScalarResult('a__topic', 'topic'); + $rsm->addScalarResult('c__id', 'cid'); + $rsm->addScalarResult('c__topic', 'ctopic'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'a__id' => '1', + 'a__topic' => 'The First', + 'c__id' => '1', + 'c__topic' => 'First Comment' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'a__id' => '1', + 'a__topic' => 'The First', + 'c__id' => '2', + 'c__topic' => 'Second Comment' + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'a__id' => '42', + 'a__topic' => 'The Answer', + 'c__id' => null, + 'c__topic' => null + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + \Doctrine\Common\Util\Debug::dump($result, 3); + + $this->assertEquals(1, count($result)); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][$userEntityKey]); // User object + $this->assertEquals(42, $result[0]['id']); + $this->assertEquals('The First', $result[0]['topic']); + $this->assertEquals(1, $result[0]['cid']); + $this->assertEquals('First Comment', $result[0]['ctopic']); + }*/ + + /** + * SELECT PARTIAL u.{id, name} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + */ + public function testResultIteration() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $iterableResult = $hydrator->iterate($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + $rowNum = 0; + + while (($row = $iterableResult->next()) !== false) { + $this->assertEquals(1, count($row)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $row[0]); + + if ($rowNum == 0) { + $this->assertEquals(1, $row[0]->id); + $this->assertEquals('romanb', $row[0]->name); + } else if ($rowNum == 1) { + $this->assertEquals(2, $row[0]->id); + $this->assertEquals('jwage', $row[0]->name); + } + + ++$rowNum; + } + } + + /** + * SELECT PARTIAL u.{id, name} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + */ + public function testResultIterationWithAliasedUserEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage' + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $iterableResult = $hydrator->iterate($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + $rowNum = 0; + + while (($row = $iterableResult->next()) !== false) { + $this->assertEquals(1, count($row)); + $this->assertArrayHasKey(0, $row); + $this->assertArrayHasKey('user', $row[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $row[0]['user']); + + if ($rowNum == 0) { + $this->assertEquals(1, $row[0]['user']->id); + $this->assertEquals('romanb', $row[0]['user']->name); + } else if ($rowNum == 1) { + $this->assertEquals(2, $row[0]['user']->id); + $this->assertEquals('jwage', $row[0]['user']->name); + } + + ++$rowNum; + } + } + + /** + * Checks if multiple joined multiple-valued collections is hydrated correctly. + * + * SELECT PARTIAL u.{id, status}, PARTIAL g.{id, name}, PARTIAL p.{phonenumber} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * + * @group DDC-809 + */ + public function testManyToManyHydration() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsGroup', 'g', 'u', 'groups'); + $rsm->addFieldResult('g', 'g__id', 'id'); + $rsm->addFieldResult('g', 'g__name', 'name'); + $rsm->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p', 'u', 'phonenumbers'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'g__id' => '3', + 'g__name' => 'TestGroupB', + 'p__phonenumber' => 1111, + ), + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'g__id' => '5', + 'g__name' => 'TestGroupD', + 'p__phonenumber' => 1111, + ), + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'g__id' => '3', + 'g__name' => 'TestGroupB', + 'p__phonenumber' => 2222, + ), + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'g__id' => '5', + 'g__name' => 'TestGroupD', + 'p__phonenumber' => 2222, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '2', + 'g__name' => 'TestGroupA', + 'p__phonenumber' => 3333, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '3', + 'g__name' => 'TestGroupB', + 'p__phonenumber' => 3333, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '4', + 'g__name' => 'TestGroupC', + 'p__phonenumber' => 3333, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '5', + 'g__name' => 'TestGroupD', + 'p__phonenumber' => 3333, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '2', + 'g__name' => 'TestGroupA', + 'p__phonenumber' => 4444, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '3', + 'g__name' => 'TestGroupB', + 'p__phonenumber' => 4444, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '4', + 'g__name' => 'TestGroupC', + 'p__phonenumber' => 4444, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '5', + 'g__name' => 'TestGroupD', + 'p__phonenumber' => 4444, + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsUser', $result); + + $this->assertEquals(2, count($result[0]->groups)); + $this->assertEquals(2, count($result[0]->phonenumbers)); + + $this->assertEquals(4, count($result[1]->groups)); + $this->assertEquals(2, count($result[1]->phonenumbers)); + } + + /** + * Checks if multiple joined multiple-valued collections is hydrated correctly. + * + * SELECT PARTIAL u.{id, status} As user, PARTIAL g.{id, name}, PARTIAL p.{phonenumber} + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * + * @group DDC-809 + */ + public function testManyToManyHydrationWithAliasedUserEntity() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', 'user'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsGroup', 'g', 'u', 'groups'); + $rsm->addFieldResult('g', 'g__id', 'id'); + $rsm->addFieldResult('g', 'g__name', 'name'); + $rsm->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p', 'u', 'phonenumbers'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'g__id' => '3', + 'g__name' => 'TestGroupB', + 'p__phonenumber' => 1111, + ), + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'g__id' => '5', + 'g__name' => 'TestGroupD', + 'p__phonenumber' => 1111, + ), + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'g__id' => '3', + 'g__name' => 'TestGroupB', + 'p__phonenumber' => 2222, + ), + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'g__id' => '5', + 'g__name' => 'TestGroupD', + 'p__phonenumber' => 2222, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '2', + 'g__name' => 'TestGroupA', + 'p__phonenumber' => 3333, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '3', + 'g__name' => 'TestGroupB', + 'p__phonenumber' => 3333, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '4', + 'g__name' => 'TestGroupC', + 'p__phonenumber' => 3333, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '5', + 'g__name' => 'TestGroupD', + 'p__phonenumber' => 3333, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '2', + 'g__name' => 'TestGroupA', + 'p__phonenumber' => 4444, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '3', + 'g__name' => 'TestGroupB', + 'p__phonenumber' => 4444, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '4', + 'g__name' => 'TestGroupC', + 'p__phonenumber' => 4444, + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage', + 'g__id' => '5', + 'g__name' => 'TestGroupD', + 'p__phonenumber' => 4444, + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInternalType('array', $result[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]['user']); + $this->assertInternalType('array', $result[1]); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1]['user']); + + $this->assertEquals(2, count($result[0]['user']->groups)); + $this->assertEquals(2, count($result[0]['user']->phonenumbers)); + + $this->assertEquals(4, count($result[1]['user']->groups)); + $this->assertEquals(2, count($result[1]['user']->phonenumbers)); + } + + /** + * SELECT PARTIAL u.{id, status}, UPPER(u.name) as nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * + * @group DDC-1358 + * @dataProvider provideDataForUserEntityResult + */ + public function testMissingIdForRootEntity($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + ), + array( + 'u__id' => null, + 'u__status' => null, + 'sclr0' => 'ROMANB', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + ), + array( + 'u__id' => null, + 'u__status' => null, + 'sclr0' => 'JWAGE', + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(4, count($result), "Should hydrate four results."); + + $this->assertEquals('ROMANB', $result[0]['nameUpper']); + $this->assertEquals('ROMANB', $result[1]['nameUpper']); + $this->assertEquals('JWAGE', $result[2]['nameUpper']); + $this->assertEquals('JWAGE', $result[3]['nameUpper']); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][$userEntityKey]); + $this->assertNull($result[1][$userEntityKey]); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[2][$userEntityKey]); + $this->assertNull($result[3][$userEntityKey]); + } + + /** + * SELECT PARTIAL u.{id, status}, PARTIAL p.{phonenumber}, UPPER(u.name) AS nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * LEFT JOIN u.phonenumbers u + * + * @group DDC-1358 + * @dataProvider provideDataForUserEntityResult + */ + public function testMissingIdForCollectionValuedChildEntity($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => null + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91' + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => null + ) + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertEquals(1, $result[0][$userEntityKey]->phonenumbers->count()); + $this->assertEquals(1, $result[1][$userEntityKey]->phonenumbers->count()); + } + + /** + * SELECT PARTIAL u.{id, status}, PARTIAL a.{id, city}, UPPER(u.name) AS nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * JOIN u.address a + * + * @group DDC-1358 + * @dataProvider provideDataForUserEntityResult + */ + public function testMissingIdForSingleValuedChildEntity($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsAddress', + 'a', + 'u', + 'address' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('a', 'a__id', 'id'); + $rsm->addFieldResult('a', 'a__city', 'city'); + $rsm->addMetaResult('a', 'user_id', 'user_id'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + 'a__id' => 1, + 'a__city' => 'Berlin', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'BENJAMIN', + 'a__id' => null, + 'a__city' => null, + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $result[0][$userEntityKey]->address); + $this->assertNull($result[1][$userEntityKey]->address); + } + + /** + * SELECT PARTIAL u.{id, status}, UPPER(u.name) AS nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * INDEX BY u.id + * + * @group DDC-1385 + * @dataProvider provideDataForUserEntityResult + */ + public function testIndexByAndMixedResult($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addIndexBy('u', 'id'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'sclr0' => 'ROMANB', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'sclr0' => 'JWAGE', + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals(2, count($result)); + + $this->assertTrue(isset($result[1])); + $this->assertEquals(1, $result[1][$userEntityKey]->id); + + $this->assertTrue(isset($result[2])); + $this->assertEquals(2, $result[2][$userEntityKey]->id); + } + + /** + * SELECT UPPER(u.name) AS nameUpper + * FROM Doctrine\Tests\Models\CMS\CmsUser u + * + * @group DDC-1385 + * @dataProvider provideDataForUserEntityResult + */ + public function testIndexByScalarsOnly($userEntityKey) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u', $userEntityKey ?: null); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addIndexByScalar('sclr0'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'sclr0' => 'ROMANB', + ), + array( + 'sclr0' => 'JWAGE', + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + + $this->assertEquals( + array( + 'ROMANB' => array('nameUpper' => 'ROMANB'), + 'JWAGE' => array('nameUpper' => 'JWAGE') + ), + $result + ); + } + + + /** + * @group DDC-1470 + * + * @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException + * @expectedExceptionMessage The meta mapping for the discriminator column "c_discr" is missing for "Doctrine\Tests\Models\Company\CompanyFixContract" using the DQL alias "c". + */ + public function testMissingMetaMappingException() + { + $rsm = new ResultSetMapping; + + $rsm->addEntityResult('Doctrine\Tests\Models\Company\CompanyFixContract', 'c'); + $rsm->addJoinedEntityResult('Doctrine\Tests\Models\Company\CompanyEmployee', 'e', 'c', 'salesPerson'); + + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->setDiscriminatorColumn('c', 'c_discr'); + + $resultSet = array( + array( + 'c__id' => '1', + 'c_discr' => 'fix', + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $hydrator->hydrateAll($stmt, $rsm); + } + + /** + * @group DDC-1470 + * + * @expectedException \Doctrine\ORM\Internal\Hydration\HydrationException + * @expectedExceptionMessage The discriminator column "discr" is missing for "Doctrine\Tests\Models\Company\CompanyEmployee" using the DQL alias "e". + */ + public function testMissingDiscriminatorColumnException() + { + $rsm = new ResultSetMapping; + + $rsm->addEntityResult('Doctrine\Tests\Models\Company\CompanyFixContract', 'c'); + $rsm->addJoinedEntityResult('Doctrine\Tests\Models\Company\CompanyEmployee', 'e', 'c', 'salesPerson'); + + $rsm->addFieldResult('c', 'c__id', 'id'); + $rsm->addMetaResult('c', 'c_discr', 'discr'); + $rsm->setDiscriminatorColumn('c', 'c_discr'); + + $rsm->addFieldResult('e', 'e__id', 'id'); + $rsm->addFieldResult('e', 'e__name', 'name'); + $rsm->addMetaResult('e ', 'e_discr', 'discr'); + $rsm->setDiscriminatorColumn('e', 'e_discr'); + + $resultSet = array( + array( + 'c__id' => '1', + 'c_discr' => 'fix', + 'e__id' => '1', + 'e__name' => 'Fabio B. Silva' + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + $hydrator->hydrateAll($stmt, $rsm); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php new file mode 100644 index 0000000..801937f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php @@ -0,0 +1,259 @@ +_rsm = new ResultSetMapping; + $this->_em = $this->_getTestEntityManager(); + } + + /** + * For SQL: SELECT id, status, username, name FROM cms_users + */ + public function testBasicResultSetMapping() + { + $this->_rsm->addEntityResult( + 'Doctrine\Tests\Models\CMS\CmsUser', + 'u' + ); + $this->_rsm->addFieldResult('u', 'id', 'id'); + $this->_rsm->addFieldResult('u', 'status', 'status'); + $this->_rsm->addFieldResult('u', 'username', 'username'); + $this->_rsm->addFieldResult('u', 'name', 'name'); + + $this->assertFalse($this->_rsm->isScalarResult('id')); + $this->assertFalse($this->_rsm->isScalarResult('status')); + $this->assertFalse($this->_rsm->isScalarResult('username')); + $this->assertFalse($this->_rsm->isScalarResult('name')); + + $this->assertTrue($this->_rsm->getClassName('u') == 'Doctrine\Tests\Models\CMS\CmsUser'); + $class = $this->_rsm->getDeclaringClass('id'); + $this->assertTrue($class == 'Doctrine\Tests\Models\CMS\CmsUser'); + + $this->assertEquals('u', $this->_rsm->getEntityAlias('id')); + $this->assertEquals('u', $this->_rsm->getEntityAlias('status')); + $this->assertEquals('u', $this->_rsm->getEntityAlias('username')); + $this->assertEquals('u', $this->_rsm->getEntityAlias('name')); + + $this->assertEquals('id', $this->_rsm->getFieldName('id')); + $this->assertEquals('status', $this->_rsm->getFieldName('status')); + $this->assertEquals('username', $this->_rsm->getFieldName('username')); + $this->assertEquals('name', $this->_rsm->getFieldName('name')); + } + + /** + * @group DDC-1057 + * + * Fluent interface test, not a real result set mapping + */ + public function testFluentInterface() + { + $rms = $this->_rsm; + + $rms->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser','u') + ->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsPhonenumber','p','u','phonenumbers') + ->addFieldResult('u', 'id', 'id') + ->addFieldResult('u', 'name', 'name') + ->setDiscriminatorColumn('name', 'name') + ->addIndexByColumn('id', 'id') + ->addIndexBy('username', 'username') + ->addIndexByScalar('sclr0') + ->addScalarResult('sclr0', 'numPhones') + ->addMetaResult('a', 'user_id', 'user_id'); + + + $this->assertTrue($rms->hasIndexBy('id')); + $this->assertTrue($rms->isFieldResult('id')); + $this->assertTrue($rms->isFieldResult('name')); + $this->assertTrue($rms->isScalarResult('sclr0')); + $this->assertTrue($rms->isRelation('p')); + $this->assertTrue($rms->hasParentAlias('p')); + $this->assertTrue($rms->isMixedResult()); + } + + /** + * @group DDC-1663 + */ + public function testAddNamedNativeQueryResultSetMapping() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->mapOneToOne(array( + 'fieldName' => 'email', + 'targetEntity' => 'Doctrine\Tests\Models\CMS\CmsEmail', + 'cascade' => array('persist'), + 'inversedBy' => 'user', + 'orphanRemoval' => false, + 'joinColumns' => array(array( + 'nullable' => true, + 'referencedColumnName' => 'id', + ) + ) + )); + + $cm->addNamedNativeQuery(array( + 'name' => 'find-all', + 'query' => 'SELECT u.id AS user_id, e.id AS email_id, u.name, e.email, u.id + e.id AS scalarColumn FROM cms_users u INNER JOIN cms_emails e ON e.id = u.email_id', + 'resultSetMapping' => 'find-all', + )); + $cm->addSqlResultSetMapping(array( + 'name' => 'find-all', + 'entities' => array( + array( + 'entityClass' => '__CLASS__', + 'fields' => array( + array( + 'name' => 'id', + 'column'=> 'user_id' + ), + array( + 'name' => 'name', + 'column'=> 'name' + ) + ) + ), + array( + 'entityClass' => 'CmsEmail', + 'fields' => array( + array( + 'name' => 'id', + 'column'=> 'email_id' + ), + array( + 'name' => 'email', + 'column'=> 'email' + ) + ) + ) + ), + 'columns' => array( + array( + 'name' => 'scalarColumn' + ) + ) + )); + + + $queryMapping = $cm->getNamedNativeQuery('find-all'); + + $rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->_em); + $rsm->addNamedNativeQueryMapping($cm, $queryMapping); + + $this->assertEquals('scalarColumn', $rsm->getScalarAlias('scalarColumn')); + + $this->assertEquals('c0', $rsm->getEntityAlias('user_id')); + $this->assertEquals('c0', $rsm->getEntityAlias('name')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getClassName('c0')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('name')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('user_id')); + + + $this->assertEquals('c1', $rsm->getEntityAlias('email_id')); + $this->assertEquals('c1', $rsm->getEntityAlias('email')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsEmail', $rsm->getClassName('c1')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsEmail', $rsm->getDeclaringClass('email')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsEmail', $rsm->getDeclaringClass('email_id')); + } + + /** + * @group DDC-1663 + */ + public function testAddNamedNativeQueryResultSetMappingWithoutFields() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->addNamedNativeQuery(array( + 'name' => 'find-all', + 'query' => 'SELECT u.id AS user_id, e.id AS email_id, u.name, e.email, u.id + e.id AS scalarColumn FROM cms_users u INNER JOIN cms_emails e ON e.id = u.email_id', + 'resultSetMapping' => 'find-all', + )); + $cm->addSqlResultSetMapping(array( + 'name' => 'find-all', + 'entities' => array( + array( + 'entityClass' => '__CLASS__', + ) + ), + 'columns' => array( + array( + 'name' => 'scalarColumn' + ) + ) + )); + + + $queryMapping = $cm->getNamedNativeQuery('find-all'); + + $rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->_em); + $rsm->addNamedNativeQueryMapping($cm, $queryMapping); + + $this->assertEquals('scalarColumn', $rsm->getScalarAlias('scalarColumn')); + + $this->assertEquals('c0', $rsm->getEntityAlias('id')); + $this->assertEquals('c0', $rsm->getEntityAlias('name')); + $this->assertEquals('c0', $rsm->getEntityAlias('status')); + $this->assertEquals('c0', $rsm->getEntityAlias('username')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getClassName('c0')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('id')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('name')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('status')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('username')); + } + + /** + * @group DDC-1663 + */ + public function testAddNamedNativeQueryResultClass() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->addNamedNativeQuery(array( + 'name' => 'find-all', + 'resultClass' => '__CLASS__', + 'query' => 'SELECT * FROM cms_users', + )); + + $queryMapping = $cm->getNamedNativeQuery('find-all'); + + $rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->_em); + $rsm->addNamedNativeQueryMapping($cm, $queryMapping); + + + $this->assertEquals('c0', $rsm->getEntityAlias('id')); + $this->assertEquals('c0', $rsm->getEntityAlias('name')); + $this->assertEquals('c0', $rsm->getEntityAlias('status')); + $this->assertEquals('c0', $rsm->getEntityAlias('username')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getClassName('c0')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('id')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('name')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('status')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $rsm->getDeclaringClass('username')); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ScalarHydratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ScalarHydratorTest.php new file mode 100644 index 0000000..c8c376f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/ScalarHydratorTest.php @@ -0,0 +1,101 @@ +addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ), + array( + 'u__id' => '2', + 'u__name' => 'jwage' + ) + ); + + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this->_em); + + $result = $hydrator->hydrateAll($stmt, $rsm); + + $this->assertTrue(is_array($result)); + $this->assertEquals(2, count($result)); + $this->assertEquals('romanb', $result[0]['u_name']); + $this->assertEquals(1, $result[0]['u_id']); + $this->assertEquals('jwage', $result[1]['u_name']); + $this->assertEquals(2, $result[1]['u_id']); + } + + /** + * @group DDC-407 + */ + public function testHydrateScalarResults() + { + $rsm = new ResultSetMapping(); + $rsm->addScalarResult('foo1', 'foo'); + $rsm->addScalarResult('bar2', 'bar'); + $rsm->addScalarResult('baz3', 'baz'); + + $resultSet = array( + array( + 'foo1' => 'A', + 'bar2' => 'B', + 'baz3' => 'C', + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this->_em); + + $result = $hydrator->hydrateAll($stmt, $rsm); + } + + /** + * @group DDC-644 + */ + public function testSkipUnknownColumns() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addScalarResult('foo1', 'foo'); + $rsm->addScalarResult('bar2', 'bar'); + $rsm->addScalarResult('baz3', 'baz'); + + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'romanb', + 'foo1' => 'A', + 'bar2' => 'B', + 'baz3' => 'C', + 'foo' => 'bar', // Unknown! + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this->_em); + + $result = $hydrator->hydrateAll($stmt, $rsm); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/SimpleObjectHydratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/SimpleObjectHydratorTest.php new file mode 100644 index 0000000..80f90e7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/SimpleObjectHydratorTest.php @@ -0,0 +1,37 @@ +addEntityResult('Doctrine\Tests\Models\Company\CompanyPerson', 'p'); + $rsm->addFieldResult('p', 'p__id', 'id'); + $rsm->addFieldResult('p', 'p__name', 'name'); + $rsm->addMetaResult('p ', 'discr', 'discr'); + $rsm->setDiscriminatorColumn('p', 'discr'); + $resultSet = array( + array( + 'u__id' => '1', + 'u__name' => 'Fabio B. Silva' + ), + ); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\SimpleObjectHydrator($this->_em); + $hydrator->hydrateAll($stmt, $rsm); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/SingleScalarHydratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/SingleScalarHydratorTest.php new file mode 100644 index 0000000..f6abe24 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Hydration/SingleScalarHydratorTest.php @@ -0,0 +1,78 @@ + 'result1', + 'resultSet' => array( + array( + 'u__name' => 'romanb' + ) + )), + // valid + array('name' => 'result2', + 'resultSet' => array( + array( + 'u__id' => '1' + ) + )), + // invalid + array('name' => 'result3', + 'resultSet' => array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ) + )), + // invalid + array('name' => 'result4', + 'resultSet' => array( + array( + 'u__id' => '1' + ), + array( + 'u__id' => '2' + ) + )), + ); + } + + /** + * select u.name from CmsUser u where u.id = 1 + * + * @dataProvider singleScalarResultSetProvider + */ + public function testHydrateSingleScalar($name, $resultSet) + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\SingleScalarHydrator($this->_em); + + if ($name == 'result1') { + $result = $hydrator->hydrateAll($stmt, $rsm); + $this->assertEquals('romanb', $result); + } else if ($name == 'result2') { + $result = $hydrator->hydrateAll($stmt, $rsm); + $this->assertEquals(1, $result); + } else if ($name == 'result3' || $name == 'result4') { + try { + $result = $hydrator->hydrateAll($stmt, $rsm); + $this->fail(); + } catch (\Doctrine\ORM\NonUniqueResultException $e) {} + } + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Id/AssignedGeneratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Id/AssignedGeneratorTest.php new file mode 100644 index 0000000..3a009e5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Id/AssignedGeneratorTest.php @@ -0,0 +1,67 @@ +_em = $this->_getTestEntityManager(); + $this->_assignedGen = new AssignedGenerator; + } + + public function testThrowsExceptionIfIdNotAssigned() + { + try { + $entity = new AssignedSingleIdEntity; + $this->_assignedGen->generate($this->_em, $entity); + $this->fail('Assigned generator did not throw exception even though ID was missing.'); + } catch (\Doctrine\ORM\ORMException $expected) {} + + try { + $entity = new AssignedCompositeIdEntity; + $this->_assignedGen->generate($this->_em, $entity); + $this->fail('Assigned generator did not throw exception even though ID was missing.'); + } catch (\Doctrine\ORM\ORMException $expected) {} + } + + public function testCorrectIdGeneration() + { + $entity = new AssignedSingleIdEntity; + $entity->myId = 1; + $id = $this->_assignedGen->generate($this->_em, $entity); + $this->assertEquals(array('myId' => 1), $id); + + $entity = new AssignedCompositeIdEntity; + $entity->myId2 = 2; + $entity->myId1 = 4; + $id = $this->_assignedGen->generate($this->_em, $entity); + $this->assertEquals(array('myId1' => 4, 'myId2' => 2), $id); + } +} + +/** @Entity */ +class AssignedSingleIdEntity { + /** @Id @Column(type="integer") */ + public $myId; +} + +/** @Entity */ +class AssignedCompositeIdEntity { + /** @Id @Column(type="integer") */ + public $myId1; + /** @Id @Column(type="integer") */ + public $myId2; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Id/SequenceGeneratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Id/SequenceGeneratorTest.php new file mode 100644 index 0000000..6e50d5a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Id/SequenceGeneratorTest.php @@ -0,0 +1,40 @@ +_em = $this->_getTestEntityManager(); + $this->_seqGen = new SequenceGenerator('seq', 10); + } + + public function testGeneration() + { + for ($i=0; $i < 42; ++$i) { + if ($i % 10 == 0) { + $this->_em->getConnection()->setFetchOneResult((int)($i / 10) * 10); + } + $id = $this->_seqGen->generate($this->_em, null); + $this->assertEquals($i, $id); + $this->assertEquals((int)($i / 10) * 10 + 10, $this->_seqGen->getCurrentMaxValue()); + $this->assertEquals($i + 1, $this->_seqGen->getNextValue()); + } + + + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php new file mode 100644 index 0000000..fb8525e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -0,0 +1,1078 @@ +_loadDriver(); + + $class = new ClassMetadata($entityClassName); + $class->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $mappingDriver->loadMetadataForClass($entityClassName, $class); + + return $class; + } + + /** + * @param \Doctrine\ORM\EntityManager $entityClassName + * @return \Doctrine\ORM\Mapping\ClassMetadataFactory + */ + protected function createClassMetadataFactory(\Doctrine\ORM\EntityManager $em = null) + { + $driver = $this->_loadDriver(); + $em = $em ?: $this->_getTestEntityManager(); + $factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + $em->getConfiguration()->setMetadataDriverImpl($driver); + $factory->setEntityManager($em); + + return $factory; + } + + public function testLoadMapping() + { + $entityClassName = 'Doctrine\Tests\ORM\Mapping\User'; + return $this->createClassMetadata($entityClassName); + } + + /** + * @depends testLoadMapping + * @param ClassMetadata $class + */ + public function testEntityTableNameAndInheritance($class) + { + $this->assertEquals('cms_users', $class->getTableName()); + $this->assertEquals(ClassMetadata::INHERITANCE_TYPE_NONE, $class->inheritanceType); + + return $class; + } + + /** + * @depends testEntityTableNameAndInheritance + * @param ClassMetadata $class + */ + public function testEntityIndexes($class) + { + $this->assertArrayHasKey('indexes', $class->table, 'ClassMetadata should have indexes key in table property.'); + $this->assertEquals(array( + 'name_idx' => array('columns' => array('name')), + 0 => array('columns' => array('user_email')) + ), $class->table['indexes']); + + return $class; + } + + /** + * @depends testEntityTableNameAndInheritance + * @param ClassMetadata $class + */ + public function testEntityUniqueConstraints($class) + { + $this->assertArrayHasKey('uniqueConstraints', $class->table, + 'ClassMetadata should have uniqueConstraints key in table property when Unique Constraints are set.'); + + $this->assertEquals(array( + "search_idx" => array("columns" => array("name", "user_email")) + ), $class->table['uniqueConstraints']); + + return $class; + } + + /** + * @depends testEntityTableNameAndInheritance + * @param ClassMetadata $class + */ + public function testEntityOptions($class) + { + $this->assertArrayHasKey('options', $class->table, 'ClassMetadata should have options key in table property.'); + + $this->assertEquals(array( + 'foo' => 'bar', 'baz' => array('key' => 'val') + ), $class->table['options']); + + return $class; + } + + /** + * @depends testEntityOptions + * @param ClassMetadata $class + */ + public function testEntitySequence($class) + { + $this->assertInternalType('array', $class->sequenceGeneratorDefinition, 'No Sequence Definition set on this driver.'); + $this->assertEquals( + array( + 'sequenceName' => 'tablename_seq', + 'allocationSize' => 100, + 'initialValue' => 1, + ), + $class->sequenceGeneratorDefinition + ); + } + + public function testEntityCustomGenerator() + { + $class = $this->createClassMetadata('Doctrine\Tests\ORM\Mapping\Animal'); + + $this->assertEquals(ClassMetadata::GENERATOR_TYPE_CUSTOM, + $class->generatorType, "Generator Type"); + $this->assertEquals( + array("class" => "stdClass"), + $class->customGeneratorDefinition, + "Custom Generator Definition"); + } + + + /** + * @depends testEntityTableNameAndInheritance + * @param ClassMetadata $class + */ + public function testFieldMappings($class) + { + $this->assertEquals(3, count($class->fieldMappings)); + $this->assertTrue(isset($class->fieldMappings['id'])); + $this->assertTrue(isset($class->fieldMappings['name'])); + $this->assertTrue(isset($class->fieldMappings['email'])); + + return $class; + } + + /** + * @depends testEntityTableNameAndInheritance + * @param ClassMetadata $class + */ + public function testFieldMappingsColumnNames($class) + { + $this->assertEquals("id", $class->fieldMappings['id']['columnName']); + $this->assertEquals("name", $class->fieldMappings['name']['columnName']); + $this->assertEquals("user_email", $class->fieldMappings['email']['columnName']); + + return $class; + } + + /** + * @depends testEntityTableNameAndInheritance + * @param ClassMetadata $class + */ + public function testStringFieldMappings($class) + { + $this->assertEquals('string', $class->fieldMappings['name']['type']); + $this->assertEquals(50, $class->fieldMappings['name']['length']); + $this->assertTrue($class->fieldMappings['name']['nullable']); + $this->assertTrue($class->fieldMappings['name']['unique']); + + $expected = array('foo' => 'bar', 'baz' => array('key' => 'val')); + $this->assertEquals($expected, $class->fieldMappings['name']['options']); + + return $class; + } + + /** + * @depends testFieldMappings + * @param ClassMetadata $class + */ + public function testIdentifier($class) + { + $this->assertEquals(array('id'), $class->identifier); + $this->assertEquals('integer', $class->fieldMappings['id']['type']); + $this->assertEquals(ClassMetadata::GENERATOR_TYPE_AUTO, $class->generatorType, "ID-Generator is not ClassMetadata::GENERATOR_TYPE_AUTO"); + + return $class; + } + + /** + * @depends testIdentifier + * @param ClassMetadata $class + */ + public function testAssocations($class) + { + $this->assertEquals(3, count($class->associationMappings)); + + return $class; + } + + /** + * @depends testAssocations + * @param ClassMetadata $class + */ + public function testOwningOneToOneAssocation($class) + { + $this->assertTrue(isset($class->associationMappings['address'])); + $this->assertTrue($class->associationMappings['address']['isOwningSide']); + $this->assertEquals('user', $class->associationMappings['address']['inversedBy']); + // Check cascading + $this->assertTrue($class->associationMappings['address']['isCascadeRemove']); + $this->assertFalse($class->associationMappings['address']['isCascadePersist']); + $this->assertFalse($class->associationMappings['address']['isCascadeRefresh']); + $this->assertFalse($class->associationMappings['address']['isCascadeDetach']); + $this->assertFalse($class->associationMappings['address']['isCascadeMerge']); + + return $class; + } + + /** + * @depends testOwningOneToOneAssocation + * @param ClassMetadata $class + */ + public function testInverseOneToManyAssociation($class) + { + $this->assertTrue(isset($class->associationMappings['phonenumbers'])); + $this->assertFalse($class->associationMappings['phonenumbers']['isOwningSide']); + $this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']); + $this->assertTrue($class->associationMappings['phonenumbers']['isCascadeRemove']); + $this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']); + $this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']); + $this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']); + $this->assertTrue($class->associationMappings['phonenumbers']['orphanRemoval']); + + // Test Order By + $this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']['orderBy']); + + return $class; + } + + /** + * @depends testInverseOneToManyAssociation + * @param ClassMetadata $class + */ + public function testManyToManyAssociationWithCascadeAll($class) + { + $this->assertTrue(isset($class->associationMappings['groups'])); + $this->assertTrue($class->associationMappings['groups']['isOwningSide']); + // Make sure that cascade-all works as expected + $this->assertTrue($class->associationMappings['groups']['isCascadeRemove']); + $this->assertTrue($class->associationMappings['groups']['isCascadePersist']); + $this->assertTrue($class->associationMappings['groups']['isCascadeRefresh']); + $this->assertTrue($class->associationMappings['groups']['isCascadeDetach']); + $this->assertTrue($class->associationMappings['groups']['isCascadeMerge']); + + $this->assertFalse(isset($class->associationMappings['groups']['orderBy'])); + + return $class; + } + + /** + * @depends testManyToManyAssociationWithCascadeAll + * @param ClassMetadata $class + */ + public function testLifecycleCallbacks($class) + { + $this->assertEquals(count($class->lifecycleCallbacks), 2); + $this->assertEquals($class->lifecycleCallbacks['prePersist'][0], 'doStuffOnPrePersist'); + $this->assertEquals($class->lifecycleCallbacks['postPersist'][0], 'doStuffOnPostPersist'); + + return $class; + } + + /** + * @depends testManyToManyAssociationWithCascadeAll + * @param ClassMetadata $class + */ + public function testLifecycleCallbacksSupportMultipleMethodNames($class) + { + $this->assertEquals(count($class->lifecycleCallbacks['prePersist']), 2); + $this->assertEquals($class->lifecycleCallbacks['prePersist'][1], 'doOtherStuffOnPrePersistToo'); + + return $class; + } + + /** + * @depends testLifecycleCallbacksSupportMultipleMethodNames + * @param ClassMetadata $class + */ + public function testJoinColumnUniqueAndNullable($class) + { + // Non-Nullability of Join Column + $this->assertFalse($class->associationMappings['groups']['joinTable']['joinColumns'][0]['nullable']); + $this->assertFalse($class->associationMappings['groups']['joinTable']['joinColumns'][0]['unique']); + + return $class; + } + + /** + * @depends testJoinColumnUniqueAndNullable + * @param ClassMetadata $class + */ + public function testColumnDefinition($class) + { + $this->assertEquals("CHAR(32) NOT NULL", $class->fieldMappings['email']['columnDefinition']); + $this->assertEquals("INT NULL", $class->associationMappings['groups']['joinTable']['inverseJoinColumns'][0]['columnDefinition']); + + return $class; + } + + /** + * @depends testColumnDefinition + * @param ClassMetadata $class + */ + public function testJoinColumnOnDelete($class) + { + $this->assertEquals('CASCADE', $class->associationMappings['address']['joinColumns'][0]['onDelete']); + + return $class; + } + + /** + * @group DDC-514 + */ + public function testDiscriminatorColumnDefaults() + { + if (strpos(get_class($this), 'PHPMappingDriver') !== false) { + $this->markTestSkipped('PHP Mapping Drivers have no defaults.'); + } + + $class = $this->createClassMetadata('Doctrine\Tests\ORM\Mapping\Animal'); + + $this->assertEquals( + array('name' => 'discr', 'type' => 'string', 'length' => '32', 'fieldName' => 'discr', 'columnDefinition' => null), + $class->discriminatorColumn + ); + } + + /** + * @group DDC-869 + */ + public function testMappedSuperclassWithRepository() + { + $em = $this->_getTestEntityManager(); + $factory = $this->createClassMetadataFactory($em); + + + $class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment'); + + $this->assertTrue(isset($class->fieldMappings['id'])); + $this->assertTrue(isset($class->fieldMappings['value'])); + $this->assertTrue(isset($class->fieldMappings['creditCardNumber'])); + $this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository"); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository", + $em->getRepository("Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment")); + $this->assertTrue($em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment")->isTrue()); + + + + $class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869ChequePayment'); + + $this->assertTrue(isset($class->fieldMappings['id'])); + $this->assertTrue(isset($class->fieldMappings['value'])); + $this->assertTrue(isset($class->fieldMappings['serialNumber'])); + $this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository"); + $this->assertInstanceOf("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository", + $em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment")); + $this->assertTrue($em->getRepository("Doctrine\Tests\Models\DDC869\DDC869ChequePayment")->isTrue()); + } + + /** + * @group DDC-1476 + */ + public function testDefaultFieldType() + { + $factory = $this->createClassMetadataFactory(); + $class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC1476\DDC1476EntityWithDefaultFieldType'); + + + $this->assertArrayHasKey('id', $class->fieldMappings); + $this->assertArrayHasKey('name', $class->fieldMappings); + + + $this->assertArrayHasKey('type', $class->fieldMappings['id']); + $this->assertArrayHasKey('type', $class->fieldMappings['name']); + + $this->assertEquals('string', $class->fieldMappings['id']['type']); + $this->assertEquals('string', $class->fieldMappings['name']['type']); + + + + $this->assertArrayHasKey('fieldName', $class->fieldMappings['id']); + $this->assertArrayHasKey('fieldName', $class->fieldMappings['name']); + + $this->assertEquals('id', $class->fieldMappings['id']['fieldName']); + $this->assertEquals('name', $class->fieldMappings['name']['fieldName']); + + + + $this->assertArrayHasKey('columnName', $class->fieldMappings['id']); + $this->assertArrayHasKey('columnName', $class->fieldMappings['name']); + + $this->assertEquals('id', $class->fieldMappings['id']['columnName']); + $this->assertEquals('name', $class->fieldMappings['name']['columnName']); + + $this->assertEquals(ClassMetadataInfo::GENERATOR_TYPE_NONE, $class->generatorType); + } + + /** + * @group DDC-1170 + */ + public function testIdentifierColumnDefinition() + { + $class = $this->createClassMetadata(__NAMESPACE__ . '\DDC1170Entity'); + + + $this->assertArrayHasKey('id', $class->fieldMappings); + $this->assertArrayHasKey('value', $class->fieldMappings); + + $this->assertArrayHasKey('columnDefinition', $class->fieldMappings['id']); + $this->assertArrayHasKey('columnDefinition', $class->fieldMappings['value']); + + $this->assertEquals("INT unsigned NOT NULL", $class->fieldMappings['id']['columnDefinition']); + $this->assertEquals("VARCHAR(255) NOT NULL", $class->fieldMappings['value']['columnDefinition']); + } + + /** + * @group DDC-559 + */ + public function testNamingStrategy() + { + $em = $this->_getTestEntityManager(); + $factory = $this->createClassMetadataFactory($em); + + + $this->assertInstanceOf('Doctrine\ORM\Mapping\DefaultNamingStrategy', $em->getConfiguration()->getNamingStrategy()); + $em->getConfiguration()->setNamingStrategy(new \Doctrine\ORM\Mapping\UnderscoreNamingStrategy(CASE_UPPER)); + $this->assertInstanceOf('Doctrine\ORM\Mapping\UnderscoreNamingStrategy', $em->getConfiguration()->getNamingStrategy()); + + $class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC1476\DDC1476EntityWithDefaultFieldType'); + + $this->assertEquals('ID', $class->columnNames['id']); + $this->assertEquals('NAME', $class->columnNames['name']); + $this->assertEquals('DDC1476ENTITY_WITH_DEFAULT_FIELD_TYPE', $class->table['name']); + } + + /** + * @group DDC-807 + * @group DDC-553 + */ + public function testDiscriminatorColumnDefinition() + { + $class = $this->createClassMetadata(__NAMESPACE__ . '\DDC807Entity'); + + $this->assertArrayHasKey('columnDefinition', $class->discriminatorColumn); + $this->assertArrayHasKey('name', $class->discriminatorColumn); + + $this->assertEquals("ENUM('ONE','TWO')", $class->discriminatorColumn['columnDefinition']); + $this->assertEquals("dtype", $class->discriminatorColumn['name']); + } + + /** + * @group DDC-889 + * @expectedException Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Class "Doctrine\Tests\Models\DDC889\DDC889Class" sub class of "Doctrine\Tests\Models\DDC889\DDC889SuperClass" is not a valid entity or mapped super class. + */ + public function testInvalidEntityOrMappedSuperClassShouldMentionParentClasses() + { + $this->createClassMetadata('Doctrine\Tests\Models\DDC889\DDC889Class'); + } + + /** + * @group DDC-889 + * @expectedException Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage No identifier/primary key specified for Entity "Doctrine\Tests\Models\DDC889\DDC889Entity" sub class of "Doctrine\Tests\Models\DDC889\DDC889SuperClass". Every Entity must have an identifier/primary key. + */ + public function testIdentifierRequiredShouldMentionParentClasses() + { + + $factory = $this->createClassMetadataFactory(); + + $factory->getMetadataFor('Doctrine\Tests\Models\DDC889\DDC889Entity'); + } + + public function testNamedQuery() + { + $driver = $this->_loadDriver(); + $class = $this->createClassMetadata(__NAMESPACE__.'\User'); + + $this->assertCount(1, $class->getNamedQueries(), sprintf("Named queries not processed correctly by driver %s", get_class($driver))); + } + + /** + * @group DDC-1663 + */ + public function testNamedNativeQuery() + { + + $class = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + + //named native query + $this->assertCount(3, $class->namedNativeQueries); + $this->assertArrayHasKey('find-all', $class->namedNativeQueries); + $this->assertArrayHasKey('find-by-id', $class->namedNativeQueries); + + + $findAllQuery = $class->getNamedNativeQuery('find-all'); + $this->assertEquals('find-all', $findAllQuery['name']); + $this->assertEquals('mapping-find-all', $findAllQuery['resultSetMapping']); + $this->assertEquals('SELECT id, country, city FROM cms_addresses', $findAllQuery['query']); + + $findByIdQuery = $class->getNamedNativeQuery('find-by-id'); + $this->assertEquals('find-by-id', $findByIdQuery['name']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress',$findByIdQuery['resultClass']); + $this->assertEquals('SELECT * FROM cms_addresses WHERE id = ?', $findByIdQuery['query']); + + $countQuery = $class->getNamedNativeQuery('count'); + $this->assertEquals('count', $countQuery['name']); + $this->assertEquals('mapping-count', $countQuery['resultSetMapping']); + $this->assertEquals('SELECT COUNT(*) AS count FROM cms_addresses', $countQuery['query']); + + // result set mapping + $this->assertCount(3, $class->sqlResultSetMappings); + $this->assertArrayHasKey('mapping-count', $class->sqlResultSetMappings); + $this->assertArrayHasKey('mapping-find-all', $class->sqlResultSetMappings); + $this->assertArrayHasKey('mapping-without-fields', $class->sqlResultSetMappings); + + $findAllMapping = $class->getSqlResultSetMapping('mapping-find-all'); + $this->assertEquals('mapping-find-all', $findAllMapping['name']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress', $findAllMapping['entities'][0]['entityClass']); + $this->assertEquals(array('name'=>'id','column'=>'id'), $findAllMapping['entities'][0]['fields'][0]); + $this->assertEquals(array('name'=>'city','column'=>'city'), $findAllMapping['entities'][0]['fields'][1]); + $this->assertEquals(array('name'=>'country','column'=>'country'), $findAllMapping['entities'][0]['fields'][2]); + + $withoutFieldsMapping = $class->getSqlResultSetMapping('mapping-without-fields'); + $this->assertEquals('mapping-without-fields', $withoutFieldsMapping['name']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress', $withoutFieldsMapping['entities'][0]['entityClass']); + $this->assertEquals(array(), $withoutFieldsMapping['entities'][0]['fields']); + + $countMapping = $class->getSqlResultSetMapping('mapping-count'); + $this->assertEquals('mapping-count', $countMapping['name']); + $this->assertEquals(array('name'=>'count'), $countMapping['columns'][0]); + + } + + /** + * @group DDC-1663 + */ + public function testSqlResultSetMapping() + { + + $userMetadata = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $personMetadata = $this->createClassMetadata('Doctrine\Tests\Models\Company\CompanyPerson'); + + // user asserts + $this->assertCount(4, $userMetadata->getSqlResultSetMappings()); + + $mapping = $userMetadata->getSqlResultSetMapping('mappingJoinedAddress'); + $this->assertEquals(array(),$mapping['columns']); + $this->assertEquals('mappingJoinedAddress', $mapping['name']); + $this->assertNull($mapping['entities'][0]['discriminatorColumn']); + $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]); + $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]); + $this->assertEquals(array('name'=>'status','column'=>'status'), $mapping['entities'][0]['fields'][2]); + $this->assertEquals(array('name'=>'address.zip','column'=>'zip'), $mapping['entities'][0]['fields'][3]); + $this->assertEquals(array('name'=>'address.city','column'=>'city'), $mapping['entities'][0]['fields'][4]); + $this->assertEquals(array('name'=>'address.country','column'=>'country'), $mapping['entities'][0]['fields'][5]); + $this->assertEquals(array('name'=>'address.id','column'=>'a_id'), $mapping['entities'][0]['fields'][6]); + $this->assertEquals($userMetadata->name, $mapping['entities'][0]['entityClass']); + + + $mapping = $userMetadata->getSqlResultSetMapping('mappingJoinedPhonenumber'); + $this->assertEquals(array(),$mapping['columns']); + $this->assertEquals('mappingJoinedPhonenumber', $mapping['name']); + $this->assertNull($mapping['entities'][0]['discriminatorColumn']); + $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]); + $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]); + $this->assertEquals(array('name'=>'status','column'=>'status'), $mapping['entities'][0]['fields'][2]); + $this->assertEquals(array('name'=>'phonenumbers.phonenumber','column'=>'number'), $mapping['entities'][0]['fields'][3]); + $this->assertEquals($userMetadata->name, $mapping['entities'][0]['entityClass']); + + $mapping = $userMetadata->getSqlResultSetMapping('mappingUserPhonenumberCount'); + $this->assertEquals(array('name'=>'numphones'),$mapping['columns'][0]); + $this->assertEquals('mappingUserPhonenumberCount', $mapping['name']); + $this->assertNull($mapping['entities'][0]['discriminatorColumn']); + $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]); + $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]); + $this->assertEquals(array('name'=>'status','column'=>'status'), $mapping['entities'][0]['fields'][2]); + $this->assertEquals($userMetadata->name, $mapping['entities'][0]['entityClass']); + + $mapping = $userMetadata->getSqlResultSetMapping('mappingMultipleJoinsEntityResults'); + $this->assertEquals(array('name'=>'numphones'),$mapping['columns'][0]); + $this->assertEquals('mappingMultipleJoinsEntityResults', $mapping['name']); + $this->assertNull($mapping['entities'][0]['discriminatorColumn']); + $this->assertEquals(array('name'=>'id','column'=>'u_id'), $mapping['entities'][0]['fields'][0]); + $this->assertEquals(array('name'=>'name','column'=>'u_name'), $mapping['entities'][0]['fields'][1]); + $this->assertEquals(array('name'=>'status','column'=>'u_status'), $mapping['entities'][0]['fields'][2]); + $this->assertEquals($userMetadata->name, $mapping['entities'][0]['entityClass']); + $this->assertNull($mapping['entities'][1]['discriminatorColumn']); + $this->assertEquals(array('name'=>'id','column'=>'a_id'), $mapping['entities'][1]['fields'][0]); + $this->assertEquals(array('name'=>'zip','column'=>'a_zip'), $mapping['entities'][1]['fields'][1]); + $this->assertEquals(array('name'=>'country','column'=>'a_country'), $mapping['entities'][1]['fields'][2]); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress', $mapping['entities'][1]['entityClass']); + + //person asserts + $this->assertCount(1, $personMetadata->getSqlResultSetMappings()); + + $mapping = $personMetadata->getSqlResultSetMapping('mappingFetchAll'); + $this->assertEquals(array(),$mapping['columns']); + $this->assertEquals('mappingFetchAll', $mapping['name']); + $this->assertEquals('discriminator', $mapping['entities'][0]['discriminatorColumn']); + $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]); + $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]); + $this->assertEquals($personMetadata->name, $mapping['entities'][0]['entityClass']); + } + + /* + * @group DDC-964 + */ + public function testAssociationOverridesMapping() + { + + $factory = $this->createClassMetadataFactory(); + $adminMetadata = $factory->getMetadataFor('Doctrine\Tests\Models\DDC964\DDC964Admin'); + $guestMetadata = $factory->getMetadataFor('Doctrine\Tests\Models\DDC964\DDC964Guest'); + + + // assert groups association mappings + $this->assertArrayHasKey('groups', $guestMetadata->associationMappings); + $this->assertArrayHasKey('groups', $adminMetadata->associationMappings); + + $guestGroups = $guestMetadata->associationMappings['groups']; + $adminGroups = $adminMetadata->associationMappings['groups']; + + // assert not override attributes + $this->assertEquals($guestGroups['fieldName'], $adminGroups['fieldName']); + $this->assertEquals($guestGroups['type'], $adminGroups['type']); + $this->assertEquals($guestGroups['mappedBy'], $adminGroups['mappedBy']); + $this->assertEquals($guestGroups['inversedBy'], $adminGroups['inversedBy']); + $this->assertEquals($guestGroups['isOwningSide'], $adminGroups['isOwningSide']); + $this->assertEquals($guestGroups['fetch'], $adminGroups['fetch']); + $this->assertEquals($guestGroups['isCascadeRemove'], $adminGroups['isCascadeRemove']); + $this->assertEquals($guestGroups['isCascadePersist'], $adminGroups['isCascadePersist']); + $this->assertEquals($guestGroups['isCascadeRefresh'], $adminGroups['isCascadeRefresh']); + $this->assertEquals($guestGroups['isCascadeMerge'], $adminGroups['isCascadeMerge']); + $this->assertEquals($guestGroups['isCascadeDetach'], $adminGroups['isCascadeDetach']); + + // assert not override attributes + $this->assertEquals('ddc964_users_groups', $guestGroups['joinTable']['name']); + $this->assertEquals('user_id', $guestGroups['joinTable']['joinColumns'][0]['name']); + $this->assertEquals('group_id', $guestGroups['joinTable']['inverseJoinColumns'][0]['name']); + + $this->assertEquals(array('user_id'=>'id'), $guestGroups['relationToSourceKeyColumns']); + $this->assertEquals(array('group_id'=>'id'), $guestGroups['relationToTargetKeyColumns']); + $this->assertEquals(array('user_id','group_id'), $guestGroups['joinTableColumns']); + + + $this->assertEquals('ddc964_users_admingroups', $adminGroups['joinTable']['name']); + $this->assertEquals('adminuser_id', $adminGroups['joinTable']['joinColumns'][0]['name']); + $this->assertEquals('admingroup_id', $adminGroups['joinTable']['inverseJoinColumns'][0]['name']); + + $this->assertEquals(array('adminuser_id'=>'id'), $adminGroups['relationToSourceKeyColumns']); + $this->assertEquals(array('admingroup_id'=>'id'), $adminGroups['relationToTargetKeyColumns']); + $this->assertEquals(array('adminuser_id','admingroup_id'), $adminGroups['joinTableColumns']); + + + // assert address association mappings + $this->assertArrayHasKey('address', $guestMetadata->associationMappings); + $this->assertArrayHasKey('address', $adminMetadata->associationMappings); + + $guestAddress = $guestMetadata->associationMappings['address']; + $adminAddress = $adminMetadata->associationMappings['address']; + + // assert not override attributes + $this->assertEquals($guestAddress['fieldName'], $adminAddress['fieldName']); + $this->assertEquals($guestAddress['type'], $adminAddress['type']); + $this->assertEquals($guestAddress['mappedBy'], $adminAddress['mappedBy']); + $this->assertEquals($guestAddress['inversedBy'], $adminAddress['inversedBy']); + $this->assertEquals($guestAddress['isOwningSide'], $adminAddress['isOwningSide']); + $this->assertEquals($guestAddress['fetch'], $adminAddress['fetch']); + $this->assertEquals($guestAddress['isCascadeRemove'], $adminAddress['isCascadeRemove']); + $this->assertEquals($guestAddress['isCascadePersist'], $adminAddress['isCascadePersist']); + $this->assertEquals($guestAddress['isCascadeRefresh'], $adminAddress['isCascadeRefresh']); + $this->assertEquals($guestAddress['isCascadeMerge'], $adminAddress['isCascadeMerge']); + $this->assertEquals($guestAddress['isCascadeDetach'], $adminAddress['isCascadeDetach']); + + // assert override + $this->assertEquals('address_id', $guestAddress['joinColumns'][0]['name']); + $this->assertEquals(array('address_id'=>'id'), $guestAddress['sourceToTargetKeyColumns']); + $this->assertEquals(array('address_id'=>'address_id'), $guestAddress['joinColumnFieldNames']); + $this->assertEquals(array('id'=>'address_id'), $guestAddress['targetToSourceKeyColumns']); + + + $this->assertEquals('adminaddress_id', $adminAddress['joinColumns'][0]['name']); + $this->assertEquals(array('adminaddress_id'=>'id'), $adminAddress['sourceToTargetKeyColumns']); + $this->assertEquals(array('adminaddress_id'=>'adminaddress_id'), $adminAddress['joinColumnFieldNames']); + $this->assertEquals(array('id'=>'adminaddress_id'), $adminAddress['targetToSourceKeyColumns']); + } + + /** + * @group DDC-964 + */ + public function testAttributeOverridesMapping() + { + + $factory = $this->createClassMetadataFactory(); + $guestMetadata = $factory->getMetadataFor('Doctrine\Tests\Models\DDC964\DDC964Guest'); + $adminMetadata = $factory->getMetadataFor('Doctrine\Tests\Models\DDC964\DDC964Admin'); + + $this->assertTrue($adminMetadata->fieldMappings['id']['id']); + $this->assertEquals('id', $adminMetadata->fieldMappings['id']['fieldName']); + $this->assertEquals('user_id', $adminMetadata->fieldMappings['id']['columnName']); + $this->assertEquals(array('user_id'=>'id','user_name'=>'name'), $adminMetadata->fieldNames); + $this->assertEquals(array('id'=>'user_id','name'=>'user_name'), $adminMetadata->columnNames); + $this->assertEquals(150, $adminMetadata->fieldMappings['id']['length']); + + + $this->assertEquals('name', $adminMetadata->fieldMappings['name']['fieldName']); + $this->assertEquals('user_name', $adminMetadata->fieldMappings['name']['columnName']); + $this->assertEquals(250, $adminMetadata->fieldMappings['name']['length']); + $this->assertTrue($adminMetadata->fieldMappings['name']['nullable']); + $this->assertFalse($adminMetadata->fieldMappings['name']['unique']); + + + $this->assertTrue($guestMetadata->fieldMappings['id']['id']); + $this->assertEquals('guest_id', $guestMetadata->fieldMappings['id']['columnName']); + $this->assertEquals('id', $guestMetadata->fieldMappings['id']['fieldName']); + $this->assertEquals(array('guest_id'=>'id','guest_name'=>'name'), $guestMetadata->fieldNames); + $this->assertEquals(array('id'=>'guest_id','name'=>'guest_name'), $guestMetadata->columnNames); + $this->assertEquals(140, $guestMetadata->fieldMappings['id']['length']); + + $this->assertEquals('name', $guestMetadata->fieldMappings['name']['fieldName']); + $this->assertEquals('guest_name', $guestMetadata->fieldMappings['name']['columnName']); + $this->assertEquals(240, $guestMetadata->fieldMappings['name']['length']); + $this->assertFalse($guestMetadata->fieldMappings['name']['nullable']); + $this->assertTrue($guestMetadata->fieldMappings['name']['unique']); + } + +} + +/** + * @Entity + * @HasLifecycleCallbacks + * @Table( + * name="cms_users", + * uniqueConstraints={@UniqueConstraint(name="search_idx", columns={"name", "user_email"})}, + * indexes={@Index(name="name_idx", columns={"name"}), @Index(name="0", columns={"user_email"})}, + * options={"foo": "bar", "baz": {"key": "val"}} + * ) + * @NamedQueries({@NamedQuery(name="all", query="SELECT u FROM __CLASS__ u")}) + */ +class User +{ + /** + * @Id + * @Column(type="integer") + * @generatedValue(strategy="AUTO") + * @SequenceGenerator(sequenceName="tablename_seq", initialValue=1, allocationSize=100) + **/ + public $id; + + /** + * @Column(length=50, nullable=true, unique=true, options={"foo": "bar", "baz": {"key": "val"}}) + */ + public $name; + + /** + * @Column(name="user_email", columnDefinition="CHAR(32) NOT NULL") + */ + public $email; + + /** + * @OneToOne(targetEntity="Address", cascade={"remove"}, inversedBy="user") + * @JoinColumn(onDelete="CASCADE") + */ + public $address; + + /** + * @OneToMany(targetEntity="Phonenumber", mappedBy="user", cascade={"persist"}, orphanRemoval=true) + * @OrderBy({"number"="ASC"}) + */ + public $phonenumbers; + + /** + * @ManyToMany(targetEntity="Group", cascade={"all"}) + * @JoinTable(name="cms_user_groups", + * joinColumns={@JoinColumn(name="user_id", referencedColumnName="id", nullable=false, unique=false)}, + * inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id", columnDefinition="INT NULL")} + * ) + */ + public $groups; + + + /** + * @PrePersist + */ + public function doStuffOnPrePersist() + { + } + + /** + * @PrePersist + */ + public function doOtherStuffOnPrePersistToo() { + } + + /** + * @PostPersist + */ + public function doStuffOnPostPersist() + { + + } + + public static function loadMetadata(ClassMetadataInfo $metadata) + { + $metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE); + $metadata->setPrimaryTable(array( + 'name' => 'cms_users', + 'options' => array('foo' => 'bar', 'baz' => array('key' => 'val')), + )); + $metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT); + $metadata->addLifecycleCallback('doStuffOnPrePersist', 'prePersist'); + $metadata->addLifecycleCallback('doOtherStuffOnPrePersistToo', 'prePersist'); + $metadata->addLifecycleCallback('doStuffOnPostPersist', 'postPersist'); + $metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'id', + )); + $metadata->mapField(array( + 'fieldName' => 'name', + 'type' => 'string', + 'length' => 50, + 'unique' => true, + 'nullable' => true, + 'columnName' => 'name', + 'options' => array('foo' => 'bar', 'baz' => array('key' => 'val')), + )); + $metadata->mapField(array( + 'fieldName' => 'email', + 'type' => 'string', + 'columnName' => 'user_email', + 'columnDefinition' => 'CHAR(32) NOT NULL', + )); + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); + $metadata->mapOneToOne(array( + 'fieldName' => 'address', + 'targetEntity' => 'Doctrine\\Tests\\ORM\\Mapping\\Address', + 'cascade' => + array( + 0 => 'remove', + ), + 'mappedBy' => NULL, + 'inversedBy' => 'user', + 'joinColumns' => + array( + 0 => + array( + 'name' => 'address_id', + 'referencedColumnName' => 'id', + 'onDelete' => 'CASCADE', + ), + ), + 'orphanRemoval' => false, + )); + $metadata->mapOneToMany(array( + 'fieldName' => 'phonenumbers', + 'targetEntity' => 'Doctrine\\Tests\\ORM\\Mapping\\Phonenumber', + 'cascade' => + array( + 1 => 'persist', + ), + 'mappedBy' => 'user', + 'orphanRemoval' => true, + 'orderBy' => + array( + 'number' => 'ASC', + ), + )); + $metadata->mapManyToMany(array( + 'fieldName' => 'groups', + 'targetEntity' => 'Doctrine\\Tests\\ORM\\Mapping\\Group', + 'cascade' => + array( + 0 => 'remove', + 1 => 'persist', + 2 => 'refresh', + 3 => 'merge', + 4 => 'detach', + ), + 'mappedBy' => NULL, + 'joinTable' => + array( + 'name' => 'cms_users_groups', + 'joinColumns' => + array( + 0 => + array( + 'name' => 'user_id', + 'referencedColumnName' => 'id', + 'unique' => false, + 'nullable' => false, + ), + ), + 'inverseJoinColumns' => + array( + 0 => + array( + 'name' => 'group_id', + 'referencedColumnName' => 'id', + 'columnDefinition' => 'INT NULL', + ), + ), + ), + 'orderBy' => NULL, + )); + $metadata->table['uniqueConstraints'] = array( + 'search_idx' => array('columns' => array('name', 'user_email')), + ); + $metadata->table['indexes'] = array( + 'name_idx' => array('columns' => array('name')), 0 => array('columns' => array('user_email')) + ); + $metadata->setSequenceGeneratorDefinition(array( + 'sequenceName' => 'tablename_seq', + 'allocationSize' => 100, + 'initialValue' => 1, + )); + $metadata->addNamedQuery(array( + 'name' => 'all', + 'query' => 'SELECT u FROM __CLASS__ u' + )); + } +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorMap({"cat" = "Cat", "dog" = "Dog"}) + * @DiscriminatorColumn(name="discr", length=32, type="string") + */ +abstract class Animal +{ + /** + * @Id @Column(type="string") @GeneratedValue(strategy="CUSTOM") + * @CustomIdGenerator(class="stdClass") + */ + public $id; + + public static function loadMetadata(ClassMetadataInfo $metadata) + { + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_CUSTOM); + $metadata->setCustomGeneratorDefinition(array("class" => "stdClass")); + } +} + +/** @Entity */ +class Cat extends Animal +{ + public static function loadMetadata(ClassMetadataInfo $metadata) + { + + } +} + +/** @Entity */ +class Dog extends Animal +{ + public static function loadMetadata(ClassMetadataInfo $metadata) + { + + } +} + + +/** + * @Entity + */ +class DDC1170Entity +{ + + /** + * @param string $value + */ + function __construct($value = null) + { + $this->value = $value; + } + + /** + * @Id + * @GeneratedValue(strategy="NONE") + * @Column(type="integer", columnDefinition = "INT unsigned NOT NULL") + **/ + private $id; + + /** + * @Column(columnDefinition = "VARCHAR(255) NOT NULL") + */ + private $value; + + /** + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getValue() + { + return $this->value; + } + + public static function loadMetadata(ClassMetadataInfo $metadata) + { + $metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'columnDefinition' => 'INT unsigned NOT NULL', + )); + + $metadata->mapField(array( + 'fieldName' => 'value', + 'columnDefinition' => 'VARCHAR(255) NOT NULL' + )); + + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE); + } + +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorMap({"ONE" = "DDC807SubClasse1", "TWO" = "DDC807SubClasse2"}) + * @DiscriminatorColumn(name = "dtype", columnDefinition="ENUM('ONE','TWO')") + */ +class DDC807Entity +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="NONE") + **/ + public $id; + + public static function loadMetadata(ClassMetadataInfo $metadata) + { + $metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + )); + + $metadata->setDiscriminatorColumn(array( + 'name' => "dtype", + 'type' => "string", + 'columnDefinition' => "ENUM('ONE','TWO')" + )); + + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE); + } +} + + +class DDC807SubClasse1 {} +class DDC807SubClasse2 {} + +class Address {} +class Phonenumber {} +class Group {} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php new file mode 100644 index 0000000..4d7715e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/AnnotationDriverTest.php @@ -0,0 +1,340 @@ +initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache()); + $annotationDriver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + $annotationDriver->loadMetadataForClass('stdClass', $cm); + } + + /** + * @group DDC-268 + */ + public function testColumnWithMissingTypeDefaultsToString() + { + $cm = new ClassMetadata('Doctrine\Tests\ORM\Mapping\ColumnWithoutType'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $annotationDriver = $this->_loadDriver(); + + $annotationDriver->loadMetadataForClass('Doctrine\Tests\ORM\Mapping\InvalidColumn', $cm); + $this->assertEquals('string', $cm->fieldMappings['id']['type']); + } + + /** + * @group DDC-318 + */ + public function testGetAllClassNamesIsIdempotent() + { + $annotationDriver = $this->_loadDriverForCMSModels(); + $original = $annotationDriver->getAllClassNames(); + + $annotationDriver = $this->_loadDriverForCMSModels(); + $afterTestReset = $annotationDriver->getAllClassNames(); + + $this->assertEquals($original, $afterTestReset); + } + + /** + * @group DDC-318 + */ + public function testGetAllClassNamesIsIdempotentEvenWithDifferentDriverInstances() + { + $annotationDriver = $this->_loadDriverForCMSModels(); + $original = $annotationDriver->getAllClassNames(); + + $annotationDriver = $this->_loadDriverForCMSModels(); + $afterTestReset = $annotationDriver->getAllClassNames(); + + $this->assertEquals($original, $afterTestReset); + } + + /** + * @group DDC-318 + */ + public function testGetAllClassNamesReturnsAlreadyLoadedClassesIfAppropriate() + { + $rightClassName = 'Doctrine\Tests\Models\CMS\CmsUser'; + $this->_ensureIsLoaded($rightClassName); + + $annotationDriver = $this->_loadDriverForCMSModels(); + $classes = $annotationDriver->getAllClassNames(); + + $this->assertContains($rightClassName, $classes); + } + + /** + * @group DDC-318 + */ + public function testGetClassNamesReturnsOnlyTheAppropriateClasses() + { + $extraneousClassName = 'Doctrine\Tests\Models\ECommerce\ECommerceCart'; + $this->_ensureIsLoaded($extraneousClassName); + + $annotationDriver = $this->_loadDriverForCMSModels(); + $classes = $annotationDriver->getAllClassNames(); + + $this->assertNotContains($extraneousClassName, $classes); + } + + protected function _loadDriverForCMSModels() + { + $annotationDriver = $this->_loadDriver(); + $annotationDriver->addPaths(array(__DIR__ . '/../../Models/CMS/')); + return $annotationDriver; + } + + protected function _loadDriver() + { + return $this->createAnnotationDriver(); + } + + protected function _ensureIsLoaded($entityClassName) + { + new $entityClassName; + } + + /** + * @group DDC-671 + * + * Entities for this test are in AbstractMappingDriverTest + */ + public function testJoinTablesWithMappedSuperclassForAnnotationDriver() + { + $annotationDriver = $this->_loadDriver(); + $annotationDriver->addPaths(array(__DIR__ . '/../../Models/DirectoryTree/')); + + $em = $this->_getTestEntityManager(); + $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); + $factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + $factory->setEntityManager($em); + + $classPage = $factory->getMetadataFor('Doctrine\Tests\Models\DirectoryTree\File'); + $this->assertEquals('Doctrine\Tests\Models\DirectoryTree\File', $classPage->associationMappings['parentDirectory']['sourceEntity']); + + $classDirectory = $factory->getMetadataFor('Doctrine\Tests\Models\DirectoryTree\Directory'); + $this->assertEquals('Doctrine\Tests\Models\DirectoryTree\Directory', $classDirectory->associationMappings['parentDirectory']['sourceEntity']); + } + + /** + * @group DDC-945 + */ + public function testInvalidMappedSuperClassWithManyToManyAssociation() + { + $annotationDriver = $this->_loadDriver(); + + $em = $this->_getTestEntityManager(); + $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); + $factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + $factory->setEntityManager($em); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', + "It is illegal to put an inverse side one-to-many or many-to-many association on ". + "mapped superclass 'Doctrine\Tests\ORM\Mapping\InvalidMappedSuperClass#users'"); + $usingInvalidMsc = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\UsingInvalidMappedSuperClass'); + } + + /** + * @group DDC-1050 + */ + public function testInvalidMappedSuperClassWithInheritanceInformation() + { + $annotationDriver = $this->_loadDriver(); + + $em = $this->_getTestEntityManager(); + $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); + $factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + $factory->setEntityManager($em); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', + "Its not supported to define inheritance information on a mapped ". + "superclass 'Doctrine\Tests\ORM\Mapping\MappedSuperClassInheritence'."); + $usingInvalidMsc = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\MappedSuperClassInheritence'); + } + + /** + * @group DDC-1034 + */ + public function testInheritanceSkipsParentLifecycleCallbacks() + { + $annotationDriver = $this->_loadDriver(); + + $cm = new ClassMetadata('Doctrine\Tests\ORM\Mapping\AnnotationChild'); + $em = $this->_getTestEntityManager(); + $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); + $factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + $factory->setEntityManager($em); + + $cm = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\AnnotationChild'); + $this->assertEquals(array("postLoad" => array("postLoad"), "preUpdate" => array("preUpdate")), $cm->lifecycleCallbacks); + + $cm = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\AnnotationParent'); + $this->assertEquals(array("postLoad" => array("postLoad"), "preUpdate" => array("preUpdate")), $cm->lifecycleCallbacks); + } + + /** + * @group DDC-1156 + */ + public function testMappedSuperclassInMiddleOfInheritanceHierachy() + { + $annotationDriver = $this->_loadDriver(); + + $em = $this->_getTestEntityManager(); + $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); + $factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + $factory->setEntityManager($em); + + $cm = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\ChildEntity'); + } + + public function testInvalidFetchOptionThrowsException() + { + $annotationDriver = $this->_loadDriver(); + + $em = $this->_getTestEntityManager(); + $em->getConfiguration()->setMetadataDriverImpl($annotationDriver); + $factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + $factory->setEntityManager($em); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', + "Entity 'Doctrine\Tests\ORM\Mapping\InvalidFetchOption' has a mapping with invalid fetch mode 'eager"); + $cm = $factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\InvalidFetchOption'); + } +} + +/** + * @Entity + */ +class ColumnWithoutType +{ + /** @Id @Column */ + public $id; +} + +/** + * @MappedSuperclass + */ +class InvalidMappedSuperClass +{ + /** + * @ManyToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsUser", mappedBy="invalid") + */ + private $users; +} + +/** + * @Entity + */ +class UsingInvalidMappedSuperClass extends InvalidMappedSuperClass +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + private $id; +} + +/** + * @MappedSuperclass + * @InheritanceType("JOINED") + * @DiscriminatorMap({"test" = "ColumnWithoutType"}) + */ +class MappedSuperClassInheritence +{ + +} + +/** + * @Entity + * @InheritanceType("JOINED") + * @DiscriminatorMap({"parent" = "AnnotationParent", "child" = "AnnotationChild"}) + * @HasLifecycleCallbacks + */ +class AnnotationParent +{ + /** + * @Id @Column(type="integer") @GeneratedValue + */ + private $id; + + /** + * @PostLoad + */ + public function postLoad() + { + + } + + /** + * @PreUpdate + */ + public function preUpdate() + { + + } +} + +/** + * @Entity + * @HasLifecycleCallbacks + */ +class AnnotationChild extends AnnotationParent +{ + +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorMap({"s"="SuperEntity", "c"="ChildEntity"}) + */ +class SuperEntity +{ + /** @Id @Column(type="string") */ + private $id; +} + +/** + * @MappedSuperclass + */ +class MiddleMappedSuperclass extends SuperEntity +{ + /** @Column(type="string") */ + private $name; +} + +/** + * @Entity + */ +class ChildEntity extends MiddleMappedSuperclass +{ + /** + * @Column(type="string") + */ + private $text; +} + +/** + * @Entity + */ +class InvalidFetchOption +{ + /** + * @OneToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsUser", fetch="eager") + */ + private $collection; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/BasicInheritanceMappingTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/BasicInheritanceMappingTest.php new file mode 100644 index 0000000..ff7f040 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/BasicInheritanceMappingTest.php @@ -0,0 +1,319 @@ +_factory = new ClassMetadataFactory(); + $this->_factory->setEntityManager($this->_getTestEntityManager()); + } + + /** + * @expectedException Doctrine\ORM\Mapping\MappingException + */ + public function testGetMetadataForTransientClassThrowsException() + { + $this->_factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\TransientBaseClass'); + } + + public function testGetMetadataForSubclassWithTransientBaseClass() + { + $class = $this->_factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\EntitySubClass'); + + $this->assertTrue(empty($class->subClasses)); + $this->assertTrue(empty($class->parentClasses)); + $this->assertTrue(isset($class->fieldMappings['id'])); + $this->assertTrue(isset($class->fieldMappings['name'])); + } + + public function testGetMetadataForSubclassWithMappedSuperclass() + { + $class = $this->_factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\EntitySubClass2'); + + $this->assertTrue(empty($class->subClasses)); + $this->assertTrue(empty($class->parentClasses)); + + $this->assertTrue(isset($class->fieldMappings['mapped1'])); + $this->assertTrue(isset($class->fieldMappings['mapped2'])); + $this->assertTrue(isset($class->fieldMappings['id'])); + $this->assertTrue(isset($class->fieldMappings['name'])); + + $this->assertFalse(isset($class->fieldMappings['mapped1']['inherited'])); + $this->assertFalse(isset($class->fieldMappings['mapped2']['inherited'])); + $this->assertFalse(isset($class->fieldMappings['transient'])); + + $this->assertTrue(isset($class->associationMappings['mappedRelated1'])); + } + + /** + * @group DDC-869 + */ + public function testGetMetadataForSubclassWithMappedSuperclassWhithRepository() + { + $class = $this->_factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment'); + + $this->assertTrue(isset($class->fieldMappings['id'])); + $this->assertTrue(isset($class->fieldMappings['value'])); + $this->assertTrue(isset($class->fieldMappings['creditCardNumber'])); + $this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository"); + + + $class = $this->_factory->getMetadataFor('Doctrine\Tests\Models\DDC869\DDC869ChequePayment'); + + $this->assertTrue(isset($class->fieldMappings['id'])); + $this->assertTrue(isset($class->fieldMappings['value'])); + $this->assertTrue(isset($class->fieldMappings['serialNumber'])); + $this->assertEquals($class->customRepositoryClassName, "Doctrine\Tests\Models\DDC869\DDC869PaymentRepository"); + + + // override repositoryClass + $class = $this->_factory->getMetadataFor('Doctrine\Tests\ORM\Mapping\SubclassWithRepository'); + + $this->assertTrue(isset($class->fieldMappings['id'])); + $this->assertTrue(isset($class->fieldMappings['value'])); + $this->assertEquals($class->customRepositoryClassName, "Doctrine\ORM\EntityRepository"); + } + + /** + * @group DDC-388 + */ + public function testSerializationWithPrivateFieldsFromMappedSuperclass() + { + + $class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\EntitySubClass2'); + + $class2 = unserialize(serialize($class)); + $class2->wakeupReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $this->assertTrue(isset($class2->reflFields['mapped1'])); + $this->assertTrue(isset($class2->reflFields['mapped2'])); + $this->assertTrue(isset($class2->reflFields['mappedRelated1'])); + } + + /** + * @group DDC-1203 + */ + public function testUnmappedSuperclassInHierachy() + { + $class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\HierachyD'); + + $this->assertTrue(isset($class->fieldMappings['id'])); + $this->assertTrue(isset($class->fieldMappings['a'])); + $this->assertTrue(isset($class->fieldMappings['d'])); + } + + /** + * @group DDC-1204 + */ + public function testUnmappedEntityInHierachy() + { + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', "Entity 'Doctrine\Tests\ORM\Mapping\HierachyBEntity' has to be part of the discriminator map of 'Doctrine\Tests\ORM\Mapping\HierachyBase' to be properly mapped in the inheritance hierachy. Alternatively you can make 'Doctrine\Tests\ORM\Mapping\HierachyBEntity' an abstract class to avoid this exception from occuring."); + + $class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\HierachyE'); + } + + /** + * @group DDC-1204 + * @group DDC-1203 + */ + public function testMappedSuperclassWithId() + { + $class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\SuperclassEntity'); + + $this->assertTrue(isset($class->fieldMappings['id'])); + } + + /** + * @group DDC-1156 + * @group DDC-1218 + */ + public function testGeneratedValueFromMappedSuperclass() + { + $class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\SuperclassEntity'); + /* @var $class ClassMetadataInfo */ + + $this->assertInstanceOf('Doctrine\ORM\Id\SequenceGenerator', $class->idGenerator); + $this->assertEquals(array('allocationSize' => 1, 'initialValue' => 10, 'sequenceName' => 'foo'), $class->sequenceGeneratorDefinition); + } + + /** + * @group DDC-1156 + * @group DDC-1218 + */ + public function testSequenceDefinitionInHierachyWithSandwichMappedSuperclass() + { + $class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\HierachyD'); + /* @var $class ClassMetadataInfo */ + + $this->assertInstanceOf('Doctrine\ORM\Id\SequenceGenerator', $class->idGenerator); + $this->assertEquals(array('allocationSize' => 1, 'initialValue' => 10, 'sequenceName' => 'foo'), $class->sequenceGeneratorDefinition); + } + + /** + * @group DDC-1156 + * @group DDC-1218 + */ + public function testMultipleMappedSuperclasses() + { + $class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\MediumSuperclassEntity'); + /* @var $class ClassMetadataInfo */ + + $this->assertInstanceOf('Doctrine\ORM\Id\SequenceGenerator', $class->idGenerator); + $this->assertEquals(array('allocationSize' => 1, 'initialValue' => 10, 'sequenceName' => 'foo'), $class->sequenceGeneratorDefinition); + } +} + +class TransientBaseClass { + private $transient1; + private $transient2; +} + +/** @Entity */ +class EntitySubClass extends TransientBaseClass +{ + /** @Id @Column(type="integer") */ + private $id; + /** @Column(type="string") */ + private $name; +} + +/** @MappedSuperclass */ +class MappedSuperclassBase { + /** @Column(type="integer") */ + private $mapped1; + /** @Column(type="string") */ + private $mapped2; + /** + * @OneToOne(targetEntity="MappedSuperclassRelated1") + * @JoinColumn(name="related1_id", referencedColumnName="id") + */ + private $mappedRelated1; + private $transient; +} +class MappedSuperclassRelated1 {} + +/** @Entity */ +class EntitySubClass2 extends MappedSuperclassBase { + /** @Id @Column(type="integer") */ + private $id; + /** @Column(type="string") */ + private $name; +} + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorColumn(name="type", type="string", length=20) + * @DiscriminatorMap({ + * "c" = "HierachyC", + * "d" = "HierachyD", + * "e" = "HierachyE" + * }) + */ +abstract class HierachyBase +{ + /** + * @Column(type="integer") @Id @GeneratedValue(strategy="SEQUENCE") + * @SequenceGenerator(sequenceName="foo", initialValue=10) + * @var int + */ + public $id; +} + +/** + * @MappedSuperclass + */ +abstract class HierachyASuperclass extends HierachyBase +{ + /** @Column(type="string") */ + public $a; +} + +/** + * @Entity + */ +class HierachyBEntity extends HierachyBase +{ + /** @Column(type="string") */ + public $b; +} + +/** + * @Entity + */ +class HierachyC extends HierachyBase +{ + /** @Column(type="string") */ + public $c; +} + +/** + * @Entity + */ +class HierachyD extends HierachyASuperclass +{ + /** @Column(type="string") */ + public $d; +} + +/** + * @Entity + */ +class HierachyE extends HierachyBEntity +{ + /** @Column(type="string") */ + public $e; +} + +/** + * @Entity + */ +class SuperclassEntity extends SuperclassBase +{ + +} + +/** + * @MappedSuperclass + */ +abstract class SuperclassBase +{ + /** + * @Column(type="integer") @Id @GeneratedValue(strategy="SEQUENCE") + * @SequenceGenerator(sequenceName="foo", initialValue=10) + * @var int + */ + public $id; +} + +/** + * @MappedSuperclass + */ +abstract class MediumSuperclassBase extends SuperclassBase +{ + +} + +/** + * @Entity + */ +class MediumSuperclassEntity extends MediumSuperclassBase +{ + +} + +/** + * @Entity(repositoryClass = "Doctrine\ORM\EntityRepository") + */ +class SubclassWithRepository extends \Doctrine\Tests\Models\DDC869\DDC869Payment +{ + +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php new file mode 100644 index 0000000..f14b60b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataBuilderTest.php @@ -0,0 +1,428 @@ +. + */ + + +namespace Doctrine\Tests\ORM\Mapping; + +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder; + +/** + * @group DDC-659 + */ +class ClassMetadataBuilderTest extends \Doctrine\Tests\OrmTestCase +{ + /** + * @var ClassMetadata + */ + private $cm; + /** + * @var ClassMetadataBuilder + */ + private $builder; + + public function setUp() + { + $this->cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $this->cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $this->builder = new ClassMetadataBuilder($this->cm); + } + + public function testSetMappedSuperClass() + { + $this->assertIsFluent($this->builder->setMappedSuperClass()); + $this->assertTrue($this->cm->isMappedSuperclass); + } + + public function testSetCustomRepositoryClass() + { + $this->assertIsFluent($this->builder->setCustomRepositoryClass('Doctrine\Tests\Models\CMS\CmsGroup')); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsGroup', $this->cm->customRepositoryClassName); + } + + public function testSetReadOnly() + { + $this->assertIsFluent($this->builder->setReadOnly()); + $this->assertTrue($this->cm->isReadOnly); + } + + public function testSetTable() + { + $this->assertIsFluent($this->builder->setTable('users')); + $this->assertEquals('users', $this->cm->table['name']); + } + + public function testAddIndex() + { + $this->assertIsFluent($this->builder->addIndex(array('username', 'name'), 'users_idx')); + $this->assertEquals(array('users_idx' => array('columns' => array('username', 'name'))), $this->cm->table['indexes']); + } + + public function testAddUniqueConstraint() + { + $this->assertIsFluent($this->builder->addUniqueConstraint(array('username', 'name'), 'users_idx')); + $this->assertEquals(array('users_idx' => array('columns' => array('username', 'name'))), $this->cm->table['uniqueConstraints']); + } + + public function testSetPrimaryTableRelated() + { + $this->builder->addUniqueConstraint(array('username', 'name'), 'users_idx'); + $this->builder->addIndex(array('username', 'name'), 'users_idx'); + $this->builder->setTable('users'); + + $this->assertEquals( + array( + 'name' => 'users', + 'indexes' => array('users_idx' => array('columns' => array('username', 'name'))), + 'uniqueConstraints' => array('users_idx' => array('columns' => array('username', 'name'))), + ), + $this->cm->table + ); + } + + public function testSetInheritanceJoined() + { + $this->assertIsFluent($this->builder->setJoinedTableInheritance()); + $this->assertEquals(ClassMetadata::INHERITANCE_TYPE_JOINED, $this->cm->inheritanceType); + } + + public function testSetInheritanceSingleTable() + { + $this->assertIsFluent($this->builder->setSingleTableInheritance()); + $this->assertEquals(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE, $this->cm->inheritanceType); + } + + public function testSetDiscriminatorColumn() + { + $this->assertIsFluent($this->builder->setDiscriminatorColumn('discr', 'string', '124')); + $this->assertEquals(array('fieldName' => 'discr', 'name' => 'discr', 'type' => 'string', 'length' => '124'), $this->cm->discriminatorColumn); + } + + public function testAddDiscriminatorMapClass() + { + $this->assertIsFluent($this->builder->addDiscriminatorMapClass('test', 'Doctrine\Tests\Models\CMS\CmsUser')); + $this->assertIsFluent($this->builder->addDiscriminatorMapClass('test2', 'Doctrine\Tests\Models\CMS\CmsGroup')); + + $this->assertEquals(array('test' => 'Doctrine\Tests\Models\CMS\CmsUser', 'test2' => 'Doctrine\Tests\Models\CMS\CmsGroup'), $this->cm->discriminatorMap); + $this->assertEquals('test', $this->cm->discriminatorValue); + } + + public function testChangeTrackingPolicyExplicit() + { + $this->assertIsFluent($this->builder->setChangeTrackingPolicyDeferredExplicit()); + $this->assertEquals(ClassMetadata::CHANGETRACKING_DEFERRED_EXPLICIT, $this->cm->changeTrackingPolicy); + } + + public function testChangeTrackingPolicyNotify() + { + $this->assertIsFluent($this->builder->setChangeTrackingPolicyNotify()); + $this->assertEquals(ClassMetadata::CHANGETRACKING_NOTIFY, $this->cm->changeTrackingPolicy); + } + + public function testAddField() + { + $this->assertIsFluent($this->builder->addField('name', 'string')); + $this->assertEquals(array('columnName' => 'name', 'fieldName' => 'name', 'type' => 'string'), $this->cm->fieldMappings['name']); + } + + public function testCreateField() + { + $fieldBuilder = ($this->builder->createField('name', 'string')); + $this->assertInstanceOf('Doctrine\ORM\Mapping\Builder\FieldBuilder', $fieldBuilder); + + $this->assertFalse(isset($this->cm->fieldMappings['name'])); + $this->assertIsFluent($fieldBuilder->build()); + $this->assertEquals(array('columnName' => 'name', 'fieldName' => 'name', 'type' => 'string'), $this->cm->fieldMappings['name']); + } + + public function testCreateVersionedField() + { + $this->builder->createField('name', 'integer')->columnName('username')->length(124)->nullable()->columnDefinition('foobar')->unique()->isVersionField()->build(); + $this->assertEquals(array( + 'columnDefinition' => 'foobar', + 'columnName' => 'username', + 'default' => 1, + 'fieldName' => 'name', + 'length' => 124, + 'type' => 'integer', + 'nullable' => true, + 'unique' => true, + ), $this->cm->fieldMappings['name']); + } + + public function testCreatePrimaryField() + { + $this->builder->createField('id', 'integer')->isPrimaryKey()->generatedValue()->build(); + + $this->assertEquals(array('id'), $this->cm->identifier); + $this->assertEquals(array('columnName' => 'id', 'fieldName' => 'id', 'id' => true, 'type' => 'integer'), $this->cm->fieldMappings['id']); + } + + public function testAddLifecycleEvent() + { + $this->builder->addLifecycleEvent('getStatus', 'postLoad'); + + $this->assertEquals(array('postLoad' => array('getStatus')), $this->cm->lifecycleCallbacks); + } + + public function testCreateManyToOne() + { + $this->assertIsFluent( + $this->builder->createManyToOne('groups', 'Doctrine\Tests\Models\CMS\CmsGroup') + ->addJoinColumn('group_id', 'id', true, false, 'CASCADE') + ->cascadeAll() + ->fetchExtraLazy() + ->build() + ); + + $this->assertEquals(array('groups' => array ( + 'fieldName' => 'groups', + 'targetEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsGroup', + 'cascade' => array ( + 0 => 'remove', + 1 => 'persist', + 2 => 'refresh', + 3 => 'merge', + 4 => 'detach', + ), + 'fetch' => 4, + 'joinColumns' => array ( + 0 => + array ( + 'name' => 'group_id', + 'referencedColumnName' => 'id', + 'nullable' => true, + 'unique' => false, + 'onDelete' => 'CASCADE', + 'columnDefinition' => NULL, + ), + ), + 'type' => 2, + 'mappedBy' => NULL, + 'inversedBy' => NULL, + 'isOwningSide' => true, + 'sourceEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', + 'isCascadeRemove' => true, + 'isCascadePersist' => true, + 'isCascadeRefresh' => true, + 'isCascadeMerge' => true, + 'isCascadeDetach' => true, + 'sourceToTargetKeyColumns' => + array ( + 'group_id' => 'id', + ), + 'joinColumnFieldNames' => + array ( + 'group_id' => 'group_id', + ), + 'targetToSourceKeyColumns' => + array ( + 'id' => 'group_id', + ), + 'orphanRemoval' => false, + ), + ), $this->cm->associationMappings); + } + + public function testCreateOneToOne() + { + $this->assertIsFluent( + $this->builder->createOneToOne('groups', 'Doctrine\Tests\Models\CMS\CmsGroup') + ->addJoinColumn('group_id', 'id', true, false, 'CASCADE') + ->cascadeAll() + ->fetchExtraLazy() + ->build() + ); + + $this->assertEquals(array('groups' => array ( + 'fieldName' => 'groups', + 'targetEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsGroup', + 'cascade' => array ( + 0 => 'remove', + 1 => 'persist', + 2 => 'refresh', + 3 => 'merge', + 4 => 'detach', + ), + 'fetch' => 4, + 'joinColumns' => array ( + 0 => + array ( + 'name' => 'group_id', + 'referencedColumnName' => 'id', + 'nullable' => true, + 'unique' => true, + 'onDelete' => 'CASCADE', + 'columnDefinition' => NULL, + ), + ), + 'type' => 1, + 'mappedBy' => NULL, + 'inversedBy' => NULL, + 'isOwningSide' => true, + 'sourceEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', + 'isCascadeRemove' => true, + 'isCascadePersist' => true, + 'isCascadeRefresh' => true, + 'isCascadeMerge' => true, + 'isCascadeDetach' => true, + 'sourceToTargetKeyColumns' => + array ( + 'group_id' => 'id', + ), + 'joinColumnFieldNames' => + array ( + 'group_id' => 'group_id', + ), + 'targetToSourceKeyColumns' => + array ( + 'id' => 'group_id', + ), + 'orphanRemoval' => false, + ), + ), $this->cm->associationMappings); + } + + public function testCreateManyToMany() + { + $this->assertIsFluent( + $this->builder->createManyToMany('groups', 'Doctrine\Tests\Models\CMS\CmsGroup') + ->setJoinTable('groups_users') + ->addJoinColumn('group_id', 'id', true, false, 'CASCADE') + ->addInverseJoinColumn('user_id', 'id') + ->cascadeAll() + ->fetchExtraLazy() + ->build() + ); + + $this->assertEquals(array( + 'groups' => + array( + 'fieldName' => 'groups', + 'targetEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsGroup', + 'cascade' => + array( + 0 => 'remove', + 1 => 'persist', + 2 => 'refresh', + 3 => 'merge', + 4 => 'detach', + ), + 'fetch' => 4, + 'joinTable' => + array( + 'joinColumns' => + array( + 0 => + array( + 'name' => 'group_id', + 'referencedColumnName' => 'id', + 'nullable' => true, + 'unique' => false, + 'onDelete' => 'CASCADE', + 'columnDefinition' => NULL, + ), + ), + 'inverseJoinColumns' => + array( + 0 => + array( + 'name' => 'user_id', + 'referencedColumnName' => 'id', + 'nullable' => true, + 'unique' => false, + 'onDelete' => NULL, + 'columnDefinition' => NULL, + ), + ), + 'name' => 'groups_users', + ), + 'type' => 8, + 'mappedBy' => NULL, + 'inversedBy' => NULL, + 'isOwningSide' => true, + 'sourceEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', + 'isCascadeRemove' => true, + 'isCascadePersist' => true, + 'isCascadeRefresh' => true, + 'isCascadeMerge' => true, + 'isCascadeDetach' => true, + 'isOnDeleteCascade' => true, + 'relationToSourceKeyColumns' => + array( + 'group_id' => 'id', + ), + 'joinTableColumns' => + array( + 0 => 'group_id', + 1 => 'user_id', + ), + 'relationToTargetKeyColumns' => + array( + 'user_id' => 'id', + ), + 'orphanRemoval' => false, + ), + ), $this->cm->associationMappings); + } + + public function testCreateOneToMany() + { + $this->assertIsFluent( + $this->builder->createOneToMany('groups', 'Doctrine\Tests\Models\CMS\CmsGroup') + ->mappedBy('test') + ->setOrderBy(array('test')) + ->setIndexBy('test') + ->build() + ); + + $this->assertEquals(array( + 'groups' => + array( + 'fieldName' => 'groups', + 'targetEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsGroup', + 'mappedBy' => 'test', + 'orderBy' => + array( + 0 => 'test', + ), + 'indexBy' => 'test', + 'type' => 4, + 'inversedBy' => NULL, + 'isOwningSide' => false, + 'sourceEntity' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', + 'fetch' => 2, + 'cascade' => + array( + ), + 'isCascadeRemove' => false, + 'isCascadePersist' => false, + 'isCascadeRefresh' => false, + 'isCascadeMerge' => false, + 'isCascadeDetach' => false, + 'orphanRemoval' => false, + ), + ), $this->cm->associationMappings); + } + + public function assertIsFluent($ret) + { + $this->assertSame($this->builder, $ret, "Return Value has to be same instance as used builder"); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php new file mode 100644 index 0000000..100e4df --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php @@ -0,0 +1,368 @@ +_createEntityManager($mockDriver); + + $conn = $entityManager->getConnection(); + $mockPlatform = $conn->getDatabasePlatform(); + $mockPlatform->setPrefersSequences(true); + $mockPlatform->setPrefersIdentityColumns(false); + + $cm1 = $this->_createValidClassMetadata(); + + // SUT + $cmf = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + $cmf->setEntityManager($entityManager); + $cmf->setMetadataFor($cm1->name, $cm1); + + // Prechecks + $this->assertEquals(array(), $cm1->parentClasses); + $this->assertEquals(ClassMetadata::INHERITANCE_TYPE_NONE, $cm1->inheritanceType); + $this->assertTrue($cm1->hasField('name')); + $this->assertEquals(2, count($cm1->associationMappings)); + $this->assertEquals(ClassMetadata::GENERATOR_TYPE_AUTO, $cm1->generatorType); + $this->assertEquals('group', $cm1->table['name']); + + // Go + $cmMap1 = $cmf->getMetadataFor($cm1->name); + + $this->assertSame($cm1, $cmMap1); + $this->assertEquals('group', $cmMap1->table['name']); + $this->assertTrue($cmMap1->table['quoted']); + $this->assertEquals(array(), $cmMap1->parentClasses); + $this->assertTrue($cmMap1->hasField('name')); + } + + public function testGetMetadataFor_ReturnsLoadedCustomIdGenerator() + { + $cm1 = $this->_createValidClassMetadata(); + $cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM); + $cm1->customGeneratorDefinition = array( + "class" => "Doctrine\Tests\ORM\Mapping\CustomIdGenerator"); + $cmf = $this->_createTestFactory(); + $cmf->setMetadataForClass($cm1->name, $cm1); + + $actual = $cmf->getMetadataFor($cm1->name); + + $this->assertEquals(ClassMetadata::GENERATOR_TYPE_CUSTOM, + $actual->generatorType); + $this->assertInstanceOf("Doctrine\Tests\ORM\Mapping\CustomIdGenerator", + $actual->idGenerator); + } + + public function testGetMetadataFor_ThrowsExceptionOnUnknownCustomGeneratorClass() + { + $cm1 = $this->_createValidClassMetadata(); + $cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM); + $cm1->customGeneratorDefinition = array("class" => "NotExistingGenerator"); + $cmf = $this->_createTestFactory(); + $cmf->setMetadataForClass($cm1->name, $cm1); + $this->setExpectedException("Doctrine\ORM\ORMException"); + + $actual = $cmf->getMetadataFor($cm1->name); + } + + public function testGetMetadataFor_ThrowsExceptionOnMissingCustomGeneratorDefinition() + { + $cm1 = $this->_createValidClassMetadata(); + $cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM); + $cmf = $this->_createTestFactory(); + $cmf->setMetadataForClass($cm1->name, $cm1); + $this->setExpectedException("Doctrine\ORM\ORMException"); + + $actual = $cmf->getMetadataFor($cm1->name); + } + + public function testHasGetMetadata_NamespaceSeperatorIsNotNormalized() + { + require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php"; + + $metadataDriver = $this->createAnnotationDriver(array(__DIR__ . '/../../Models/Global/')); + + $entityManager = $this->_createEntityManager($metadataDriver); + + $mf = $entityManager->getMetadataFactory(); + $m1 = $mf->getMetadataFor("DoctrineGlobal_Article"); + $h1 = $mf->hasMetadataFor("DoctrineGlobal_Article"); + $h2 = $mf->hasMetadataFor("\DoctrineGlobal_Article"); + $m2 = $mf->getMetadataFor("\DoctrineGlobal_Article"); + + $this->assertNotSame($m1, $m2); + $this->assertFalse($h2); + $this->assertTrue($h1); + } + + /** + * @group DDC-1512 + */ + public function testIsTransient() + { + $cmf = new ClassMetadataFactory(); + $driver = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $driver->expects($this->at(0)) + ->method('isTransient') + ->with($this->equalTo('Doctrine\Tests\Models\CMS\CmsUser')) + ->will($this->returnValue(true)); + $driver->expects($this->at(1)) + ->method('isTransient') + ->with($this->equalTo('Doctrine\Tests\Models\CMS\CmsArticle')) + ->will($this->returnValue(false)); + + $em = $this->_createEntityManager($driver); + + $this->assertTrue($em->getMetadataFactory()->isTransient('Doctrine\Tests\Models\CMS\CmsUser')); + $this->assertFalse($em->getMetadataFactory()->isTransient('Doctrine\Tests\Models\CMS\CmsArticle')); + } + + /** + * @group DDC-1512 + */ + public function testIsTransientEntityNamespace() + { + $cmf = new ClassMetadataFactory(); + $driver = $this->getMock('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver'); + $driver->expects($this->at(0)) + ->method('isTransient') + ->with($this->equalTo('Doctrine\Tests\Models\CMS\CmsUser')) + ->will($this->returnValue(true)); + $driver->expects($this->at(1)) + ->method('isTransient') + ->with($this->equalTo('Doctrine\Tests\Models\CMS\CmsArticle')) + ->will($this->returnValue(false)); + + $em = $this->_createEntityManager($driver); + $em->getConfiguration()->addEntityNamespace('CMS', 'Doctrine\Tests\Models\CMS'); + + $this->assertTrue($em->getMetadataFactory()->isTransient('CMS:CmsUser')); + $this->assertFalse($em->getMetadataFactory()->isTransient('CMS:CmsArticle')); + } + + public function testAddDefaultDiscriminatorMap() + { + $cmf = new ClassMetadataFactory(); + $driver = $this->createAnnotationDriver(array(__DIR__ . '/../../Models/JoinedInheritanceType/')); + $em = $this->_createEntityManager($driver); + $cmf->setEntityManager($em); + + $rootMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\RootClass'); + $childMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\ChildClass'); + $anotherChildMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\AnotherChildClass'); + $rootDiscriminatorMap = $rootMetadata->discriminatorMap; + $childDiscriminatorMap = $childMetadata->discriminatorMap; + $anotherChildDiscriminatorMap = $anotherChildMetadata->discriminatorMap; + + $rootClass = 'Doctrine\Tests\Models\JoinedInheritanceType\RootClass'; + $childClass = 'Doctrine\Tests\Models\JoinedInheritanceType\ChildClass'; + $anotherChildClass = 'Doctrine\Tests\Models\JoinedInheritanceType\AnotherChildClass'; + + $rootClassKey = array_search($rootClass, $rootDiscriminatorMap); + $childClassKey = array_search($childClass, $rootDiscriminatorMap); + $anotherChildClassKey = array_search($anotherChildClass, $rootDiscriminatorMap); + + $this->assertEquals('rootclass', $rootClassKey); + $this->assertEquals('childclass', $childClassKey); + $this->assertEquals('anotherchildclass', $anotherChildClassKey); + + $this->assertEquals($childDiscriminatorMap, $rootDiscriminatorMap); + $this->assertEquals($anotherChildDiscriminatorMap, $rootDiscriminatorMap); + + // ClassMetadataFactory::addDefaultDiscriminatorMap shouldn't be called again, because the + // discriminator map is already cached + $cmf = $this->getMock('Doctrine\ORM\Mapping\ClassMetadataFactory', array('addDefaultDiscriminatorMap')); + $cmf->setEntityManager($em); + $cmf->expects($this->never()) + ->method('addDefaultDiscriminatorMap'); + + $rootMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\JoinedInheritanceType\RootClass'); + } + + protected function _createEntityManager($metadataDriver) + { + $driverMock = new DriverMock(); + $config = new \Doctrine\ORM\Configuration(); + $config->setProxyDir(__DIR__ . '/../../Proxies'); + $config->setProxyNamespace('Doctrine\Tests\Proxies'); + $eventManager = new EventManager(); + $conn = new ConnectionMock(array(), $driverMock, $config, $eventManager); + $mockDriver = new MetadataDriverMock(); + $config->setMetadataDriverImpl($metadataDriver); + + return EntityManagerMock::create($conn, $config, $eventManager); + } + + /** + * @return ClassMetadataFactoryTestSubject + */ + protected function _createTestFactory() + { + $mockDriver = new MetadataDriverMock(); + $entityManager = $this->_createEntityManager($mockDriver); + $cmf = new ClassMetadataFactoryTestSubject(); + $cmf->setEntityManager($entityManager); + return $cmf; + } + + /** + * @param string $class + * @return ClassMetadata + */ + protected function _createValidClassMetadata() + { + // Self-made metadata + $cm1 = new ClassMetadata('Doctrine\Tests\ORM\Mapping\TestEntity1'); + $cm1->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm1->setPrimaryTable(array('name' => '`group`')); + // Add a mapped field + $cm1->mapField(array('fieldName' => 'name', 'type' => 'varchar')); + // Add a mapped field + $cm1->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true)); + // and a mapped association + $cm1->mapOneToOne(array('fieldName' => 'other', 'targetEntity' => 'TestEntity1', 'mappedBy' => 'this')); + // and an association on the owning side + $joinColumns = array( + array('name' => 'other_id', 'referencedColumnName' => 'id') + ); + $cm1->mapOneToOne(array('fieldName' => 'association', 'targetEntity' => 'TestEntity1', 'joinColumns' => $joinColumns)); + // and an id generator type + $cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO); + return $cm1; + } + + /** + * @group DDC-1845 + */ + public function testQuoteMetadata() + { + $cmf = new ClassMetadataFactory(); + $driver = $this->createAnnotationDriver(array(__DIR__ . '/../../Models/Quote/')); + $em = $this->_createEntityManager($driver); + $cmf->setEntityManager($em); + + + $userMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\Quote\User'); + $phoneMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\Quote\Phone'); + $groupMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\Quote\Group'); + $addressMetadata = $cmf->getMetadataFor('Doctrine\Tests\Models\Quote\Address'); + + + // Phone Class Metadata + $this->assertTrue($phoneMetadata->fieldMappings['number']['quoted']); + $this->assertEquals('phone-number', $phoneMetadata->fieldMappings['number']['columnName']); + + $user = $phoneMetadata->associationMappings['user']; + $this->assertTrue($user['joinColumns'][0]['quoted']); + $this->assertEquals('user-id', $user['joinColumns'][0]['name']); + $this->assertEquals('user-id', $user['joinColumns'][0]['referencedColumnName']); + + + + // User Group Metadata + $this->assertTrue($groupMetadata->fieldMappings['id']['quoted']); + $this->assertTrue($groupMetadata->fieldMappings['name']['quoted']); + + $this->assertEquals('user-id', $userMetadata->fieldMappings['id']['columnName']); + $this->assertEquals('user-name', $userMetadata->fieldMappings['name']['columnName']); + + $user = $groupMetadata->associationMappings['parent']; + $this->assertTrue($user['joinColumns'][0]['quoted']); + $this->assertEquals('parent-id', $user['joinColumns'][0]['name']); + $this->assertEquals('group-id', $user['joinColumns'][0]['referencedColumnName']); + + + // Address Class Metadata + $this->assertTrue($addressMetadata->fieldMappings['id']['quoted']); + $this->assertTrue($addressMetadata->fieldMappings['zip']['quoted']); + + $this->assertEquals('address-id', $addressMetadata->fieldMappings['id']['columnName']); + $this->assertEquals('address-zip', $addressMetadata->fieldMappings['zip']['columnName']); + + $user = $addressMetadata->associationMappings['user']; + $this->assertTrue($user['joinColumns'][0]['quoted']); + $this->assertEquals('user-id', $user['joinColumns'][0]['name']); + $this->assertEquals('user-id', $user['joinColumns'][0]['referencedColumnName']); + + + + // User Class Metadata + $this->assertTrue($userMetadata->fieldMappings['id']['quoted']); + $this->assertTrue($userMetadata->fieldMappings['name']['quoted']); + + $this->assertEquals('user-id', $userMetadata->fieldMappings['id']['columnName']); + $this->assertEquals('user-name', $userMetadata->fieldMappings['name']['columnName']); + + + $address = $userMetadata->associationMappings['address']; + $this->assertTrue($address['joinColumns'][0]['quoted']); + $this->assertEquals('address-id', $address['joinColumns'][0]['name']); + $this->assertEquals('address-id', $address['joinColumns'][0]['referencedColumnName']); + + $groups = $userMetadata->associationMappings['groups']; + $this->assertTrue($groups['joinTable']['quoted']); + $this->assertTrue($groups['joinTable']['joinColumns'][0]['quoted']); + $this->assertEquals('quote-users-groups', $groups['joinTable']['name']); + $this->assertEquals('user-id', $groups['joinTable']['joinColumns'][0]['name']); + $this->assertEquals('user-id', $groups['joinTable']['joinColumns'][0]['referencedColumnName']); + + $this->assertTrue($groups['joinTable']['inverseJoinColumns'][0]['quoted']); + $this->assertEquals('group-id', $groups['joinTable']['inverseJoinColumns'][0]['name']); + $this->assertEquals('group-id', $groups['joinTable']['inverseJoinColumns'][0]['referencedColumnName']); + } +} + +/* Test subject class with overriden factory method for mocking purposes */ +class ClassMetadataFactoryTestSubject extends \Doctrine\ORM\Mapping\ClassMetadataFactory +{ + private $mockMetadata = array(); + private $requestedClasses = array(); + + /** @override */ + protected function newClassMetadataInstance($className) + { + $this->requestedClasses[] = $className; + if ( ! isset($this->mockMetadata[$className])) { + throw new InvalidArgumentException("No mock metadata found for class $className."); + } + return $this->mockMetadata[$className]; + } + + public function setMetadataForClass($className, $metadata) + { + $this->mockMetadata[$className] = $metadata; + } + + public function getRequestedClasses() + { + return $this->requestedClasses; + } +} + +class TestEntity1 +{ + private $id; + private $name; + private $other; + private $association; +} + +class CustomIdGenerator extends \Doctrine\ORM\Id\AbstractIdGenerator +{ + public function generate(\Doctrine\ORM\EntityManager $em, $entity) + { + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataLoadEventTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataLoadEventTest.php new file mode 100644 index 0000000..70aae70 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataLoadEventTest.php @@ -0,0 +1,56 @@ +_getTestEntityManager(); + $metadataFactory = $em->getMetadataFactory(); + $evm = $em->getEventManager(); + $evm->addEventListener(Events::loadClassMetadata, $this); + $classMetadata = $metadataFactory->getMetadataFor('Doctrine\Tests\ORM\Mapping\LoadEventTestEntity'); + $this->assertTrue($classMetadata->hasField('about')); + $this->assertArrayHasKey('about', $classMetadata->reflFields); + $this->assertInstanceOf('ReflectionProperty', $classMetadata->reflFields['about']); + } + + public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs) + { + $classMetadata = $eventArgs->getClassMetadata(); + $field = array( + 'fieldName' => 'about', + 'type' => 'string', + 'length' => 255 + ); + $classMetadata->mapField($field); + } +} + +/** + * @Entity + * @Table(name="load_event_test_entity") + */ +class LoadEventTestEntity +{ + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + /** + * @Column(type="string", length=255) + */ + private $name; + + private $about; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php new file mode 100644 index 0000000..954985e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php @@ -0,0 +1,995 @@ +initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + // Test initial state + $this->assertTrue(count($cm->getReflectionProperties()) == 0); + $this->assertInstanceOf('ReflectionClass', $cm->reflClass); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $cm->name); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $cm->rootEntityName); + $this->assertEquals(array(), $cm->subClasses); + $this->assertEquals(array(), $cm->parentClasses); + $this->assertEquals(ClassMetadata::INHERITANCE_TYPE_NONE, $cm->inheritanceType); + + // Customize state + $cm->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE); + $cm->setSubclasses(array("One", "Two", "Three")); + $cm->setParentClasses(array("UserParent")); + $cm->setCustomRepositoryClass("UserRepository"); + $cm->setDiscriminatorColumn(array('name' => 'disc', 'type' => 'integer')); + $cm->mapOneToOne(array('fieldName' => 'phonenumbers', 'targetEntity' => 'CmsAddress', 'mappedBy' => 'foo')); + $cm->markReadOnly(); + $cm->addNamedQuery(array('name' => 'dql', 'query' => 'foo')); + $this->assertEquals(1, count($cm->associationMappings)); + + $serialized = serialize($cm); + $cm = unserialize($serialized); + $cm->wakeupReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + // Check state + $this->assertTrue(count($cm->getReflectionProperties()) > 0); + $this->assertEquals('Doctrine\Tests\Models\CMS', $cm->namespace); + $this->assertInstanceOf('ReflectionClass', $cm->reflClass); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $cm->name); + $this->assertEquals('UserParent', $cm->rootEntityName); + $this->assertEquals(array('Doctrine\Tests\Models\CMS\One', 'Doctrine\Tests\Models\CMS\Two', 'Doctrine\Tests\Models\CMS\Three'), $cm->subClasses); + $this->assertEquals(array('UserParent'), $cm->parentClasses); + $this->assertEquals('Doctrine\Tests\Models\CMS\UserRepository', $cm->customRepositoryClassName); + $this->assertEquals(array('name' => 'disc', 'type' => 'integer', 'fieldName' => 'disc'), $cm->discriminatorColumn); + $this->assertTrue($cm->associationMappings['phonenumbers']['type'] == ClassMetadata::ONE_TO_ONE); + $this->assertEquals(1, count($cm->associationMappings)); + $oneOneMapping = $cm->getAssociationMapping('phonenumbers'); + $this->assertTrue($oneOneMapping['fetch'] == ClassMetadata::FETCH_LAZY); + $this->assertEquals('phonenumbers', $oneOneMapping['fieldName']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress', $oneOneMapping['targetEntity']); + $this->assertTrue($cm->isReadOnly); + $this->assertEquals(array('dql' => array('name'=>'dql','query'=>'foo','dql'=>'foo')), $cm->namedQueries); + } + + public function testFieldIsNullable() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + // Explicit Nullable + $cm->mapField(array('fieldName' => 'status', 'nullable' => true, 'type' => 'string', 'length' => 50)); + $this->assertTrue($cm->isNullable('status')); + + // Explicit Not Nullable + $cm->mapField(array('fieldName' => 'username', 'nullable' => false, 'type' => 'string', 'length' => 50)); + $this->assertFalse($cm->isNullable('username')); + + // Implicit Not Nullable + $cm->mapField(array('fieldName' => 'name', 'type' => 'string', 'length' => 50)); + $this->assertFalse($cm->isNullable('name'), "By default a field should not be nullable."); + } + + /** + * @group DDC-115 + */ + public function testMapAssocationInGlobalNamespace() + { + require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php"; + + $cm = new ClassMetadata('DoctrineGlobal_Article'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->mapManyToMany(array( + 'fieldName' => 'author', + 'targetEntity' => 'DoctrineGlobal_User', + 'joinTable' => array( + 'name' => 'bar', + 'joinColumns' => array(array('name' => 'bar_id', 'referencedColumnName' => 'id')), + 'inverseJoinColumns' => array(array('name' => 'baz_id', 'referencedColumnName' => 'id')), + ), + )); + + $this->assertEquals("DoctrineGlobal_User", $cm->associationMappings['author']['targetEntity']); + } + + public function testMapManyToManyJoinTableDefaults() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->mapManyToMany( + array( + 'fieldName' => 'groups', + 'targetEntity' => 'CmsGroup' + )); + + $assoc = $cm->associationMappings['groups']; + //$this->assertInstanceOf('Doctrine\ORM\Mapping\ManyToManyMapping', $assoc); + $this->assertEquals(array( + 'name' => 'cmsuser_cmsgroup', + 'joinColumns' => array(array('name' => 'cmsuser_id', 'referencedColumnName' => 'id', 'onDelete' => 'CASCADE')), + 'inverseJoinColumns' => array(array('name' => 'cmsgroup_id', 'referencedColumnName' => 'id', 'onDelete' => 'CASCADE')) + ), $assoc['joinTable']); + $this->assertTrue($assoc['isOnDeleteCascade']); + } + + public function testSerializeManyToManyJoinTableCascade() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->mapManyToMany( + array( + 'fieldName' => 'groups', + 'targetEntity' => 'CmsGroup' + )); + + /* @var $assoc \Doctrine\ORM\Mapping\ManyToManyMapping */ + $assoc = $cm->associationMappings['groups']; + $assoc = unserialize(serialize($assoc)); + + $this->assertTrue($assoc['isOnDeleteCascade']); + } + + /** + * @group DDC-115 + */ + public function testSetDiscriminatorMapInGlobalNamespace() + { + require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php"; + + $cm = new ClassMetadata('DoctrineGlobal_User'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->setDiscriminatorMap(array('descr' => 'DoctrineGlobal_Article', 'foo' => 'DoctrineGlobal_User')); + + $this->assertEquals("DoctrineGlobal_Article", $cm->discriminatorMap['descr']); + $this->assertEquals("DoctrineGlobal_User", $cm->discriminatorMap['foo']); + } + + /** + * @group DDC-115 + */ + public function testSetSubClassesInGlobalNamespace() + { + require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php"; + + $cm = new ClassMetadata('DoctrineGlobal_User'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->setSubclasses(array('DoctrineGlobal_Article')); + + $this->assertEquals("DoctrineGlobal_Article", $cm->subClasses[0]); + } + + /** + * @group DDC-268 + */ + public function testSetInvalidVersionMapping_ThrowsException() + { + $field = array(); + $field['fieldName'] = 'foo'; + $field['type'] = 'string'; + + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + $cm->setVersionMapping($field); + } + + public function testGetSingleIdentifierFieldName_MultipleIdentifierEntity_ThrowsException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->isIdentifierComposite = true; + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + $cm->getSingleIdentifierFieldName(); + } + + public function testDuplicateAssociationMappingException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $a1 = array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo'); + $a2 = array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo'); + + $cm->addInheritedAssociationMapping($a1); + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + $cm->addInheritedAssociationMapping($a2); + } + + public function testDuplicateColumnName_ThrowsMappingException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->mapField(array('fieldName' => 'name', 'columnName' => 'name')); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + $cm->mapField(array('fieldName' => 'username', 'columnName' => 'name')); + } + + public function testDuplicateColumnName_DiscriminatorColumn_ThrowsMappingException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->mapField(array('fieldName' => 'name', 'columnName' => 'name')); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + $cm->setDiscriminatorColumn(array('name' => 'name')); + } + + public function testDuplicateColumnName_DiscriminatorColumn2_ThrowsMappingException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->setDiscriminatorColumn(array('name' => 'name')); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + $cm->mapField(array('fieldName' => 'name', 'columnName' => 'name')); + } + + public function testDuplicateFieldAndAssocationMapping1_ThrowsException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->mapField(array('fieldName' => 'name', 'columnName' => 'name')); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + $cm->mapOneToOne(array('fieldName' => 'name', 'targetEntity' => 'CmsUser')); + } + + public function testDuplicateFieldAndAssocationMapping2_ThrowsException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->mapOneToOne(array('fieldName' => 'name', 'targetEntity' => 'CmsUser')); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException'); + $cm->mapField(array('fieldName' => 'name', 'columnName' => 'name')); + } + + /** + * @group DDC-1224 + */ + public function testGetTemporaryTableNameSchema() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->setTableName('foo.bar'); + + $this->assertEquals('foo_bar_id_tmp', $cm->getTemporaryIdTableName()); + } + + public function testDefaultTableName() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + // When table's name is not given + $primaryTable = array(); + $cm->setPrimaryTable($primaryTable); + + $this->assertEquals('CmsUser', $cm->getTableName()); + $this->assertEquals('CmsUser', $cm->table['name']); + + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + // When joinTable's name is not given + $cm->mapManyToMany(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser', + 'inversedBy' => 'users', + 'joinTable' => array('joinColumns' => array(array('referencedColumnName' => 'id')), + 'inverseJoinColumns' => array(array('referencedColumnName' => 'id'))))); + $this->assertEquals('cmsaddress_cmsuser', $cm->associationMappings['user']['joinTable']['name']); + } + + public function testDefaultJoinColumnName() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + // this is really dirty, but it's the simpliest way to test whether + // joinColumn's name will be automatically set to user_id + $cm->mapOneToOne(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser', + 'joinColumns' => array(array('referencedColumnName' => 'id')))); + $this->assertEquals('user_id', $cm->associationMappings['user']['joinColumns'][0]['name']); + + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->mapManyToMany(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser', + 'inversedBy' => 'users', + 'joinTable' => array('name' => 'user_CmsUser', + 'joinColumns' => array(array('referencedColumnName' => 'id')), + 'inverseJoinColumns' => array(array('referencedColumnName' => 'id'))))); + $this->assertEquals('cmsaddress_id', $cm->associationMappings['user']['joinTable']['joinColumns'][0]['name']); + $this->assertEquals('cmsuser_id', $cm->associationMappings['user']['joinTable']['inverseJoinColumns'][0]['name']); + } + + /** + * @group DDC-559 + */ + public function testUnderscoreNamingStrategyDefaults() + { + $namingStrategy = new \Doctrine\ORM\Mapping\UnderscoreNamingStrategy(CASE_UPPER); + $oneToOneMetadata = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', $namingStrategy); + $manyToManyMetadata = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', $namingStrategy); + + $oneToOneMetadata->mapOneToOne(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser' + )); + + $manyToManyMetadata->mapManyToMany(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser' + )); + + $this->assertEquals(array('USER_ID'=>'ID'), $oneToOneMetadata->associationMappings['user']['sourceToTargetKeyColumns']); + $this->assertEquals(array('USER_ID'=>'USER_ID'), $oneToOneMetadata->associationMappings['user']['joinColumnFieldNames']); + $this->assertEquals(array('ID'=>'USER_ID'), $oneToOneMetadata->associationMappings['user']['targetToSourceKeyColumns']); + + $this->assertEquals('USER_ID', $oneToOneMetadata->associationMappings['user']['joinColumns'][0]['name']); + $this->assertEquals('ID', $oneToOneMetadata->associationMappings['user']['joinColumns'][0]['referencedColumnName']); + + + $this->assertEquals('CMS_ADDRESS_CMS_USER', $manyToManyMetadata->associationMappings['user']['joinTable']['name']); + + $this->assertEquals(array('CMS_ADDRESS_ID','CMS_USER_ID'), $manyToManyMetadata->associationMappings['user']['joinTableColumns']); + $this->assertEquals(array('CMS_ADDRESS_ID'=>'ID'), $manyToManyMetadata->associationMappings['user']['relationToSourceKeyColumns']); + $this->assertEquals(array('CMS_USER_ID'=>'ID'), $manyToManyMetadata->associationMappings['user']['relationToTargetKeyColumns']); + + $this->assertEquals('CMS_ADDRESS_ID', $manyToManyMetadata->associationMappings['user']['joinTable']['joinColumns'][0]['name']); + $this->assertEquals('CMS_USER_ID', $manyToManyMetadata->associationMappings['user']['joinTable']['inverseJoinColumns'][0]['name']); + + $this->assertEquals('ID', $manyToManyMetadata->associationMappings['user']['joinTable']['joinColumns'][0]['referencedColumnName']); + $this->assertEquals('ID', $manyToManyMetadata->associationMappings['user']['joinTable']['inverseJoinColumns'][0]['referencedColumnName']); + + + $cm = new ClassMetadata('DoctrineGlobal_Article', $namingStrategy); + $cm->mapManyToMany(array('fieldName' => 'author', 'targetEntity' => 'Doctrine\Tests\Models\CMS\CmsUser')); + $this->assertEquals('DOCTRINE_GLOBAL_ARTICLE_CMS_USER', $cm->associationMappings['author']['joinTable']['name']); + } + + /** + * @group DDC-886 + */ + public function testSetMultipleIdentifierSetsComposite() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->mapField(array('fieldName' => 'name')); + $cm->mapField(array('fieldName' => 'username')); + + $cm->setIdentifier(array('name', 'username')); + $this->assertTrue($cm->isIdentifierComposite); + } + + /** + * @group DDC-944 + */ + public function testMappingNotFound() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', "No mapping found for field 'foo' on class 'Doctrine\Tests\Models\CMS\CmsUser'."); + $cm->getFieldMapping('foo'); + } + + /** + * @group DDC-961 + */ + public function testJoinTableMappingDefaults() + { + $cm = new ClassMetadata('DoctrineGlobal_Article'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->mapManyToMany(array('fieldName' => 'author', 'targetEntity' => 'Doctrine\Tests\Models\CMS\CmsUser')); + + $this->assertEquals('doctrineglobal_article_cmsuser', $cm->associationMappings['author']['joinTable']['name']); + } + + /** + * @group DDC-117 + */ + public function testMapIdentifierAssociation() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->mapOneToOne(array( + 'fieldName' => 'article', + 'id' => true, + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'joinColumns' => array(), + )); + + $this->assertTrue($cm->containsForeignIdentifier, "Identifier Association should set 'containsForeignIdentifier' boolean flag."); + $this->assertEquals(array("article"), $cm->identifier); + } + + /** + * @group DDC-117 + */ + public function testOrphanRemovalIdentifierAssociation() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'The orphan removal option is not allowed on an association that'); + $cm->mapOneToOne(array( + 'fieldName' => 'article', + 'id' => true, + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'orphanRemoval' => true, + 'joinColumns' => array(), + )); + } + + /** + * @group DDC-117 + */ + public function testInverseIdentifierAssocation() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'An inverse association is not allowed to be identifier in'); + $cm->mapOneToOne(array( + 'fieldName' => 'article', + 'id' => true, + 'mappedBy' => 'details', // INVERSE! + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'joinColumns' => array(), + )); + } + + /** + * @group DDC-117 + */ + public function testIdentifierAssocationManyToMany() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'Many-to-many or one-to-many associations are not allowed to be identifier in'); + $cm->mapManyToMany(array( + 'fieldName' => 'article', + 'id' => true, + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'joinColumns' => array(), + )); + } + + /** + * @group DDC-996 + */ + public function testEmptyFieldNameThrowsException() + { + $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', + "The field or association mapping misses the 'fieldName' attribute in entity 'Doctrine\Tests\Models\CMS\CmsUser'."); + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->mapField(array('fieldName' => '')); + } + + public function testRetrievalOfNamedQueries() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + + $this->assertEquals(0, count($cm->getNamedQueries())); + + $cm->addNamedQuery(array( + 'name' => 'userById', + 'query' => 'SELECT u FROM __CLASS__ u WHERE u.id = ?1' + )); + + $this->assertEquals(1, count($cm->getNamedQueries())); + } + + /** + * @group DDC-1663 + */ + public function testRetrievalOfResultSetMappings() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + + $this->assertEquals(0, count($cm->getSqlResultSetMappings())); + + $cm->addSqlResultSetMapping(array( + 'name' => 'find-all', + 'entities' => array( + array( + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + ), + ), + )); + + $this->assertEquals(1, count($cm->getSqlResultSetMappings())); + } + + public function testExistanceOfNamedQuery() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + + $cm->addNamedQuery(array( + 'name' => 'all', + 'query' => 'SELECT u FROM __CLASS__ u' + )); + + $this->assertTrue($cm->hasNamedQuery('all')); + $this->assertFalse($cm->hasNamedQuery('userById')); + } + + /** + * @group DDC-1663 + */ + public function testRetrieveOfNamedNativeQuery() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->addNamedNativeQuery(array( + 'name' => 'find-all', + 'query' => 'SELECT * FROM cms_users', + 'resultSetMapping' => 'result-mapping-name', + 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + )); + + $cm->addNamedNativeQuery(array( + 'name' => 'find-by-id', + 'query' => 'SELECT * FROM cms_users WHERE id = ?', + 'resultClass' => '__CLASS__', + 'resultSetMapping' => 'result-mapping-name', + )); + + $mapping = $cm->getNamedNativeQuery('find-all'); + $this->assertEquals('SELECT * FROM cms_users', $mapping['query']); + $this->assertEquals('result-mapping-name', $mapping['resultSetMapping']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $mapping['resultClass']); + + $mapping = $cm->getNamedNativeQuery('find-by-id'); + $this->assertEquals('SELECT * FROM cms_users WHERE id = ?', $mapping['query']); + $this->assertEquals('result-mapping-name', $mapping['resultSetMapping']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $mapping['resultClass']); + } + + /** + * @group DDC-1663 + */ + public function testRetrieveOfSqlResultSetMapping() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->addSqlResultSetMapping(array( + 'name' => 'find-all', + 'entities' => array( + array( + 'entityClass' => '__CLASS__', + 'fields' => array( + array( + 'name' => 'id', + 'column'=> 'id' + ), + array( + 'name' => 'name', + 'column'=> 'name' + ) + ) + ), + array( + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsEmail', + 'fields' => array( + array( + 'name' => 'id', + 'column'=> 'id' + ), + array( + 'name' => 'email', + 'column'=> 'email' + ) + ) + ) + ), + 'columns' => array( + array( + 'name' => 'scalarColumn' + ) + ) + )); + + $mapping = $cm->getSqlResultSetMapping('find-all'); + + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $mapping['entities'][0]['entityClass']); + $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][0]['fields'][0]); + $this->assertEquals(array('name'=>'name','column'=>'name'), $mapping['entities'][0]['fields'][1]); + + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsEmail', $mapping['entities'][1]['entityClass']); + $this->assertEquals(array('name'=>'id','column'=>'id'), $mapping['entities'][1]['fields'][0]); + $this->assertEquals(array('name'=>'email','column'=>'email'), $mapping['entities'][1]['fields'][1]); + + $this->assertEquals('scalarColumn', $mapping['columns'][0]['name']); + } + + /** + * @group DDC-1663 + */ + public function testExistanceOfSqlResultSetMapping() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->addSqlResultSetMapping(array( + 'name' => 'find-all', + 'entities' => array( + array( + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + ), + ), + )); + + $this->assertTrue($cm->hasSqlResultSetMapping('find-all')); + $this->assertFalse($cm->hasSqlResultSetMapping('find-by-id')); + } + + /** + * @group DDC-1663 + */ + public function testExistanceOfNamedNativeQuery() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + + $cm->addNamedNativeQuery(array( + 'name' => 'find-all', + 'query' => 'SELECT * FROM cms_users', + 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'resultSetMapping' => 'result-mapping-name' + )); + + $this->assertTrue($cm->hasNamedNativeQuery('find-all')); + $this->assertFalse($cm->hasNamedNativeQuery('find-by-id')); + } + + public function testRetrieveOfNamedQuery() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + + $cm->addNamedQuery(array( + 'name' => 'userById', + 'query' => 'SELECT u FROM __CLASS__ u WHERE u.id = ?1' + )); + + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1', $cm->getNamedQuery('userById')); + } + + /** + * @group DDC-1663 + */ + public function testRetrievalOfNamedNativeQueries() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $this->assertEquals(0, count($cm->getNamedNativeQueries())); + + $cm->addNamedNativeQuery(array( + 'name' => 'find-all', + 'query' => 'SELECT * FROM cms_users', + 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'resultSetMapping' => 'result-mapping-name' + )); + + $this->assertEquals(1, count($cm->getNamedNativeQueries())); + } + + /** + * @expectedException \Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Query named "userById" in "Doctrine\Tests\Models\CMS\CmsUser" was already declared, but it must be declared only once + */ + public function testNamingCollisionNamedQueryShouldThrowException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->addNamedQuery(array( + 'name' => 'userById', + 'query' => 'SELECT u FROM __CLASS__ u WHERE u.id = ?1' + )); + + $cm->addNamedQuery(array( + 'name' => 'userById', + 'query' => 'SELECT u FROM __CLASS__ u WHERE u.id = ?1' + )); + } + + /** + * @group DDC-1663 + * + * @expectedException \Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Query named "find-all" in "Doctrine\Tests\Models\CMS\CmsUser" was already declared, but it must be declared only once + */ + public function testNamingCollisionNamedNativeQueryShouldThrowException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->addNamedNativeQuery(array( + 'name' => 'find-all', + 'query' => 'SELECT * FROM cms_users', + 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'resultSetMapping' => 'result-mapping-name' + )); + + $cm->addNamedNativeQuery(array( + 'name' => 'find-all', + 'query' => 'SELECT * FROM cms_users', + 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'resultSetMapping' => 'result-mapping-name' + )); + } + + /** + * @group DDC-1663 + * + * @expectedException \Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Result set mapping named "find-all" in "Doctrine\Tests\Models\CMS\CmsUser" was already declared, but it must be declared only once + */ + public function testNamingCollisionSqlResultSetMappingShouldThrowException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $cm->addSqlResultSetMapping(array( + 'name' => 'find-all', + 'entities' => array( + array( + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + ), + ), + )); + + $cm->addSqlResultSetMapping(array( + 'name' => 'find-all', + 'entities' => array( + array( + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + ), + ), + )); + } + + /** + * @group DDC-1068 + */ + public function testClassCaseSensitivity() + { + $user = new \Doctrine\Tests\Models\CMS\CmsUser(); + $cm = new ClassMetadata('DOCTRINE\TESTS\MODELS\CMS\CMSUSER'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $cm->name); + } + + /** + * @group DDC-659 + */ + public function testLifecycleCallbackNotFound() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->addLifecycleCallback('notfound', 'postLoad'); + + $this->setExpectedException("Doctrine\ORM\Mapping\MappingException", "Entity 'Doctrine\Tests\Models\CMS\CmsUser' has no method 'notfound' to be registered as lifecycle callback."); + $cm->validateLifecycleCallbacks(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + } + + /** + * @group ImproveErrorMessages + */ + public function testTargetEntityNotFound() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->mapManyToOne(array('fieldName' => 'address', 'targetEntity' => 'UnknownClass')); + + $this->setExpectedException("Doctrine\ORM\Mapping\MappingException", "The target-entity Doctrine\Tests\Models\CMS\UnknownClass cannot be found in 'Doctrine\Tests\Models\CMS\CmsUser#address'."); + $cm->validateAssocations(); + } + + /** + * @group DDC-1663 + * + * @expectedException \Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Query name on entity class 'Doctrine\Tests\Models\CMS\CmsUser' is not defined. + */ + public function testNameIsMandatoryForNamedQueryMappingException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->addNamedQuery(array( + 'query' => 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', + )); + } + + /** + * @group DDC-1663 + * + * @expectedException \Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Query name on entity class 'Doctrine\Tests\Models\CMS\CmsUser' is not defined. + */ + public function testNameIsMandatoryForNameNativeQueryMappingException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->addNamedQuery(array( + 'query' => 'SELECT * FROM cms_users', + 'resultClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'resultSetMapping' => 'result-mapping-name' + )); + } + + /** + * @group DDC-1663 + * + * @expectedException \Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Result set mapping named "find-all" in "Doctrine\Tests\Models\CMS\CmsUser requires a entity class name. + */ + public function testNameIsMandatoryForEntityNameSqlResultSetMappingException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->addSqlResultSetMapping(array( + 'name' => 'find-all', + 'entities' => array( + array( + 'fields' => array() + ) + ), + )); + } + + /** + * @expectedException \Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Discriminator column name on entity class 'Doctrine\Tests\Models\CMS\CmsUser' is not defined. + */ + public function testNameIsMandatoryForDiscriminatorColumnsMappingException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->setDiscriminatorColumn(array()); + } + + /** + * @group DDC-984 + * @group DDC-559 + * @group DDC-1575 + */ + public function testFullyQualifiedClassNameShouldBeGivenToNamingStrategy() + { + $namingStrategy = new MyNamespacedNamingStrategy(); + $addressMetadata = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', $namingStrategy); + $articleMetadata = new ClassMetadata('DoctrineGlobal_Article', $namingStrategy); + $routingMetadata = new ClassMetadata('Doctrine\Tests\Models\Routing\RoutingLeg',$namingStrategy); + + $addressMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $articleMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $routingMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $addressMetadata->mapManyToMany(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser' + )); + + $articleMetadata->mapManyToMany(array( + 'fieldName' => 'author', + 'targetEntity' => 'Doctrine\Tests\Models\CMS\CmsUser' + )); + + $this->assertEquals('routing_routingleg', $routingMetadata->table['name']); + $this->assertEquals('cms_cmsaddress_cms_cmsuser', $addressMetadata->associationMappings['user']['joinTable']['name']); + $this->assertEquals('doctrineglobal_article_cms_cmsuser', $articleMetadata->associationMappings['author']['joinTable']['name']); + } + + /** + * @group DDC-1746 + */ + public function testInvalidCascade() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $this->setExpectedException("Doctrine\ORM\Mapping\MappingException", "You have specified invalid cascade options for Doctrine\Tests\Models\CMS\CmsUser::\$address: 'invalid'; available options: 'remove', 'persist', 'refresh', 'merge', and 'detach'"); + + + $cm->mapManyToOne(array('fieldName' => 'address', 'targetEntity' => 'UnknownClass', 'cascade' => array('invalid'))); + } + + /** + * @group DDC-964 + * @expectedException Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Invalid field override named 'invalidPropertyName' for class 'Doctrine\Tests\Models\DDC964\DDC964Admin + */ + public function testInvalidPropertyAssociationOverrideNameException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\DDC964\DDC964Admin'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->mapManyToOne(array('fieldName' => 'address', 'targetEntity' => 'DDC964Address')); + + $cm->setAssociationOverride('invalidPropertyName', array()); + } + + /** + * @group DDC-964 + * @expectedException Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage Invalid field override named 'invalidPropertyName' for class 'Doctrine\Tests\Models\DDC964\DDC964Guest'. + */ + public function testInvalidPropertyAttributeOverrideNameException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\DDC964\DDC964Guest'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->mapField(array('fieldName' => 'name')); + + $cm->setAttributeOverride('invalidPropertyName', array()); + } + + /** + * @group DDC-964 + * @expectedException Doctrine\ORM\Mapping\MappingException + * @expectedExceptionMessage The column type of attribute 'name' on class 'Doctrine\Tests\Models\DDC964\DDC964Guest' could not be changed. + */ + public function testInvalidOverrideAttributeFieldTypeException() + { + $cm = new ClassMetadata('Doctrine\Tests\Models\DDC964\DDC964Guest'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->mapField(array('fieldName' => 'name', 'type'=>'string')); + + $cm->setAttributeOverride('name', array('type'=>'date')); + } +} + +class MyNamespacedNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy +{ + /** + * {@inheritdoc} + */ + public function classToTableName($className) + { + if (strpos($className, '\\') !== false) { + $className = str_replace('\\', '_', str_replace('Doctrine\Tests\Models\\', '', $className)); + } + + return strtolower($className); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/NamingStrategyTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/NamingStrategyTest.php new file mode 100644 index 0000000..0c56aa8 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/NamingStrategyTest.php @@ -0,0 +1,298 @@ +assertEquals($expected, $strategy->classToTableName($className)); + } + + /** + * Data Provider for NamingStrategy#propertyToColumnName + * + * @return array + */ + static public function dataPropertyToColumnName() + { + return array( + // DefaultNamingStrategy + array(self::defaultNaming(), 'someProperty', + 'someProperty' + ), + array(self::defaultNaming(), 'SOME_PROPERTY', + 'SOME_PROPERTY' + ), + array(self::defaultNaming(), 'some_property', + 'some_property' + ), + + // UnderscoreNamingStrategy + array(self::underscoreNamingLower(), 'some_property', + 'someProperty' + ), + array(self::underscoreNamingUpper(), 'SOME_PROPERTY', + 'someProperty' + ), + array(self::underscoreNamingUpper(), 'SOME_PROPERTY', + 'some_property' + ), + array(self::underscoreNamingUpper(), 'SOME_PROPERTY', + 'SOME_PROPERTY' + ), + ); + } + + /** + * @dataProvider dataPropertyToColumnName + * + * @param NamingStrategy $strategy + * @param string $expected + * @param string $propertyName + */ + public function testPropertyToColumnName(NamingStrategy $strategy, $expected, $propertyName) + { + $this->assertEquals($expected, $strategy->propertyToColumnName($propertyName)); + } + + /** + * Data Provider for NamingStrategy#referenceColumnName + * + * @return array + */ + static public function dataReferenceColumnName() + { + return array( + // DefaultNamingStrategy + array(self::defaultNaming(), 'id'), + + // UnderscoreNamingStrategy + array(self::underscoreNamingLower(), 'id'), + array(self::underscoreNamingUpper(), 'ID'), + ); + } + + /** + * @dataProvider dataReferenceColumnName + * + * @param NamingStrategy $strategy + * @param string $expected + */ + public function testReferenceColumnName(NamingStrategy $strategy, $expected) + { + $this->assertEquals($expected, $strategy->referenceColumnName()); + } + + /** + * Data Provider for NamingStrategy#joinColumnName + * + * @return array + */ + static public function dataJoinColumnName() + { + return array( + // DefaultNamingStrategy + array(self::defaultNaming(), 'someColumn_id', + 'someColumn', null, + ), + array(self::defaultNaming(), 'some_column_id', + 'some_column', null, + ), + + // UnderscoreNamingStrategy + array(self::underscoreNamingLower(), 'some_column_id', + 'someColumn', null, + ), + array(self::underscoreNamingUpper(), 'SOME_COLUMN_ID', + 'someColumn', null, + ), + ); + } + + /** + * @dataProvider dataJoinColumnName + * + * @param NamingStrategy $strategy + * @param string $expected + * @param string $propertyName + */ + public function testJoinColumnName(NamingStrategy $strategy, $expected, $propertyName) + { + $this->assertEquals($expected, $strategy->joinColumnName($propertyName)); + } + + /** + * Data Provider for NamingStrategy#joinTableName + * + * @return array + */ + static public function dataJoinTableName() + { + return array( + // DefaultNamingStrategy + array(self::defaultNaming(), 'someclassname_classname', + 'SomeClassName', 'Some\ClassName', null, + ), + array(self::defaultNaming(), 'someclassname_classname', + '\SomeClassName', 'ClassName', null, + ), + array(self::defaultNaming(), 'name_classname', + '\Some\Class\Name', 'ClassName', null, + ), + + // UnderscoreNamingStrategy + array(self::underscoreNamingLower(), 'some_class_name_class_name', + 'SomeClassName', 'Some\ClassName', null, + ), + array(self::underscoreNamingLower(), 'some_class_name_class_name', + '\SomeClassName', 'ClassName', null, + ), + array(self::underscoreNamingLower(), 'name_class_name', + '\Some\Class\Name', 'ClassName', null, + ), + + array(self::underscoreNamingUpper(), 'SOME_CLASS_NAME_CLASS_NAME', + 'SomeClassName', 'Some\ClassName', null, + ), + array(self::underscoreNamingUpper(), 'SOME_CLASS_NAME_CLASS_NAME', + '\SomeClassName', 'ClassName', null, + ), + array(self::underscoreNamingUpper(), 'NAME_CLASS_NAME', + '\Some\Class\Name', 'ClassName', null, + ), + ); + } + + /** + * @dataProvider dataJoinTableName + * + * @param NamingStrategy $strategy + * @param string $expected + * @param string $ownerEntity + * @param string $associatedEntity + * @param string $propertyName + */ + public function testJoinTableName(NamingStrategy $strategy, $expected, $ownerEntity, $associatedEntity, $propertyName = null) + { + $this->assertEquals($expected, $strategy->joinTableName($ownerEntity, $associatedEntity, $propertyName)); + } + + /** + * Data Provider for NamingStrategy#joinKeyColumnName + * + * @return array + */ + static public function dataJoinKeyColumnName() + { + return array( + // DefaultNamingStrategy + array(self::defaultNaming(), 'someclassname_id', + 'SomeClassName', null, null, + ), + array(self::defaultNaming(), 'name_identifier', + '\Some\Class\Name', 'identifier', null, + ), + + // UnderscoreNamingStrategy + array(self::underscoreNamingLower(), 'some_class_name_id', + 'SomeClassName', null, null, + ), + array(self::underscoreNamingLower(), 'class_name_identifier', + '\Some\Class\ClassName', 'identifier', null, + ), + + array(self::underscoreNamingUpper(), 'SOME_CLASS_NAME_ID', + 'SomeClassName', null, null, + ), + array(self::underscoreNamingUpper(), 'CLASS_NAME_IDENTIFIER', + '\Some\Class\ClassName', 'IDENTIFIER', null, + ), + ); + } + + /** + * @dataProvider dataJoinKeyColumnName + * + * @param NamingStrategy $strategy + * @param string $expected + * @param string $propertyEntityName + * @param string $referencedColumnName + * @param string $propertyName + */ + public function testJoinKeyColumnName(NamingStrategy $strategy, $expected, $propertyEntityName, $referencedColumnName = null, $propertyName = null) + { + $this->assertEquals($expected, $strategy->joinKeyColumnName($propertyEntityName, $referencedColumnName, $propertyName)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/PHPMappingDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/PHPMappingDriverTest.php new file mode 100644 index 0000000..c9da3dc --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/PHPMappingDriverTest.php @@ -0,0 +1,38 @@ +createAnnotationDriver(); +// $driver->loadMetadataForClass("Doctrine\Tests\ORM\Mapping\Animal", $meta); +// $exporter = $cme->getExporter('php', $path); +// echo $exporter->exportClassMetadata($meta); + + return new PHPDriver($path); + } + + /** + * All class are entitier for php driver + * + * @group DDC-889 + */ + public function testinvalidEntityOrMappedSuperClassShouldMentionParentClasses() + { + $this->createClassMetadata('Doctrine\Tests\Models\DDC889\DDC889Class'); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/QuoteStrategyTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/QuoteStrategyTest.php new file mode 100644 index 0000000..23f02b4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/QuoteStrategyTest.php @@ -0,0 +1,197 @@ +_getTestEntityManager(); + $this->platform = $em->getConnection()->getDatabasePlatform(); + $this->strategy = new DefaultQuoteStrategy(); + } + + /** + * @param string $className + * @return \Doctrine\ORM\Mapping\ClassMetadata + */ + private function createClassMetadata($className) + { + $cm = new ClassMetadata($className); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + return $cm; + } + + public function testConfiguration() + { + $em = $this->_getTestEntityManager(); + $config = $em->getConfiguration(); + + $this->assertInstanceOf('Doctrine\ORM\Mapping\QuoteStrategy', $config->getQuoteStrategy()); + $this->assertInstanceOf('Doctrine\ORM\Mapping\DefaultQuoteStrategy', $config->getQuoteStrategy()); + + $config->setQuoteStrategy(new MyQuoteStrategy()); + + $this->assertInstanceOf('Doctrine\ORM\Mapping\QuoteStrategy', $config->getQuoteStrategy()); + $this->assertInstanceOf('Doctrine\Tests\ORM\Mapping\MyQuoteStrategy', $config->getQuoteStrategy()); + } + + public function testGetColumnName() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->mapField(array('fieldName' => 'name', 'columnName' => '`name`')); + $cm->mapField(array('fieldName' => 'id', 'columnName' => 'id')); + + $this->assertEquals('id' ,$this->strategy->getColumnName('id', $cm, $this->platform)); + $this->assertEquals('"name"' ,$this->strategy->getColumnName('name', $cm, $this->platform)); + } + + public function testGetTableName() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->setPrimaryTable(array('name'=>'`cms_user`')); + $this->assertEquals('"cms_user"' ,$this->strategy->getTableName($cm, $this->platform)); + + $cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $cm->setPrimaryTable(array('name'=>'cms_user')); + $this->assertEquals('cms_user' ,$this->strategy->getTableName($cm, $this->platform)); + } + + public function testJoinTableName() + { + $cm1 = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + $cm2 = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + + $cm1->mapManyToMany(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser', + 'inversedBy' => 'users', + 'joinTable' => array( + 'name' => '`cmsaddress_cmsuser`' + ) + )); + + $cm2->mapManyToMany(array( + 'fieldName' => 'user', + 'targetEntity' => 'CmsUser', + 'inversedBy' => 'users', + 'joinTable' => array( + 'name' => 'cmsaddress_cmsuser' + ) + ) + ); + + $this->assertEquals('"cmsaddress_cmsuser"', $this->strategy->getJoinTableName($cm1->associationMappings['user'], $cm1, $this->platform)); + $this->assertEquals('cmsaddress_cmsuser', $this->strategy->getJoinTableName($cm2->associationMappings['user'], $cm2, $this->platform)); + + } + + public function testIdentifierColumnNames() + { + $cm1 = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + $cm2 = $this->createClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'); + + $cm1->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'columnName' => '`id`', + )); + + $cm2->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'columnName' => 'id', + )); + + $this->assertEquals(array('"id"'), $this->strategy->getIdentifierColumnNames($cm1, $this->platform)); + $this->assertEquals(array('id'), $this->strategy->getIdentifierColumnNames($cm2, $this->platform)); + } + + + public function testColumnAlias() + { + $i = 0; + $this->assertEquals('columnName0', $this->strategy->getColumnAlias('columnName', $i++, $this->platform)); + $this->assertEquals('column_name1', $this->strategy->getColumnAlias('column_name', $i++, $this->platform)); + $this->assertEquals('COLUMN_NAME2', $this->strategy->getColumnAlias('COLUMN_NAME', $i++, $this->platform)); + $this->assertEquals('COLUMNNAME3', $this->strategy->getColumnAlias('COLUMN-NAME-', $i++, $this->platform)); + } + + public function testQuoteIdentifierJoinColumns() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + + $cm->mapOneToOne(array( + 'id' => true, + 'fieldName' => 'article', + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'joinColumns' => array(array( + 'name' => '`article`' + )), + )); + + $this->assertEquals(array('"article"'), $this->strategy->getIdentifierColumnNames($cm, $this->platform)); + } + + public function testJoinColumnName() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + + $cm->mapOneToOne(array( + 'id' => true, + 'fieldName' => 'article', + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'joinColumns' => array(array( + 'name' => '`article`' + )), + )); + + $joinColumn = $cm->associationMappings['article']['joinColumns'][0]; + $this->assertEquals('"article"',$this->strategy->getJoinColumnName($joinColumn, $cm, $this->platform)); + } + + public function testReferencedJoinColumnName() + { + $cm = $this->createClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails'); + + $cm->mapOneToOne(array( + 'id' => true, + 'fieldName' => 'article', + 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'joinColumns' => array(array( + 'name' => '`article`' + )), + )); + + $joinColumn = $cm->associationMappings['article']['joinColumns'][0]; + $this->assertEquals('"id"',$this->strategy->getReferencedJoinColumnName($joinColumn, $cm, $this->platform)); + } +} + +class MyQuoteStrategy extends \Doctrine\ORM\Mapping\DefaultQuoteStrategy +{ + +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/StaticPHPMappingDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/StaticPHPMappingDriverTest.php new file mode 100644 index 0000000..77eafe1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/StaticPHPMappingDriverTest.php @@ -0,0 +1,28 @@ +createClassMetadata('Doctrine\Tests\Models\DDC889\DDC889Class'); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php new file mode 100644 index 0000000..4052601 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php @@ -0,0 +1,113 @@ +. +*/ + +namespace Doctrine\Tests\ORM\Mapping\Symfony; + +/** + * @group DDC-1418 + */ +abstract class AbstractDriverTest extends \PHPUnit_Framework_TestCase +{ + public function testFindMappingFile() + { + $driver = $this->getDriver(array( + 'MyNamespace\MySubnamespace\EntityFoo' => 'foo', + 'MyNamespace\MySubnamespace\Entity' => $this->dir, + )); + + touch($filename = $this->dir.'/Foo'.$this->getFileExtension()); + $this->assertEquals($filename, $driver->getLocator()->findMappingFile('MyNamespace\MySubnamespace\Entity\Foo')); + } + + public function testFindMappingFileInSubnamespace() + { + $driver = $this->getDriver(array( + 'MyNamespace\MySubnamespace\Entity' => $this->dir, + )); + + touch($filename = $this->dir.'/Foo.Bar'.$this->getFileExtension()); + $this->assertEquals($filename, $driver->getLocator()->findMappingFile('MyNamespace\MySubnamespace\Entity\Foo\Bar')); + } + + public function testFindMappingFileNamespacedFoundFileNotFound() + { + $this->setExpectedException( + 'Doctrine\Common\Persistence\Mapping\MappingException', + "No mapping file found named '".$this->dir."/Foo".$this->getFileExtension()."' for class 'MyNamespace\MySubnamespace\Entity\Foo'." + ); + + $driver = $this->getDriver(array( + 'MyNamespace\MySubnamespace\Entity' => $this->dir, + )); + + $driver->getLocator()->findMappingFile('MyNamespace\MySubnamespace\Entity\Foo'); + } + + public function testFindMappingNamespaceNotFound() + { + $this->setExpectedException( + 'Doctrine\Common\Persistence\Mapping\MappingException', + "No mapping file found named 'Foo".$this->getFileExtension()."' for class 'MyOtherNamespace\MySubnamespace\Entity\Foo'." + ); + + $driver = $this->getDriver(array( + 'MyNamespace\MySubnamespace\Entity' => $this->dir, + )); + + $driver->getLocator()->findMappingFile('MyOtherNamespace\MySubnamespace\Entity\Foo'); + } + + protected function setUp() + { + $this->dir = sys_get_temp_dir().'/abstract_driver_test'; + @mkdir($this->dir, 0777, true); + } + + protected function tearDown() + { + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->dir), \RecursiveIteratorIterator::CHILD_FIRST); + + foreach ($iterator as $path) { + if ($path->isDir()) { + @rmdir($path); + } else { + @unlink($path); + } + } + + @rmdir($this->dir); + } + + abstract protected function getFileExtension(); + abstract protected function getDriver(array $paths = array()); + + private function setField($obj, $field, $value) + { + $ref = new \ReflectionProperty($obj, $field); + $ref->setAccessible(true); + $ref->setValue($obj, $value); + } + + private function invoke($obj, $method, array $args = array()) { + $ref = new \ReflectionMethod($obj, $method); + $ref->setAccessible(true); + + return $ref->invokeArgs($obj, $args); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/XmlDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/XmlDriverTest.php new file mode 100644 index 0000000..5908b67 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/XmlDriverTest.php @@ -0,0 +1,40 @@ +. +*/ + +namespace Doctrine\Tests\ORM\Mapping\Symfony; + +use \Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver; + +/** + * @group DDC-1418 + */ +class XmlDriverTest extends AbstractDriverTest +{ + protected function getFileExtension() + { + return '.orm.xml'; + } + + protected function getDriver(array $paths = array()) + { + $driver = new SimplifiedXmlDriver(array_flip($paths)); + + return $driver; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/YamlDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/YamlDriverTest.php new file mode 100644 index 0000000..c5d8d1c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/Symfony/YamlDriverTest.php @@ -0,0 +1,40 @@ +. +*/ + +namespace Doctrine\Tests\ORM\Mapping\Symfony; + +use \Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver; + +/** + * @group DDC-1418 + */ +class YamlDriverTest extends AbstractDriverTest +{ + protected function getFileExtension() + { + return '.orm.yml'; + } + + protected function getDriver(array $paths = array()) + { + $driver = new SimplifiedYamlDriver(array_flip($paths)); + + return $driver; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php new file mode 100644 index 0000000..e69f23a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php @@ -0,0 +1,106 @@ +_loadDriver(); + + $class = new ClassMetadata($className); + $class->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $mappingDriver->loadMetadataForClass($className, $class); + + $expectedMap = array( + "foo" => "Doctrine\Tests\ORM\Mapping\CTIFoo", + "bar" => "Doctrine\Tests\ORM\Mapping\CTIBar", + "baz" => "Doctrine\Tests\ORM\Mapping\CTIBaz", + ); + + $this->assertEquals(3, count($class->discriminatorMap)); + $this->assertEquals($expectedMap, $class->discriminatorMap); + } + + public function testIdentifierWithAssociationKey() + { + $driver = $this->_loadDriver(); + $em = $this->_getTestEntityManager(); + $factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + + $em->getConfiguration()->setMetadataDriverImpl($driver); + $factory->setEntityManager($em); + + $class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC117\DDC117Translation'); + + $this->assertEquals(array('language', 'article'), $class->identifier); + $this->assertArrayHasKey('article', $class->associationMappings); + + $this->assertArrayHasKey('id', $class->associationMappings['article']); + $this->assertTrue($class->associationMappings['article']['id']); + } + + /** + * @group DDC-1468 + * + * @expectedException Doctrine\Common\Persistence\Mapping\MappingException + * @expectedExceptionMessage Invalid mapping file 'Doctrine.Tests.Models.Generic.SerializationModel.dcm.xml' for class 'Doctrine\Tests\Models\Generic\SerializationModel'. + */ + public function testInvalidMappingFileException() + { + $this->createClassMetadata('Doctrine\Tests\Models\Generic\SerializationModel'); + } + + /** + * @param string $xmlMappingFile + * @dataProvider dataValidSchema + */ + public function testValidateXmlSchema($xmlMappingFile) + { + $xsdSchemaFile = __DIR__ . "/../../../../../doctrine-mapping.xsd"; + + $dom = new \DOMDocument('UTF-8'); + $dom->load($xmlMappingFile); + $this->assertTrue($dom->schemaValidate($xsdSchemaFile)); + } + + static public function dataValidSchema() + { + return array( + array(__DIR__ . "/xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml"), + array(__DIR__ . "/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml"), + array(__DIR__ . "/xml/CatNoId.dcm.xml"), + ); + } + + /** + * @group DDC-889 + * @expectedException Doctrine\Common\Persistence\Mapping\MappingException + * @expectedExceptionMessage Invalid mapping file 'Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml' for class 'Doctrine\Tests\Models\DDC889\DDC889Class'. + */ + public function testinvalidEntityOrMappedSuperClassShouldMentionParentClasses() + { + $this->createClassMetadata('Doctrine\Tests\Models\DDC889\DDC889Class'); + } +} + +class CTI +{ + public $id; +} + +class CTIFoo extends CTI {} +class CTIBar extends CTI {} +class CTIBaz extends CTI {} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/YamlMappingDriverTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/YamlMappingDriverTest.php new file mode 100644 index 0000000..91dd7e3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/YamlMappingDriverTest.php @@ -0,0 +1,57 @@ +markTestSkipped('Please install Symfony YAML Component into the include path of your PHP installation.'); + } + + return new YamlDriver(__DIR__ . DIRECTORY_SEPARATOR . 'yaml'); + } + + /** + * @group DDC-671 + * + * Entities for this test are in AbstractMappingDriverTest + */ + public function testJoinTablesWithMappedSuperclassForYamlDriver() + { + $yamlDriver = $this->_loadDriver(); + $yamlDriver->getLocator()->addPaths(array(__DIR__ . DIRECTORY_SEPARATOR . 'yaml')); + + $em = $this->_getTestEntityManager(); + $em->getConfiguration()->setMetadataDriverImpl($yamlDriver); + $factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory(); + $factory->setEntityManager($em); + + $classPage = new ClassMetadata('Doctrine\Tests\Models\DirectoryTree\File'); + $classPage = $factory->getMetadataFor('Doctrine\Tests\Models\DirectoryTree\File'); + $this->assertEquals('Doctrine\Tests\Models\DirectoryTree\File', $classPage->associationMappings['parentDirectory']['sourceEntity']); + + $classDirectory = new ClassMetadata('Doctrine\Tests\Models\DirectoryTree\Directory'); + $classDirectory = $factory->getMetadataFor('Doctrine\Tests\Models\DirectoryTree\Directory'); + $this->assertEquals('Doctrine\Tests\Models\DirectoryTree\Directory', $classDirectory->associationMappings['parentDirectory']['sourceEntity']); + } + + /** + * @group DDC-1468 + * + * @expectedException Doctrine\Common\Persistence\Mapping\MappingException + * @expectedExceptionMessage Invalid mapping file 'Doctrine.Tests.Models.Generic.SerializationModel.dcm.yml' for class 'Doctrine\Tests\Models\Generic\SerializationModel'. + */ + public function testInvalidMappingFileException() + { + $this->createClassMetadata('Doctrine\Tests\Models\Generic\SerializationModel'); + } + +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php new file mode 100644 index 0000000..964065c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php @@ -0,0 +1,69 @@ +setPrimaryTable(array( + 'name' => 'company_person', +)); + + +$metadata->addNamedNativeQuery(array ( + 'name' => 'find-all', + 'query' => 'SELECT id, country, city FROM cms_addresses', + 'resultSetMapping' => 'mapping-find-all', +)); + +$metadata->addNamedNativeQuery(array ( + 'name' => 'find-by-id', + 'query' => 'SELECT * FROM cms_addresses WHERE id = ?', + 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsAddress', +)); + +$metadata->addNamedNativeQuery(array ( + 'name' => 'count', + 'query' => 'SELECT COUNT(*) AS count FROM cms_addresses', + 'resultSetMapping' => 'mapping-count', +)); + + +$metadata->addSqlResultSetMapping(array ( + 'name' => 'mapping-find-all', + 'columns' => array(), + 'entities' => array ( array ( + 'fields' => array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'city', + 'column' => 'city', + ), + array ( + 'name' => 'country', + 'column' => 'country', + ), + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsAddress', + ), + ), +)); + +$metadata->addSqlResultSetMapping(array ( + 'name' => 'mapping-without-fields', + 'columns' => array(), + 'entities' => array(array ( + 'entityClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsAddress', + 'fields' => array() + ) + ) +)); + +$metadata->addSqlResultSetMapping(array ( + 'name' => 'mapping-count', + 'columns' =>array ( + array ( + 'name' => 'count', + ), + ) +)); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsUser.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsUser.php new file mode 100644 index 0000000..9484bf7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsUser.php @@ -0,0 +1,186 @@ +setPrimaryTable(array( + 'name' => 'cms_users', +)); + +$metadata->addNamedNativeQuery(array ( + 'name' => 'fetchIdAndUsernameWithResultClass', + 'query' => 'SELECT id, username FROM cms_users WHERE username = ?', + 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', +)); + +$metadata->addNamedNativeQuery(array ( + 'name' => 'fetchAllColumns', + 'query' => 'SELECT * FROM cms_users WHERE username = ?', + 'resultClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', +)); + +$metadata->addNamedNativeQuery(array ( + 'name' => 'fetchJoinedAddress', + 'query' => 'SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', + 'resultSetMapping' => 'mappingJoinedAddress', +)); + +$metadata->addNamedNativeQuery(array ( + 'name' => 'fetchJoinedPhonenumber', + 'query' => 'SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?', + 'resultSetMapping' => 'mappingJoinedPhonenumber', +)); + +$metadata->addNamedNativeQuery(array ( + 'name' => 'fetchUserPhonenumberCount', + 'query' => 'SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username', + 'resultSetMapping' => 'mappingUserPhonenumberCount', +)); + +$metadata->addNamedNativeQuery(array ( + "name" => "fetchMultipleJoinsEntityResults", + "resultSetMapping" => "mappingMultipleJoinsEntityResults", + "query" => "SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username" +)); + +$metadata->addSqlResultSetMapping(array ( + 'name' => 'mappingJoinedAddress', + 'columns' => array(), + 'entities' => array(array ( + 'fields'=> array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'name', + 'column' => 'name', + ), + array ( + 'name' => 'status', + 'column' => 'status', + ), + array ( + 'name' => 'address.zip', + 'column' => 'zip', + ), + array ( + 'name' => 'address.city', + 'column' => 'city', + ), + array ( + 'name' => 'address.country', + 'column' => 'country', + ), + array ( + 'name' => 'address.id', + 'column' => 'a_id', + ), + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'discriminatorColumn' => null + ), + ), +)); + +$metadata->addSqlResultSetMapping(array ( + 'name' => 'mappingJoinedPhonenumber', + 'columns' => array(), + 'entities' => array(array( + 'fields'=> array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'name', + 'column' => 'name', + ), + array ( + 'name' => 'status', + 'column' => 'status', + ), + array ( + 'name' => 'phonenumbers.phonenumber', + 'column' => 'number', + ), + ), + 'entityClass' => 'Doctrine\\Tests\\Models\\CMS\\CmsUser', + 'discriminatorColumn' => null + ), + ), +)); + +$metadata->addSqlResultSetMapping(array ( + 'name' => 'mappingUserPhonenumberCount', + 'columns' => array(), + 'entities' => array ( + array( + 'fields' => array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'name', + 'column' => 'name', + ), + array ( + 'name' => 'status', + 'column' => 'status', + ) + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'discriminatorColumn' => null + ) + ), + 'columns' => array ( + array ( + 'name' => 'numphones', + ) + ) +)); + +$metadata->addSqlResultSetMapping(array( + 'name' => 'mappingMultipleJoinsEntityResults', + 'entities' => array(array( + 'fields' => array( + array( + 'name' => 'id', + 'column' => 'u_id', + ), + array( + 'name' => 'name', + 'column' => 'u_name', + ), + array( + 'name' => 'status', + 'column' => 'u_status', + ) + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsUser', + 'discriminatorColumn' => null, + ), + array( + 'fields' => array( + array( + 'name' => 'id', + 'column' => 'a_id', + ), + array( + 'name' => 'zip', + 'column' => 'a_zip', + ), + array( + 'name' => 'country', + 'column' => 'a_country', + ), + ), + 'entityClass' => 'Doctrine\Tests\Models\CMS\CmsAddress', + 'discriminatorColumn' => null, + ), + ), + 'columns' => array(array( + 'name' => 'numphones', + ) + ) +)); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Company.CompanyPerson.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Company.CompanyPerson.php new file mode 100644 index 0000000..68703f4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Company.CompanyPerson.php @@ -0,0 +1,39 @@ +setPrimaryTable(array( + 'name' => 'company_person', +)); + +$metadata->addNamedNativeQuery(array ( + 'name' => 'fetchAllWithResultClass', + 'query' => 'SELECT id, name, discr FROM company_persons ORDER BY name', + 'resultClass' => 'Doctrine\\Tests\\Models\\Company\\CompanyPerson', +)); + +$metadata->addNamedNativeQuery(array ( + 'name' => 'fetchAllWithSqlResultSetMapping', + 'query' => 'SELECT id, name, discr AS discriminator FROM company_persons ORDER BY name', + 'resultSetMapping' => 'mappingFetchAll', +)); + +$metadata->addSqlResultSetMapping(array ( + 'name' => 'mappingFetchAll', + 'columns' => array(), + 'entities' => array ( array ( + 'fields' => array ( + array ( + 'name' => 'id', + 'column' => 'id', + ), + array ( + 'name' => 'name', + 'column' => 'name', + ), + ), + 'entityClass' => 'Doctrine\Tests\Models\Company\CompanyPerson', + 'discriminatorColumn' => 'discriminator', + ), + ), +)); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.php new file mode 100644 index 0000000..56a9963 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.php @@ -0,0 +1,12 @@ +mapField(array( + 'id' => true, + 'fieldName' => 'id', +)); +$metadata->mapField(array( + 'fieldName' => 'name' +)); +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.php new file mode 100644 index 0000000..ad8b86d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.php @@ -0,0 +1,5 @@ +mapField(array( + 'fieldName' => 'serialNumber', + 'type' => 'string', +)); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.php new file mode 100644 index 0000000..1318333 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.php @@ -0,0 +1,5 @@ +mapField(array( + 'fieldName' => 'creditCardNumber', + 'type' => 'string', +)); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869Payment.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869Payment.php new file mode 100644 index 0000000..1d1f551 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC869.DDC869Payment.php @@ -0,0 +1,17 @@ +mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'id', +)); +$metadata->mapField(array( + 'fieldName' => 'value', + 'type' => 'float', + )); +$metadata->isMappedSuperclass = true; +$metadata->setCustomRepositoryClass("Doctrine\Tests\Models\DDC869\DDC869PaymentRepository"); +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC889.DDC889Class.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC889.DDC889Class.php new file mode 100644 index 0000000..90cfdc1 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC889.DDC889Class.php @@ -0,0 +1,12 @@ +mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'id', +)); + +//$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC889.DDC889Entity.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC889.DDC889Entity.php new file mode 100644 index 0000000..a14f3e7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC889.DDC889Entity.php @@ -0,0 +1,3 @@ +mapField(array( + 'fieldName' => 'name', + 'type' => 'string', + )); +$metadata->isMappedSuperclass = true; +$metadata->setCustomRepositoryClass("Doctrine\Tests\Models\DDC889\DDC889SuperClass"); +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964Admin.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964Admin.php new file mode 100644 index 0000000..bb8920e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964Admin.php @@ -0,0 +1,21 @@ +setAssociationOverride('address',array( + 'joinColumns'=>array(array( + 'name' => 'adminaddress_id', + 'referencedColumnName' => 'id', + )) +)); + +$metadata->setAssociationOverride('groups',array( + 'joinTable' => array ( + 'name' => 'ddc964_users_admingroups', + 'joinColumns' => array(array( + 'name' => 'adminuser_id', + )), + + 'inverseJoinColumns' =>array (array ( + 'name' => 'admingroup_id', + )) + ) +)); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964Guest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964Guest.php new file mode 100644 index 0000000..5094ecd --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964Guest.php @@ -0,0 +1,13 @@ +setAttributeOverride('id', array( + 'columnName' => 'guest_id', + 'type' => 'integer', + 'length' => 140, +)); + +$metadata->setAttributeOverride('name',array( + 'columnName' => 'guest_name', + 'nullable' => false, + 'unique' => true, + 'length' => 240, +)); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964User.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964User.php new file mode 100644 index 0000000..7b66dee --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.DDC964.DDC964User.php @@ -0,0 +1,46 @@ +mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'user_id', + 'length' => 150, +)); +$metadata->mapField(array( + 'fieldName' => 'name', + 'type' => 'string', + 'columnName'=> 'user_name', + 'nullable' => true, + 'unique' => false, + 'length' => 250, +)); + +$metadata->mapManyToOne(array( + 'fieldName' => 'address', + 'targetEntity' => 'DDC964Address', + 'cascade' => array('persist','merge'), + 'joinColumn' => array('name'=>'address_id', 'referencedColumnMame'=>'id'), +)); + +$metadata->mapManyToMany(array( + 'fieldName' => 'groups', + 'targetEntity' => 'DDC964Group', + 'inversedBy' => 'users', + 'cascade' => array('persist','merge','detach'), + 'joinTable' => array( + 'name' => 'ddc964_users_groups', + 'joinColumns' => array(array( + 'name'=>'user_id', + 'referencedColumnName'=>'id', + )), + 'inverseJoinColumns'=>array(array( + 'name'=>'group_id', + 'referencedColumnName'=>'id', + )) + ) +)); + +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.Animal.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.Animal.php new file mode 100644 index 0000000..005178e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.Animal.php @@ -0,0 +1,30 @@ +setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE); +$metadata->setDiscriminatorColumn(array( + 'name' => 'dtype', + 'type' => 'string', + 'length' => 255, + 'fieldName' => 'dtype', + )); +$metadata->setDiscriminatorMap(array( + 'cat' => 'Doctrine\\Tests\\ORM\\Mapping\\Cat', + 'dog' => 'Doctrine\\Tests\\ORM\\Mapping\\Dog', + )); +$metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT); +$metadata->mapField(array( + 'fieldName' => 'id', + 'type' => 'string', + 'length' => NULL, + 'precision' => 0, + 'scale' => 0, + 'nullable' => false, + 'unique' => false, + 'id' => true, + 'columnName' => 'id', + )); +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_CUSTOM); +$metadata->setCustomGeneratorDefinition(array("class" => "stdClass")); diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.DDC1170Entity.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.DDC1170Entity.php new file mode 100644 index 0000000..97f4624 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.DDC1170Entity.php @@ -0,0 +1,16 @@ +mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'columnDefinition' => 'INT unsigned NOT NULL', +)); + +$metadata->mapField(array( + 'fieldName' => 'value', + 'columnDefinition' => 'VARCHAR(255) NOT NULL' +)); + +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.DDC807Entity.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.DDC807Entity.php new file mode 100644 index 0000000..1682d7a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.DDC807Entity.php @@ -0,0 +1,15 @@ +mapField(array( + 'id' => true, + 'fieldName' => 'id', +)); + +$metadata->setDiscriminatorColumn(array( + 'name' => "dtype", + 'columnDefinition' => "ENUM('ONE','TWO')" +)); + +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.User.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.User.php new file mode 100644 index 0000000..df4dedd --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.ORM.Mapping.User.php @@ -0,0 +1,124 @@ +setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE); +$metadata->setPrimaryTable(array( + 'name' => 'cms_users', + )); +$metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT); +$metadata->addLifecycleCallback('doStuffOnPrePersist', 'prePersist'); +$metadata->addLifecycleCallback('doOtherStuffOnPrePersistToo', 'prePersist'); +$metadata->addLifecycleCallback('doStuffOnPostPersist', 'postPersist'); +$metadata->addNamedQuery(array( + 'name' => 'all', + 'query' => 'SELECT u FROM __CLASS__ u' +)); +$metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'id', + )); +$metadata->mapField(array( + 'fieldName' => 'name', + 'type' => 'string', + 'length' => 50, + 'unique' => true, + 'nullable' => true, + 'columnName' => 'name', + 'options' => array('foo' => 'bar', 'baz' => array('key' => 'val')), + )); +$metadata->mapField(array( + 'fieldName' => 'email', + 'type' => 'string', + 'columnName' => 'user_email', + 'columnDefinition' => 'CHAR(32) NOT NULL', + )); +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); +$metadata->mapOneToOne(array( + 'fieldName' => 'address', + 'targetEntity' => 'Doctrine\\Tests\\ORM\\Mapping\\Address', + 'cascade' => + array( + 0 => 'remove', + ), + 'mappedBy' => NULL, + 'inversedBy' => 'user', + 'joinColumns' => + array( + 0 => + array( + 'name' => 'address_id', + 'referencedColumnName' => 'id', + 'onDelete' => 'CASCADE', + ), + ), + 'orphanRemoval' => false, + )); +$metadata->mapOneToMany(array( + 'fieldName' => 'phonenumbers', + 'targetEntity' => 'Doctrine\\Tests\\ORM\\Mapping\\Phonenumber', + 'cascade' => + array( + 1 => 'persist', + ), + 'mappedBy' => 'user', + 'orphanRemoval' => true, + 'orderBy' => + array( + 'number' => 'ASC', + ), + )); +$metadata->mapManyToMany(array( + 'fieldName' => 'groups', + 'targetEntity' => 'Doctrine\\Tests\\ORM\\Mapping\\Group', + 'cascade' => + array( + 0 => 'remove', + 1 => 'persist', + 2 => 'refresh', + 3 => 'merge', + 4 => 'detach', + ), + 'mappedBy' => NULL, + 'joinTable' => + array( + 'name' => 'cms_users_groups', + 'joinColumns' => + array( + 0 => + array( + 'name' => 'user_id', + 'referencedColumnName' => 'id', + 'unique' => false, + 'nullable' => false, + ), + ), + 'inverseJoinColumns' => + array( + 0 => + array( + 'name' => 'group_id', + 'referencedColumnName' => 'id', + 'columnDefinition' => 'INT NULL', + ), + ), + ), + 'orderBy' => NULL, + )); +$metadata->table['options'] = array( + 'foo' => 'bar', + 'baz' => array('key' => 'val') +); +$metadata->table['uniqueConstraints'] = array( + 'search_idx' => array('columns' => array('name', 'user_email')), +); +$metadata->table['indexes'] = array( + 'name_idx' => array('columns' => array('name')), 0 => array('columns' => array('user_email')) +); +$metadata->setSequenceGeneratorDefinition(array( + 'sequenceName' => 'tablename_seq', + 'allocationSize' => 100, + 'initialValue' => 1, + )); \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/CatNoId.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/CatNoId.dcm.xml new file mode 100644 index 0000000..6025d35 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/CatNoId.dcm.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml new file mode 100644 index 0000000..0af5fac --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml @@ -0,0 +1,55 @@ + + + + + + + + + SELECT id, country, city FROM cms_addresses + + + + SELECT * FROM cms_addresses WHERE id = ? + + + + SELECT COUNT(*) AS count FROM cms_addresses + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml new file mode 100644 index 0000000..64a545d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + SELECT id, username FROM cms_users WHERE username = ? + + + + SELECT * FROM cms_users WHERE username = ? + + + + SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ? + + + + SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ? + + + + SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username + + + + SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml new file mode 100644 index 0000000..c573504 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml @@ -0,0 +1,57 @@ + + + + + + + + + SELECT id, name, discr FROM company_persons ORDER BY name + + + + SELECT id, name, discr AS discriminator FROM company_persons ORDER BY name + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC117.DDC117Translation.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC117.DDC117Translation.dcm.xml new file mode 100644 index 0000000..c0df088 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC117.DDC117Translation.dcm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.xml new file mode 100644 index 0000000..29b5f1d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.xml new file mode 100644 index 0000000..05e2540 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.xml new file mode 100644 index 0000000..daf01f0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.xml new file mode 100644 index 0000000..be9f760 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml new file mode 100644 index 0000000..4a8935c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml new file mode 100644 index 0000000..686bdbf --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml new file mode 100644 index 0000000..48fa4fb --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.xml new file mode 100644 index 0000000..f4bb4eb --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.xml new file mode 100644 index 0000000..561066f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml new file mode 100644 index 0000000..68db74b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.xml new file mode 100644 index 0000000..36af855 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Animal.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Animal.dcm.xml new file mode 100644 index 0000000..3f67a6b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Animal.dcm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml new file mode 100644 index 0000000..14abaef --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.xml new file mode 100644 index 0000000..9f5ad7f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.xml new file mode 100644 index 0000000..3dc9135 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml new file mode 100644 index 0000000..18f4d58 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml new file mode 100644 index 0000000..604acb2 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml @@ -0,0 +1,62 @@ +Doctrine\Tests\Models\CMS\CmsAddress: + type: entity + table: cms_address + namedNativeQueries: + find-all: + resultSetMapping: mapping-find-all + query: SELECT id, country, city FROM cms_addresses + find-by-id: + name: find-by-id + resultClass: CmsAddress + query: SELECT * FROM cms_addresses WHERE id = ? + count: + name: count + resultSetMapping: mapping-count + query: SELECT COUNT(*) AS count FROM cms_addresses + + sqlResultSetMappings: + mapping-find-all: + entityResult: + address: + entityClass: CmsAddress + fieldResult: + 0: + name: id + column: id + 1: + name: city + column: city + 2: + name: country + column: country + mapping-without-fields: + name: mapping-without-fields + entityResult: + address: + entityClass: CmsAddress + mapping-count: + name: mapping-count + columnResult: + count: + name: count + id: + id: + type: integer + generator: + strategy: AUTO + fields: + country: + type: string + length: 50 + city: + type: string + length: 50 + zip: + type: string + length: 50 + oneToOne: + address: + targetEntity: CmsUser + inversedBy: address + joinColumn: + referencedColumnName: id \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsUser.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsUser.dcm.yml new file mode 100644 index 0000000..3a03dd6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsUser.dcm.yml @@ -0,0 +1,158 @@ +Doctrine\Tests\Models\CMS\CmsUser: + type: entity + table: cms_users + namedQueries: + all: SELECT u FROM __CLASS__ u + namedNativeQueries: + fetchIdAndUsernameWithResultClass: + resultClass: CmsUser + query: SELECT id, username FROM cms_users WHERE username = ? + fetchAllColumns: + name: fetchAllColumns + resultClass: CmsUser + query: SELECT * FROM cms_users WHERE username = ? + fetchJoinedAddress: + name: fetchJoinedAddress + resultSetMapping: mappingJoinedAddress + query: SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ? + fetchJoinedPhonenumber: + name: fetchJoinedPhonenumber + resultSetMapping: mappingJoinedPhonenumber + query: SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ? + fetchUserPhonenumberCount: + name: fetchUserPhonenumberCount + resultSetMapping: mappingUserPhonenumberCount + query: SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username + fetchMultipleJoinsEntityResults: + name: fetchMultipleJoinsEntityResults + resultSetMapping: mappingMultipleJoinsEntityResults + query: SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username + + sqlResultSetMappings: + mappingJoinedAddress: + entityResult: + 0: + entityClass: __CLASS__ + fieldResult: + 0: + name: id + 1: + name: name + 2: + name: status + 3: + name: address.zip + 4: + name: address.city + 5: + name: address.country + 6: + name: address.id + column: a_id + mappingJoinedPhonenumber: + name: mappingJoinedPhonenumber + entityResult: + user: + entityClass: CmsUser + fieldResult: + 0: + name: id + 1: + name: name + 2: + name: status + 3: + name: phonenumbers.phonenumber + column: number + mappingUserPhonenumberCount: + name: mappingUserPhonenumberCount + columnResult: + 0: + name: numphones + entityResult: + user_0: + entityClass: CmsUser + fieldResult: + 0: + name: id + 1: + name: name + 2: + name: status + mappingMultipleJoinsEntityResults: + name: mappingMultipleJoinsEntityResults + columnResult: + 0: + name: numphones + entityResult: + 0: + entityClass: __CLASS__ + fieldResult: + 0: + name: id + column: u_id + 1: + name: name + column: u_name + 2: + name: status + column: u_status + 1: + entityClass: CmsAddress + fieldResult: + 0: + name: id + column: a_id + 1: + name: zip + column: a_zip + 2: + name: country + column: a_country + id: + id: + type: integer + generator: + strategy: AUTO + fields: + name: + type: string + length: 255 + username: + type: string + length: 255 + unique: true + status: + type: string + length: 50 + unique: true + oneToOne: + address: + targetEntity: CmsAddress + orphanRemoval: true + inversedBy: user + joinColumn: + name: address_id + referencedColumnName: id + cascade: [ persist ] + oneToOne: + email: + targetEntity: CmsEmail + orphanRemoval: true + inversedBy: user + joinColumn: + nullable: true + referencedColumnName: id + cascade: [ persist ] + manyToMany: + groups: + targetEntity: CmsGroup + joinTable: + name: cms_users_groups + joinColumns: + user_id: + referencedColumnName: id + inverseJoinColumns: + group_id: + referencedColumnName: id + cascade: [ persist , detach, merge] \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.yml new file mode 100644 index 0000000..26846c5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.yml @@ -0,0 +1,75 @@ +Doctrine\Tests\Models\Company\CompanyPerson: + type: entity + table: company_persons + inheritanceType: JOINED + discriminatorMap: + person: CompanyPerson + manager: CompanyManager + employee: CompanyEmployee + namedNativeQueries: + fetchAllWithResultClass: + resultClass: __CLASS__ + query: SELECT id, name, discr FROM company_persons ORDER BY name + fetchAllWithSqlResultSetMapping: + name: fetchAllWithSqlResultSetMapping + resultSetMapping: mappingFetchAll + query: SELECT id, name, discr AS discriminator FROM company_persons ORDER BY name + + sqlResultSetMappings: + mappingFetchAll: + entityResult: + 0: + entityClass: __CLASS__ + discriminatorColumn: discriminator + fieldResult: + 0: + name: id + 1: + name: name + id: + id: + type: integer + generator: + strategy: AUTO + fields: + name: + type: string + length: 255 + username: + type: string + length: 255 + unique: true + status: + type: string + length: 50 + unique: true + oneToOne: + address: + targetEntity: CmsAddress + orphanRemoval: true + inversedBy: user + joinColumn: + name: address_id + referencedColumnName: id + cascade: [ persist ] + oneToOne: + email: + targetEntity: CmsEmail + orphanRemoval: true + inversedBy: user + joinColumn: + nullable: true + referencedColumnName: id + cascade: [ persist ] + manyToMany: + groups: + targetEntity: CmsGroup + joinTable: + name: cms_users_groups + joinColumns: + user_id: + referencedColumnName: id + inverseJoinColumns: + group_id: + referencedColumnName: id + cascade: [ persist , detach, merge] \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.yml new file mode 100644 index 0000000..3437a9b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.yml @@ -0,0 +1,8 @@ +Doctrine\Tests\Models\DDC1476\DDC1476EntityWithDefaultFieldType: + type: entity + id: + id: + generator: + strategy: NONE + fields: + name: \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.yml new file mode 100644 index 0000000..94f2698 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.yml @@ -0,0 +1,5 @@ +Doctrine\Tests\Models\DDC869\DDC869ChequePayment: + type: entity + fields: + serialNumber: + type: string \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.yml new file mode 100644 index 0000000..153a99f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.yml @@ -0,0 +1,5 @@ +Doctrine\Tests\Models\DDC869\DDC869CreditCardPayment: + type: entity + fields: + creditCardNumber: + type: string \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.yml new file mode 100644 index 0000000..b776664 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.yml @@ -0,0 +1,12 @@ +Doctrine\Tests\Models\DDC869\DDC869Payment: + type: mappedSuperclass + repositoryClass : Doctrine\Tests\Models\DDC869\DDC869PaymentRepository + id: + id: + type: integer + unsigned: true + generator: + strategy: AUTO + fields: + value: + type: float \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.yml new file mode 100644 index 0000000..567e5d5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.yml @@ -0,0 +1,8 @@ +Doctrine\Tests\Models\DDC889\DDC889Class: + type: class + id: + id: + type: integer + unsigned: true + generator: + strategy: AUTO \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.yml new file mode 100644 index 0000000..aa932db --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.yml @@ -0,0 +1,2 @@ +Doctrine\Tests\Models\DDC889\DDC889Entity: + type: entity \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.yml new file mode 100644 index 0000000..7974d55 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.yml @@ -0,0 +1,5 @@ +Doctrine\Tests\Models\DDC889\DDC889SuperClass: + type: mappedSuperclass + fields: + name: + type: string \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.yml new file mode 100644 index 0000000..0b8051d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.yml @@ -0,0 +1,17 @@ +Doctrine\Tests\Models\DDC964\DDC964Admin: + type: entity + associationOverride: + address: + joinColumn: + adminaddress_id: + name: adminaddress_id + referencedColumnName: id + groups: + joinTable: + name: ddc964_users_admingroups + joinColumns: + adminuser_id: + referencedColumnName: id + inverseJoinColumns: + admingroup_id: + referencedColumnName: id \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.yml new file mode 100644 index 0000000..ec7936f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.yml @@ -0,0 +1,13 @@ +Doctrine\Tests\Models\DDC964\DDC964Guest: + type: entity + attributeOverride: + id: + column: guest_id + type: integer + length: 140 + name: + column: guest_name + type: string + length: 240 + nullable: false + unique: true \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.yml new file mode 100644 index 0000000..3a9ebbf --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.yml @@ -0,0 +1,35 @@ +Doctrine\Tests\Models\DDC964\DDC964User: + type: mappedSuperclass + id: + id: + type: integer + column: user_id + length: 150 + generator: + strategy: AUTO + fields: + name: + type: string + column: user_name + length: 250 + nullable: true + unique: false + manyToOne: + address: + targetEntity: DDC964Address + joinColumn: + name: address_id + referencedColumnName: id + cascade: [ persist, merge ] + manyToMany: + groups: + targetEntity: DDC964Group + joinTable: + name: ddc964_users_groups + joinColumns: + user_id: + referencedColumnName: id + inverseJoinColumns: + group_id: + referencedColumnName: id + cascade: [ persist, merge, detach ] \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.AbstractContentItem.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.AbstractContentItem.dcm.yml new file mode 100644 index 0000000..9c573a5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.AbstractContentItem.dcm.yml @@ -0,0 +1,14 @@ +Doctrine\Tests\Models\DirectoryTree\AbstractContentItem: + type: mappedSuperclass + id: + id: + type: integer + unsigned: true + generator: + strategy: AUTO + fields: + name: + type: string + manyToOne: + parentDirectory: + targetEntity: Doctrine\Tests\Models\DirectoryTree\Directory diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.Directory.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.Directory.dcm.yml new file mode 100644 index 0000000..d2b93d4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.Directory.dcm.yml @@ -0,0 +1,6 @@ +Doctrine\Tests\Models\DirectoryTree\Directory: + type: entity + fields: + path: + type: string + length: 255 diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.File.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.File.dcm.yml new file mode 100644 index 0000000..cbc8edf --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.DirectoryTree.File.dcm.yml @@ -0,0 +1,6 @@ +Doctrine\Tests\Models\DirectoryTree\File: + type: entity + fields: + extension: + type: string + length: 10 diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.yml new file mode 100644 index 0000000..64f74b5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.yml @@ -0,0 +1,13 @@ +\stdClass: + type: entity + id: + id: + type: integer + unsigned: true + generator: + strategy: AUTO + fields: + array: + type: array + object: + type: object \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.Animal.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.Animal.dcm.yml new file mode 100644 index 0000000..7bdad82 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.Animal.dcm.yml @@ -0,0 +1,17 @@ +Doctrine\Tests\ORM\Mapping\Animal: + type: entity + inheritanceType: SINGLE_TABLE + discriminatorMap: + cat: Cat + dog: Dog + discriminatorColumn: + type: string + name: discr + length: 32 + id: + id: + type: integer + generator: + strategy: CUSTOM + customIdGenerator: + class: stdClass diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.yml new file mode 100644 index 0000000..8b2ac51 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.yml @@ -0,0 +1,10 @@ +Doctrine\Tests\ORM\Mapping\DDC1170Entity: + type: entity + id: + id: + columnDefinition: INT unsigned NOT NULL + generator: + strategy: NONE + fields: + value: + columnDefinition: VARCHAR(255) NOT NULL \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.yml new file mode 100644 index 0000000..20db3c3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.yml @@ -0,0 +1,13 @@ +Doctrine\Tests\ORM\Mapping\DDC807Entity: + type: entity + inheritanceType: SINGLE_TABLE + discriminatorMap: + ONE: DDC807SubClasse1 + TWO: DDC807SubClasse2 + discriminatorColumn: + name: dtype + columnDefinition: ENUM('ONE','TWO') + id: + id: + generator: + strategy: NONE \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml new file mode 100644 index 0000000..5c10185 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml @@ -0,0 +1,76 @@ +Doctrine\Tests\ORM\Mapping\User: + type: entity + table: cms_users + options: + foo: bar + baz: + key: val + namedQueries: + all: SELECT u FROM __CLASS__ u + id: + id: + type: integer + generator: + strategy: AUTO + sequenceGenerator: + sequenceName: tablename_seq + allocationSize: 100 + initialValue: 1 + fields: + name: + type: string + length: 50 + nullable: true + unique: true + options: + foo: bar + baz: + key: val + email: + type: string + column: user_email + columnDefinition: CHAR(32) NOT NULL + oneToOne: + address: + targetEntity: Address + inversedBy: user + joinColumn: + name: address_id + referencedColumnName: id + onDelete: CASCADE + cascade: [ remove ] + oneToMany: + phonenumbers: + targetEntity: Phonenumber + orphanRemoval: true + mappedBy: user + orderBy: + number: ASC + cascade: [ persist ] + manyToMany: + groups: + targetEntity: Group + joinTable: + name: cms_users_groups + joinColumns: + user_id: + referencedColumnName: id + nullable: false + unique: false + inverseJoinColumns: + group_id: + referencedColumnName: id + columnDefinition: INT NULL + cascade: + - all + lifecycleCallbacks: + prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ] + postPersist: [ doStuffOnPostPersist ] + uniqueConstraints: + search_idx: + columns: name,user_email + indexes: + name_idx: + columns: name + 0: + columns: user_email \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/HydrationPerformanceTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/HydrationPerformanceTest.php new file mode 100644 index 0000000..07a202e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/HydrationPerformanceTest.php @@ -0,0 +1,461 @@ + 0.7 seconds] + * + * MAXIMUM TIME: 1 second + */ + public function testSimpleQueryScalarHydrationPerformance10000Rows() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('u', 'u__username', 'username'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + ) + ); + + for ($i = 4; $i < 10000; ++$i) { + $resultSet[] = array( + 'u__id' => $i, + 'u__status' => 'developer', + 'u__username' => 'jwage', + 'u__name' => 'Jonathan', + ); + } + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this->_em); + + $this->setMaxRunningTime(1); + $s = microtime(true); + $result = $hydrator->hydrateAll($stmt, $rsm); + $e = microtime(true); + echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL; + } + + /** + * Times for comparison: + * + * [romanb: 10000 rows => 1 second] + * + * MAXIMUM TIME: 2 seconds + */ + public function testSimpleQueryArrayHydrationPerformance10000Rows() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('u', 'u__username', 'username'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + ) + ); + + for ($i = 4; $i < 10000; ++$i) { + $resultSet[] = array( + 'u__id' => $i, + 'u__status' => 'developer', + 'u__username' => 'jwage', + 'u__name' => 'Jonathan', + ); + } + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + + $this->setMaxRunningTime(2); + $s = microtime(true); + $result = $hydrator->hydrateAll($stmt, $rsm); + $e = microtime(true); + echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL; + } + + /** + * Times for comparison: + * + * [romanb: 10000 rows => 1.4 seconds] + * + * MAXIMUM TIME: 3 seconds + */ + public function testMixedQueryFetchJoinArrayHydrationPerformance10000Rows() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('u', 'u__username', 'username'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91' + ) + ); + + for ($i = 4; $i < 10000; ++$i) { + $resultSet[] = array( + 'u__id' => $i, + 'u__status' => 'developer', + 'u__username' => 'jwage', + 'u__name' => 'Jonathan', + 'sclr0' => 'JWAGE' . $i, + 'p__phonenumber' => '91' + ); + } + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em); + + $this->setMaxRunningTime(3); + $s = microtime(true); + $result = $hydrator->hydrateAll($stmt, $rsm); + $e = microtime(true); + echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL; + } + + /** + * [romanb: 10000 rows => 1.5 seconds] + * + * MAXIMUM TIME: 3 seconds + */ + public function testSimpleQueryPartialObjectHydrationPerformance10000Rows() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('u', 'u__username', 'username'); + $rsm->addFieldResult('u', 'u__name', 'name'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + ) + ); + + for ($i = 4; $i < 10000; ++$i) { + $resultSet[] = array( + 'u__id' => $i, + 'u__status' => 'developer', + 'u__username' => 'jwage', + 'u__name' => 'Jonathan', + ); + } + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + + $this->setMaxRunningTime(3); + $s = microtime(true); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + $e = microtime(true); + echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL; + } + + /** + * [romanb: 10000 rows => 3 seconds] + * + * MAXIMUM TIME: 4.5 seconds + */ + public function testSimpleQueryFullObjectHydrationPerformance10000Rows() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('u', 'u__username', 'username'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsAddress', + 'a', + 'u', + 'address' + ); + $rsm->addFieldResult('a', 'a__id', 'id'); + //$rsm->addFieldResult('a', 'a__country', 'country'); + //$rsm->addFieldResult('a', 'a__zip', 'zip'); + //$rsm->addFieldResult('a', 'a__city', 'city'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + 'a__id' => '1' + ) + ); + + for ($i = 2; $i < 10000; ++$i) { + $resultSet[] = array( + 'u__id' => $i, + 'u__status' => 'developer', + 'u__username' => 'jwage', + 'u__name' => 'Jonathan', + 'a__id' => $i + ); + } + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + + $this->setMaxRunningTime(5); + $s = microtime(true); + $result = $hydrator->hydrateAll($stmt, $rsm); + $e = microtime(true); + echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL; + } + + /** + * [romanb: 2000 rows => 0.4 seconds] + * + * MAXIMUM TIME: 1 second + */ + public function testMixedQueryFetchJoinPartialObjectHydrationPerformance2000Rows() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('u', 'u__username', 'username'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + ), + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '43', + ), + array( + 'u__id' => '2', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + 'sclr0' => 'JWAGE', + 'p__phonenumber' => '91' + ) + ); + + for ($i = 4; $i < 2000; ++$i) { + $resultSet[] = array( + 'u__id' => $i, + 'u__status' => 'developer', + 'u__username' => 'jwage', + 'u__name' => 'Jonathan', + 'sclr0' => 'JWAGE' . $i, + 'p__phonenumber' => '91' + ); + } + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + + $this->setMaxRunningTime(1); + $s = microtime(true); + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true)); + $e = microtime(true); + echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL; + } + + /** + * [romanb: 2000 rows => 0.6 seconds] + * + * MAXIMUM TIME: 1 second + */ + public function testMixedQueryFetchJoinFullObjectHydrationPerformance2000Rows() + { + $rsm = new ResultSetMapping; + $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'p', + 'u', + 'phonenumbers' + ); + $rsm->addFieldResult('u', 'u__id', 'id'); + $rsm->addFieldResult('u', 'u__status', 'status'); + $rsm->addFieldResult('u', 'u__username', 'username'); + $rsm->addFieldResult('u', 'u__name', 'name'); + $rsm->addScalarResult('sclr0', 'nameUpper'); + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber'); + $rsm->addJoinedEntityResult( + 'Doctrine\Tests\Models\CMS\CmsAddress', + 'a', + 'u', + 'address' + ); + $rsm->addFieldResult('a', 'a__id', 'id'); + + // Faked result set + $resultSet = array( + //row1 + array( + 'u__id' => '1', + 'u__status' => 'developer', + 'u__username' => 'romanb', + 'u__name' => 'Roman', + 'sclr0' => 'ROMANB', + 'p__phonenumber' => '42', + 'a__id' => '1' + ) + ); + + for ($i = 2; $i < 2000; ++$i) { + $resultSet[] = array( + 'u__id' => $i, + 'u__status' => 'developer', + 'u__username' => 'jwage', + 'u__name' => 'Jonathan', + 'sclr0' => 'JWAGE' . $i, + 'p__phonenumber' => '91', + 'a__id' => $i + ); + } + + $stmt = new HydratorMockStatement($resultSet); + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); + + $this->setMaxRunningTime(1); + $s = microtime(true); + $result = $hydrator->hydrateAll($stmt, $rsm); + $e = microtime(true); + echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/InheritancePersisterPerformanceTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/InheritancePersisterPerformanceTest.php new file mode 100644 index 0000000..1c19264 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/InheritancePersisterPerformanceTest.php @@ -0,0 +1,66 @@ +useModelSet('company'); + parent::setUp(); + } + + public function testCompanyContract() + { + $person = new \Doctrine\Tests\Models\Company\CompanyEmployee(); + $person->setName('Poor Sales Guy'); + $person->setDepartment('Sales'); + $person->setSalary(100); + $this->_em->persist($person); + + for ($i = 0; $i < 33; $i++) { + $fix = new \Doctrine\Tests\Models\Company\CompanyFixContract(); + $fix->setFixPrice(1000); + $fix->setSalesPerson($person); + $fix->markCompleted(); + $this->_em->persist($fix); + + $flex = new \Doctrine\Tests\Models\Company\CompanyFlexContract(); + $flex->setSalesPerson($person); + $flex->setHoursWorked(100); + $flex->setPricePerHour(100); + $flex->markCompleted(); + $this->_em->persist($flex); + + $ultra = new \Doctrine\Tests\Models\Company\CompanyFlexUltraContract(); + $ultra->setSalesPerson($person); + $ultra->setHoursWorked(150); + $ultra->setPricePerHour(150); + $ultra->setMaxPrice(7000); + $this->_em->persist($ultra); + } + + $this->_em->flush(); + $this->_em->clear(); + + $start = microtime(true); + $contracts = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyContract')->findAll(); + echo "99 CompanyContract: " . number_format(microtime(true) - $start, 6) . "\n"; + $this->assertEquals(99, count($contracts)); + + $this->_em->clear(); + + $start = microtime(true); + $contracts = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyContract')->findAll(); + echo "99 CompanyContract: " . number_format(microtime(true) - $start, 6) . "\n"; + $this->assertEquals(99, count($contracts)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/InsertPerformanceTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/InsertPerformanceTest.php new file mode 100644 index 0000000..1c378df --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/InsertPerformanceTest.php @@ -0,0 +1,56 @@ +useModelSet('cms'); + parent::setUp(); + } + + /** + * [romanb: 10000 objects in ~8 seconds] + */ + public function testInsertPerformance() + { + $s = microtime(true); + + $conn = $this->_em->getConnection(); + + $this->setMaxRunningTime(10); + + //echo "Memory usage before: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL; + + $batchSize = 20; + for ($i=1; $i<=10000; ++$i) { + $user = new CmsUser; + $user->status = 'user'; + $user->username = 'user' . $i; + $user->name = 'Mr.Smith-' . $i; + $this->_em->persist($user); + if (($i % $batchSize) == 0) { + $this->_em->flush(); + $this->_em->clear(); + } + } + + //gc_collect_cycles(); + //echo "Memory usage after: " . (memory_get_usage() / 1024) . " KB" . PHP_EOL; + + $e = microtime(true); + + echo ' Inserted 10000 objects in ' . ($e - $s) . ' seconds' . PHP_EOL; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/PersisterPerformanceTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/PersisterPerformanceTest.php new file mode 100644 index 0000000..ec43268 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/PersisterPerformanceTest.php @@ -0,0 +1,121 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testFindCmsArticle() + { + $author = new CmsUser(); + $author->name = "beberlei"; + $author->status = "active"; + $author->username = "beberlei"; + $this->_em->persist($author); + + $ids = array(); + for ($i = 0; $i < 100; $i++) { + $article = new CmsArticle(); + $article->text = "foo"; + $article->topic = "bar"; + $article->user = $author; + $this->_em->persist($article); + $ids[] = $article; + } + $this->_em->flush(); + $this->_em->clear(); + + $start = microtime(true); + $articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsArticle')->findAll(); + echo "100 CmsArticle findAll(): " . number_format(microtime(true) - $start, 6) . "\n"; + + $this->_em->clear(); + + $start = microtime(true); + $articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsArticle')->findAll(); + echo "100 CmsArticle findAll(): " . number_format(microtime(true) - $start, 6) . "\n"; + + $this->_em->clear(); + + $start = microtime(true); + for ($i = 0; $i < 100; $i++) { + $articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsArticle')->find($ids[$i]->id); + } + echo "100 CmsArticle find(): " . number_format(microtime(true) - $start, 6) . "\n"; + + $this->_em->clear(); + + $start = microtime(true); + for ($i = 0; $i < 100; $i++) { + $articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsArticle')->find($ids[$i]->id); + } + echo "100 CmsArticle find(): " . number_format(microtime(true) - $start, 6) . "\n"; + } + + public function testFindCmsGroup() + { + for ($i = 0; $i < 100; $i++) { + $group = new CmsGroup(); + $group->name = "foo" . $i; + $this->_em->persist($group); + } + $this->_em->flush(); + $this->_em->clear(); + + $start = microtime(true); + $articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll(); + echo "100 CmsGroup: " . number_format(microtime(true) - $start, 6) . "\n"; + + $this->_em->clear(); + + $start = microtime(true); + $articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll(); + echo "100 CmsGroup: " . number_format(microtime(true) - $start, 6) . "\n"; + } + + public function testFindCmsUser() + { + for ($i = 0; $i < 100; $i++) { + $user = new CmsUser(); + $user->name = "beberlei"; + $user->status = "active"; + $user->username = "beberlei".$i; + $this->_em->persist($user); + } + + $this->_em->flush(); + $this->_em->clear(); + + $start = microtime(true); + $articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->findAll(); + echo "100 CmsUser: " . number_format(microtime(true) - $start, 6) . "\n"; + + $this->_em->clear(); + + $start = microtime(true); + $articles = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->findAll(); + echo "100 CmsUser: " . number_format(microtime(true) - $start, 6) . "\n"; + } +} + + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/UnitOfWorkPerformanceTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/UnitOfWorkPerformanceTest.php new file mode 100644 index 0000000..9320828 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Performance/UnitOfWorkPerformanceTest.php @@ -0,0 +1,51 @@ +useModelSet('cms'); + parent::setUp(); + } + + public function testComputeChanges() + { + $n = 100; + + $users = array(); + for ($i=1; $i<=$n; ++$i) { + $user = new CmsUser; + $user->status = 'user'; + $user->username = 'user' . $i; + $user->name = 'Mr.Smith-' . $i; + $this->_em->persist($user); + $users[] = $user; + } + $this->_em->flush(); + + + foreach ($users AS $user) { + $user->status = 'other'; + $user->username = $user->username . '++'; + $user->name = str_replace('Mr.', 'Mrs.', $user->name); + } + + $s = microtime(true); + $this->_em->flush(); + $e = microtime(true); + + echo ' Compute ChangeSet '.$n.' objects in ' . ($e - $s) . ' seconds' . PHP_EOL; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php new file mode 100644 index 0000000..fd0dffb --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php @@ -0,0 +1,37 @@ + + */ +class PersistentCollectionTest extends \Doctrine\Tests\OrmTestCase +{ + private $_connectionMock; + private $_emMock; + + protected function setUp() + { + parent::setUp(); + // SUT + $this->_connectionMock = new ConnectionMock(array(), new \Doctrine\Tests\Mocks\DriverMock()); + $this->_emMock = EntityManagerMock::create($this->_connectionMock); + } + + public function testCanBePutInLazyLoadingMode() + { + $class = $this->_emMock->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct'); + $collection = new PersistentCollection($this->_emMock, $class, new ArrayCollection); + $collection->setInitialized(false); + $this->assertFalse($collection->isInitialized()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php new file mode 100644 index 0000000..fa1d753 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php @@ -0,0 +1,91 @@ +_em = $this->_getTestEntityManager(); + + $this->_persister = new BasicEntityPersister($this->_em, $this->_em->getClassMetadata("Doctrine\Tests\Models\CustomType\CustomTypeParent")); + } + + public function testGetInsertSQLUsesTypeValuesSQL() + { + $method = new \ReflectionMethod($this->_persister, '_getInsertSQL'); + $method->setAccessible(true); + + $sql = $method->invoke($this->_persister); + + $this->assertEquals('INSERT INTO customtype_parents (customInteger, child_id) VALUES (ABS(?), ?)', $sql); + } + + public function testUpdateUsesTypeValuesSQL() + { + $child = new CustomTypeChild(); + + $parent = new CustomTypeParent(); + $parent->customInteger = 1; + $parent->child = $child; + + $this->_em->getUnitOfWork()->registerManaged($parent, array('id' => 1), array('customInteger' => 0, 'child' => null)); + $this->_em->getUnitOfWork()->registerManaged($child, array('id' => 1), array()); + + $this->_em->getUnitOfWork()->propertyChanged($parent, 'customInteger', 0, 1); + $this->_em->getUnitOfWork()->propertyChanged($parent, 'child', null, $child); + + $this->_persister->update($parent); + + $executeUpdates = $this->_em->getConnection()->getExecuteUpdates(); + + $this->assertEquals('UPDATE customtype_parents SET customInteger = ABS(?), child_id = ? WHERE id = ?', $executeUpdates[0]['query']); + } + + public function testGetSelectConditionSQLUsesTypeValuesSQL() + { + $method = new \ReflectionMethod($this->_persister, '_getSelectConditionSQL'); + $method->setAccessible(true); + + $sql = $method->invoke($this->_persister, array('customInteger' => 1, 'child' => 1)); + + $this->assertEquals('t0.customInteger = ABS(?) AND t0.child_id = ?', $sql); + } + + /** + * @group DDC-1719 + */ + public function testStripNonAlphanumericCharactersFromSelectColumnListSQL() + { + $persister = new BasicEntityPersister($this->_em, $this->_em->getClassMetadata('Doctrine\Tests\Models\Quote\SimpleEntity')); + $method = new \ReflectionMethod($persister, '_getSelectColumnListSQL'); + $method->setAccessible(true); + + $this->assertEquals('t0."simple-entity-id" AS simpleentityid1, t0."simple-entity-value" AS simpleentityvalue2', $method->invoke($persister)); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/AutoloaderTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/AutoloaderTest.php new file mode 100644 index 0000000..af0afec --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/AutoloaderTest.php @@ -0,0 +1,62 @@ +. + */ + +namespace Doctrine\Tests\ORM\Proxy; + +use Doctrine\Tests\OrmTestCase; +use Doctrine\ORM\Proxy\Autoloader; + +/** + * @group DDC-1698 + */ +class AutoloaderTest extends OrmTestCase +{ + static public function dataResolveFile() + { + return array( + array('/tmp', 'MyProxy', 'MyProxy\__CG__\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__RealClass.php'), + array('/tmp', 'MyProxy\Subdir', 'MyProxy\Subdir\__CG__\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__RealClass.php'), + array('/tmp', 'MyProxy', 'MyProxy\__CG__\Other\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__OtherRealClass.php'), + ); + } + + /** + * @dataProvider dataResolveFile + */ + public function testResolveFile($proxyDir, $proxyNamespace, $className, $expectedProxyFile) + { + $actualProxyFile = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className); + $this->assertEquals($expectedProxyFile, $actualProxyFile); + } + + public function testAutoload() + { + if (file_exists(sys_get_temp_dir() ."/AutoloaderTestClass.php")) { + unlink(sys_get_temp_dir() ."/AutoloaderTestClass.php"); + } + + $autoloader = Autoloader::register(sys_get_temp_dir(), 'ProxyAutoloaderTest', function($proxyDir, $proxyNamespace, $className) { + file_put_contents(sys_get_temp_dir() . "/AutoloaderTestClass.php", "assertTrue(class_exists('ProxyAutoloaderTest\AutoloaderTestClass', true)); + unlink(sys_get_temp_dir() ."/AutoloaderTestClass.php"); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/ProxyClassGeneratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/ProxyClassGeneratorTest.php new file mode 100644 index 0000000..894d500 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/ProxyClassGeneratorTest.php @@ -0,0 +1,204 @@ + + */ +class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase +{ + private $_connectionMock; + private $_uowMock; + private $_emMock; + + /** + * @var \Doctrine\ORM\Proxy\ProxyFactory + */ + private $_proxyFactory; + + protected function setUp() + { + parent::setUp(); + $this->_connectionMock = new ConnectionMock(array(), new \Doctrine\Tests\Mocks\DriverMock()); + $this->_emMock = EntityManagerMock::create($this->_connectionMock); + $this->_uowMock = new UnitOfWorkMock($this->_emMock); + $this->_emMock->setUnitOfWork($this->_uowMock); + // SUT + $this->_proxyFactory = new ProxyFactory($this->_emMock, __DIR__ . '/generated', 'Proxies', true); + } + + protected function tearDown() + { + foreach (new \DirectoryIterator(__DIR__ . '/generated') as $file) { + if (strstr($file->getFilename(), '.php')) { + unlink($file->getPathname()); + } + } + } + + public function testReferenceProxyDelegatesLoadingToThePersister() + { + $identifier = array('id' => 42); + $proxyClass = 'Proxies\__CG__\Doctrine\Tests\Models\ECommerce\ECommerceFeature'; + $persister = $this->_getMockPersister(); + $this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); + + $proxy = $this->_proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $identifier); + + $persister->expects($this->atLeastOnce()) + ->method('load') + ->with($this->equalTo($identifier), $this->isInstanceOf($proxyClass)) + ->will($this->returnValue(new \stdClass())); // fake return of entity instance + + $proxy->getDescription(); + } + + public function testReferenceProxyExecutesLoadingOnlyOnce() + { + $identifier = array('id' => 42); + $proxyClass = 'Proxies\__CG__\Doctrine\Tests\Models\ECommerce\ECommerceFeature'; + $persister = $this->_getMockPersister(); + $this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); + $proxy = $this->_proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $identifier); + + $persister->expects($this->atLeastOnce()) + ->method('load') + ->with($this->equalTo($identifier), $this->isInstanceOf($proxyClass)) + ->will($this->returnValue(new \stdClass())); // fake return of entity instance + $proxy->getDescription(); + $proxy->getProduct(); + } + + public function testReferenceProxyRespectsMethodsParametersTypeHinting() + { + $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy'; + $persister = $this->_getMockPersister(); + $this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); + $proxy = $this->_proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', null); + + $method = new \ReflectionMethod(get_class($proxy), 'setProduct'); + $params = $method->getParameters(); + + $this->assertEquals(1, count($params)); + $this->assertEquals('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $params[0]->getClass()->getName()); + } + + /** + * Test that the proxy behaves in regard to methods like &foo() correctly + */ + public function testProxyRespectsMethodsWhichReturnValuesByReference() { + $proxy = $this->_proxyFactory->getProxy('Doctrine\Tests\Models\Forum\ForumEntry', null); + $method = new \ReflectionMethod(get_class($proxy), 'getTopicByReference'); + + $this->assertTrue($method->returnsReference()); + } + + public function testCreatesAssociationProxyAsSubclassOfTheOriginalOne() + { + $proxyClass = 'Proxies\__CG__\Doctrine\Tests\Models\ECommerce\ECommerceFeature'; + $this->assertTrue(is_subclass_of($proxyClass, 'Doctrine\Tests\Models\ECommerce\ECommerceFeature')); + } + + + public function testAllowsConcurrentCreationOfBothProxyTypes() + { + $referenceProxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy'; + $associationProxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureAProxy'; + $this->assertNotEquals($referenceProxyClass, $associationProxyClass); + } + + public function testNonNamespacedProxyGeneration() + { + require_once dirname(__FILE__)."/fixtures/NonNamespacedProxies.php"; + + $className = "\DoctrineOrmTestEntity"; + $proxyName = "DoctrineOrmTestEntity"; + $classMetadata = new \Doctrine\ORM\Mapping\ClassMetadata($className); + $classMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $classMetadata->mapField(array('fieldName' => 'id', 'type' => 'integer')); + $classMetadata->setIdentifier(array('id')); + + $this->_proxyFactory->generateProxyClasses(array($classMetadata)); + + $classCode = file_get_contents(dirname(__FILE__)."/generated/__CG__".$proxyName.".php"); + + $this->assertNotContains("class DoctrineOrmTestEntity extends \\\\DoctrineOrmTestEntity", $classCode); + $this->assertContains("class DoctrineOrmTestEntity extends \\DoctrineOrmTestEntity", $classCode); + } + + public function testClassWithSleepProxyGeneration() + { + $className = "\Doctrine\Tests\ORM\Proxy\SleepClass"; + $proxyName = "DoctrineTestsORMProxySleepClass"; + $classMetadata = new \Doctrine\ORM\Mapping\ClassMetadata($className); + $classMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $classMetadata->mapField(array('fieldName' => 'id', 'type' => 'integer')); + $classMetadata->setIdentifier(array('id')); + + $this->_proxyFactory->generateProxyClasses(array($classMetadata)); + + $classCode = file_get_contents(dirname(__FILE__)."/generated/__CG__".$proxyName.".php"); + + $this->assertEquals(1, substr_count($classCode, 'function __sleep')); + } + + /** + * @group DDC-1771 + */ + public function testSkipAbstractClassesOnGeneration() + { + $cm = new \Doctrine\ORM\Mapping\ClassMetadata(__NAMESPACE__ . '\\AbstractClass'); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + $this->assertNotNull($cm->reflClass); + + $num = $this->_proxyFactory->generateProxyClasses(array($cm)); + + $this->assertEquals(0, $num, "No proxies generated."); + } + + public function testNoConfigDir_ThrowsException() + { + $this->setExpectedException('Doctrine\ORM\Proxy\ProxyException'); + new ProxyFactory($this->_getTestEntityManager(), null, null); + } + + public function testNoNamespace_ThrowsException() + { + $this->setExpectedException('Doctrine\ORM\Proxy\ProxyException'); + new ProxyFactory($this->_getTestEntityManager(), __DIR__ . '/generated', null); + } + + protected function _getMockPersister() + { + $persister = $this->getMock('Doctrine\ORM\Persisters\BasicEntityPersister', array('load'), array(), '', false); + return $persister; + } +} + +class SleepClass +{ + public $id; + + public function __sleep() + { + return array('id'); + } +} + +abstract class AbstractClass +{ + +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/fixtures/NonNamespacedProxies.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/fixtures/NonNamespacedProxies.php new file mode 100644 index 0000000..88c06e4 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Proxy/fixtures/NonNamespacedProxies.php @@ -0,0 +1,13 @@ +. + */ + +namespace Doctrine\Tests\ORM\Query; + +require_once __DIR__ . '/../../TestInit.php'; + +/** + * Test case for testing the saving and referencing of query identifiers. + * + * @author Guilherme Blanco + * @author Janne Vanhala + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + * @todo 1) [romanb] We might want to split the SQL generation tests into multiple + * testcases later since we'll have a lot of them and we might want to have special SQL + * generation tests for some dbms specific SQL syntaxes. + */ +class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase +{ + private $_em; + + protected function setUp() { + $this->_em = $this->_getTestEntityManager(); + } + + public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed) + { + try { + $query = $this->_em->createQuery($dqlToBeTested); + parent::assertEquals($sqlToBeConfirmed, $query->getSql()); + $query->free(); + } catch (\Exception $e) { + $this->fail($e->getMessage()); + } + } + + public function testSupportsDeleteWithoutWhereAndFrom() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u', + 'DELETE FROM cms_users' + ); + } + + public function testSupportsDeleteWithoutWhere() + { + $this->assertSqlGeneration( + 'DELETE FROM Doctrine\Tests\Models\CMS\CmsUser u', + 'DELETE FROM cms_users' + ); + } + + public function testSupportsWhereClause() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1', + 'DELETE FROM cms_users WHERE id = ?' + ); + } + + public function testSupportsWhereOrExpressions() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ?1 OR u.name = ?2', + 'DELETE FROM cms_users WHERE username = ? OR name = ?' + ); + } + + public function testSupportsWhereNestedConditionalExpressions() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1 OR ( u.username = ?2 OR u.name = ?3)', + 'DELETE FROM cms_users WHERE id = ? OR (username = ? OR name = ?)' + ); + + //$this->assertSqlGeneration( + // 'DELETE FROM Doctrine\Tests\Models\CMS\CmsUser WHERE id = ?1', + // 'DELETE FROM cms_users WHERE id = ?' + //); + } + + public function testIsCaseAgnostic() + { + $this->assertSqlGeneration( + "delete from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1", + "DELETE FROM cms_users WHERE username = ?" + ); + } + + public function testSupportsAndCondition() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ?1 AND u.name = ?2", + "DELETE FROM cms_users WHERE username = ? AND name = ?" + ); + } + + public function testSupportsWhereNot() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT u.id != ?1", + "DELETE FROM cms_users WHERE NOT id <> ?" + ); + } + + public function testSupportsWhereNotWithParentheses() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT ( u.id != ?1 )", + "DELETE FROM cms_users WHERE NOT (id <> ?)" + ); + } + + public function testSupportsWhereNotWithAndExpression() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT ( u.id != ?1 AND u.username = ?2 )", + "DELETE FROM cms_users WHERE NOT (id <> ? AND username = ?)" + ); + } + + // ConditionalPrimary was already tested (see testSupportsWhereClause() and testSupportsWhereNot()) + + public function testSupportsGreaterThanComparisonClause() + { + // id = ? was already tested (see testDeleteWithWhere()) + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > ?1", + "DELETE FROM cms_users WHERE id > ?" + ); + } + + public function testSupportsGreaterThanOrEqualToComparisonClause() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id >= ?1", + "DELETE FROM cms_users WHERE id >= ?" + ); + } + + public function testSupportsLessThanComparisonClause() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id < ?1", + "DELETE FROM cms_users WHERE id < ?" + ); + } + + public function testSupportsLessThanOrEqualToComparisonClause() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id <= ?1", + "DELETE FROM cms_users WHERE id <= ?" + ); + } + + public function testSupportsNotEqualToComparisonClause() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id <> ?1", + "DELETE FROM cms_users WHERE id <> ?" + ); + } + + public function testSupportsNotEqualToComparisonClauseExpressedWithExclamationMark() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id != ?1", + "DELETE FROM cms_users WHERE id <> ?" + ); + } + + public function testSupportsNotBetweenClause() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT BETWEEN ?1 AND ?2", + "DELETE FROM cms_users WHERE id NOT BETWEEN ? AND ?" + ); + } + + public function testSupportsBetweenClauseUsedWithAndClause() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id BETWEEN ?1 AND ?2 AND u.username != ?3", + "DELETE FROM cms_users WHERE id BETWEEN ? AND ? AND username <> ?" + ); + } + + public function testSupportsNotLikeClause() + { + // "WHERE" Expression LikeExpression + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username NOT LIKE ?1', + 'DELETE FROM cms_users WHERE username NOT LIKE ?' + ); + } + + public function testSupportsLikeClauseWithEscapeExpression() + { + $this->assertSqlGeneration( + "DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username LIKE ?1 ESCAPE '\\'", + "DELETE FROM cms_users WHERE username LIKE ? ESCAPE '\\'" + ); + } + + public function testSupportsIsNullClause() + { + // "WHERE" Expression NullComparisonExpression + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IS NULL', + 'DELETE FROM cms_users WHERE name IS NULL' + ); + } + + public function testSupportsIsNotNullClause() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IS NOT NULL', + 'DELETE FROM cms_users WHERE name IS NOT NULL' + ); + } + + public function testSupportsAtomExpressionAsClause() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE 1 = 1', + 'DELETE FROM cms_users WHERE 1 = 1' + ); + } + + public function testSupportsParameterizedAtomExpression() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE ?1 = 1', + 'DELETE FROM cms_users WHERE ? = 1' + ); + } + + public function testSupportsInClause() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN ( ?1, ?2, ?3, ?4 )', + 'DELETE FROM cms_users WHERE id IN (?, ?, ?, ?)' + ); + } + + public function testSupportsNotInClause() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN ( ?1, ?2 )', + 'DELETE FROM cms_users WHERE id NOT IN (?, ?)' + ); + } + + /** + * @group DDC-980 + */ + public function testSubselectTableAliasReferencing() + { + $this->assertSqlGeneration( + 'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE SIZE(u.groups) = 10', + 'DELETE FROM cms_users WHERE (SELECT COUNT(*) FROM cms_users_groups c0_ WHERE c0_.user_id = cms_users.id) = 10' + ); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ExprTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ExprTest.php new file mode 100644 index 0000000..122b98f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ExprTest.php @@ -0,0 +1,412 @@ +. + */ + +namespace Doctrine\Tests\ORM\Query; + +use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\Query; + +require_once __DIR__ . '/../../TestInit.php'; + +/** + * Test case for the DQL Expr class used for generating DQL snippets through + * a programmatic interface + * + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + */ +class ExprTest extends \Doctrine\Tests\OrmTestCase +{ + private $_em; + + protected function setUp() + { + $this->_em = $this->_getTestEntityManager(); + $this->_expr = new Expr; + } + + public function testAvgExpr() + { + $this->assertEquals('AVG(u.id)', (string) $this->_expr->avg('u.id')); + } + + public function testMaxExpr() + { + $this->assertEquals('MAX(u.id)', (string) $this->_expr->max('u.id')); + } + + public function testMinExpr() + { + $this->assertEquals('MIN(u.id)', (string) $this->_expr->min('u.id')); + } + + public function testCountExpr() + { + $this->assertEquals('MAX(u.id)', (string) $this->_expr->max('u.id')); + } + + public function testCountDistinctExpr() + { + $this->assertEquals('COUNT(DISTINCT u.id)', (string) $this->_expr->countDistinct('u.id')); + } + + public function testExistsExpr() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u')->from('User', 'u')->where('u.name = ?1'); + + $this->assertEquals('EXISTS(SELECT u FROM User u WHERE u.name = ?1)', (string) $this->_expr->exists($qb)); + } + + public function testAllExpr() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u')->from('User', 'u')->where('u.name = ?1'); + + $this->assertEquals('ALL(SELECT u FROM User u WHERE u.name = ?1)', (string) $this->_expr->all($qb)); + } + + public function testSomeExpr() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u')->from('User', 'u')->where('u.name = ?1'); + + $this->assertEquals('SOME(SELECT u FROM User u WHERE u.name = ?1)', (string) $this->_expr->some($qb)); + } + + public function testAnyExpr() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u')->from('User', 'u')->where('u.name = ?1'); + + $this->assertEquals('ANY(SELECT u FROM User u WHERE u.name = ?1)', (string) $this->_expr->any($qb)); + } + + public function testNotExpr() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u')->from('User', 'u')->where('u.name = ?1'); + + $this->assertEquals('NOT(SELECT u FROM User u WHERE u.name = ?1)', (string) $this->_expr->not($qb)); + } + + public function testAndExpr() + { + $this->assertEquals('1 = 1 AND 2 = 2', (string) $this->_expr->andx((string) $this->_expr->eq(1, 1), (string) $this->_expr->eq(2, 2))); + } + + public function testIntelligentParenthesisPreventionAndExpr() + { + $this->assertEquals( + '1 = 1 AND 2 = 2', + (string) $this->_expr->andx($this->_expr->orx($this->_expr->andx($this->_expr->eq(1, 1))), (string) $this->_expr->eq(2, 2)) + ); + } + + public function testOrExpr() + { + $this->assertEquals('1 = 1 OR 2 = 2', (string) $this->_expr->orx((string) $this->_expr->eq(1, 1), (string) $this->_expr->eq(2, 2))); + } + + public function testAbsExpr() + { + $this->assertEquals('ABS(1)', (string) $this->_expr->abs(1)); + } + + public function testProdExpr() + { + $this->assertEquals('1 * 2', (string) $this->_expr->prod(1, 2)); + } + + public function testDiffExpr() + { + $this->assertEquals('1 - 2', (string) $this->_expr->diff(1, 2)); + } + + public function testSumExpr() + { + $this->assertEquals('1 + 2', (string) $this->_expr->sum(1, 2)); + } + + public function testQuotientExpr() + { + $this->assertEquals('10 / 2', (string) $this->_expr->quot(10, 2)); + } + + public function testScopeInArithmeticExpr() + { + $this->assertEquals('(100 - 20) / 2', (string) $this->_expr->quot($this->_expr->diff(100, 20), 2)); + $this->assertEquals('100 - (20 / 2)', (string) $this->_expr->diff(100, $this->_expr->quot(20, 2))); + } + + public function testSquareRootExpr() + { + $this->assertEquals('SQRT(1)', (string) $this->_expr->sqrt(1)); + } + + public function testEqualExpr() + { + $this->assertEquals('1 = 1', (string) $this->_expr->eq(1, 1)); + } + + public function testLikeExpr() + { + $this->assertEquals('a.description LIKE :description', (string) $this->_expr->like('a.description', ':description')); + } + + public function testConcatExpr() + { + $this->assertEquals('CONCAT(u.first_name, u.last_name)', (string) $this->_expr->concat('u.first_name', 'u.last_name')); + } + + public function testSubstringExpr() + { + $this->assertEquals('SUBSTRING(a.title, 0, 25)', (string) $this->_expr->substring('a.title', 0, 25)); + } + + /** + * @group regression + * @group DDC-612 + */ + public function testSubstringExprAcceptsTwoArguments() + { + $this->assertEquals('SUBSTRING(a.title, 5)', (string) $this->_expr->substring('a.title', 5)); + } + + public function testLowerExpr() + { + $this->assertEquals('LOWER(u.first_name)', (string) $this->_expr->lower('u.first_name')); + } + + public function testUpperExpr() + { + $this->assertEquals('UPPER(u.first_name)', (string) $this->_expr->upper('u.first_name')); + } + + public function testLengthExpr() + { + $this->assertEquals('LENGTH(u.first_name)', (string) $this->_expr->length('u.first_name')); + } + + public function testGreaterThanExpr() + { + $this->assertEquals('5 > 2', (string) $this->_expr->gt(5, 2)); + } + + public function testLessThanExpr() + { + $this->assertEquals('2 < 5', (string) $this->_expr->lt(2, 5)); + } + + public function testStringLiteralExpr() + { + $this->assertEquals("'word'", (string) $this->_expr->literal('word')); + } + + public function testNumericLiteralExpr() + { + $this->assertEquals(5, (string) $this->_expr->literal(5)); + } + + /** + * @group regression + * @group DDC-610 + */ + public function testLiteralExprProperlyQuotesStrings() + { + $this->assertEquals("'00010001'", (string) $this->_expr->literal('00010001')); + } + + public function testGreaterThanOrEqualToExpr() + { + $this->assertEquals('5 >= 2', (string) $this->_expr->gte(5, 2)); + } + + public function testLessThanOrEqualTo() + { + $this->assertEquals('2 <= 5', (string) $this->_expr->lte(2, 5)); + } + + public function testBetweenExpr() + { + $this->assertEquals('u.id BETWEEN 3 AND 6', (string) $this->_expr->between('u.id', 3, 6)); + } + + public function testTrimExpr() + { + $this->assertEquals('TRIM(u.id)', (string) $this->_expr->trim('u.id')); + } + + public function testIsNullExpr() + { + $this->assertEquals('u.id IS NULL', (string) $this->_expr->isNull('u.id')); + } + + public function testIsNotNullExpr() + { + $this->assertEquals('u.id IS NOT NULL', (string) $this->_expr->isNotNull('u.id')); + } + + public function testInExpr() + { + $this->assertEquals('u.id IN(1, 2, 3)', (string) $this->_expr->in('u.id', array(1, 2, 3))); + } + + public function testInLiteralExpr() + { + $this->assertEquals("u.type IN('foo', 'bar')", (string) $this->_expr->in('u.type', array('foo', 'bar'))); + } + + public function testNotInExpr() + { + $this->assertEquals('u.id NOT IN(1, 2, 3)', (string) $this->_expr->notIn('u.id', array(1, 2, 3))); + } + + public function testNotInLiteralExpr() + { + $this->assertEquals("u.type NOT IN('foo', 'bar')", (string) $this->_expr->notIn('u.type', array('foo', 'bar'))); + } + + public function testAndxOrxExpr() + { + $andExpr = $this->_expr->andx(); + $andExpr->add($this->_expr->eq(1, 1)); + $andExpr->add($this->_expr->lt(1, 5)); + + $orExpr = $this->_expr->orx(); + $orExpr->add($andExpr); + $orExpr->add($this->_expr->eq(1, 1)); + + $this->assertEquals('(1 = 1 AND 1 < 5) OR 1 = 1', (string) $orExpr); + } + + public function testOrxExpr() + { + $orExpr = $this->_expr->orx(); + $orExpr->add($this->_expr->eq(1, 1)); + $orExpr->add($this->_expr->lt(1, 5)); + + $this->assertEquals('1 = 1 OR 1 < 5', (string) $orExpr); + } + + public function testOrderByCountExpr() + { + $orderExpr = $this->_expr->desc('u.username'); + + $this->assertEquals($orderExpr->count(), 1); + $this->assertEquals('u.username DESC', (string) $orderExpr); + } + + public function testOrderByOrder() + { + $orderExpr = $this->_expr->desc('u.username'); + $this->assertEquals('u.username DESC', (string) $orderExpr); + } + + public function testOrderByAsc() + { + $orderExpr = $this->_expr->asc('u.username'); + $this->assertEquals('u.username ASC', (string) $orderExpr); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testAddThrowsException() + { + $orExpr = $this->_expr->orx(); + $orExpr->add($this->_expr->quot(5, 2)); + } + + /** + * @group DDC-1683 + */ + public function testBooleanLiteral() + { + $this->assertEquals('true', $this->_expr->literal(true)); + $this->assertEquals('false', $this->_expr->literal(false)); + } + + + /** + * @group DDC-1686 + */ + public function testExpressionGetter() + { + + // Andx + $andx = new Expr\Andx(array('1 = 1', '2 = 2')); + $this->assertEquals(array('1 = 1', '2 = 2'), $andx->getParts()); + + // Comparison + $comparison = new Expr\Comparison('foo', Expr\Comparison::EQ, 'bar'); + $this->assertEquals('foo', $comparison->getLeftExpr()); + $this->assertEquals('bar', $comparison->getRightExpr()); + $this->assertEquals(Expr\Comparison::EQ, $comparison->getOperator()); + + // From + $from = new Expr\From('Foo', 'f', 'f.id'); + $this->assertEquals('f', $from->getAlias()); + $this->assertEquals('Foo', $from->getFrom()); + $this->assertEquals('f.id', $from->getIndexBy()); + + // Func + $func = new Expr\Func('MAX', array('f.id')); + $this->assertEquals('MAX', $func->getName()); + $this->assertEquals(array('f.id'), $func->getArguments()); + + // GroupBy + $group = new Expr\GroupBy(array('foo DESC', 'bar ASC')); + $this->assertEquals(array('foo DESC', 'bar ASC'), $group->getParts()); + + // Join + $join = new Expr\Join(Expr\Join::INNER_JOIN, 'f.bar', 'b', Expr\Join::ON, 'b.bar_id = 1', 'b.bar_id'); + $this->assertEquals(Expr\Join::INNER_JOIN, $join->getJoinType()); + $this->assertEquals(Expr\Join::ON, $join->getConditionType()); + $this->assertEquals('b.bar_id = 1', $join->getCondition()); + $this->assertEquals('b.bar_id', $join->getIndexBy()); + $this->assertEquals('f.bar', $join->getJoin()); + $this->assertEquals('b', $join->getAlias()); + + // Literal + $literal = new Expr\Literal(array('foo')); + $this->assertEquals(array('foo'), $literal->getParts()); + + // Math + $math = new Expr\Math(10, '+', 20); + $this->assertEquals(10, $math->getLeftExpr()); + $this->assertEquals(20, $math->getRightExpr()); + $this->assertEquals('+', $math->getOperator()); + + // OrderBy + $order = new Expr\OrderBy('foo', 'DESC'); + $this->assertEquals(array('foo DESC'), $order->getParts()); + + // Andx + $orx = new Expr\Orx(array('foo = 1', 'bar = 2')); + $this->assertEquals(array('foo = 1', 'bar = 2'), $orx->getParts()); + + // Select + $select = new Expr\Select(array('foo', 'bar')); + $this->assertEquals(array('foo', 'bar'), $select->getParts()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php new file mode 100644 index 0000000..1f0445c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php @@ -0,0 +1,606 @@ +_em = $this->_getTestEntityManager(); + } + + public function assertValidDQL($dql, $debug = false) + { + try { + $parserResult = $this->parseDql($dql); + } catch (QueryException $e) { + if ($debug) { + echo $e->getTraceAsString() . PHP_EOL; + } + + $this->fail($e->getMessage()); + } + } + + public function assertInvalidDQL($dql, $debug = false) + { + try { + $parserResult = $this->parseDql($dql); + + $this->fail('No syntax errors were detected, when syntax errors were expected'); + } catch (QueryException $e) { + if ($debug) { + echo $e->getMessage() . PHP_EOL; + echo $e->getTraceAsString() . PHP_EOL; + } + } + } + + public function parseDql($dql, $hints = array()) + { + $query = $this->_em->createQuery($dql); + $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); + $query->setDql($dql); + + foreach ($hints as $key => $value) { + $query->setHint($key, $value); + } + + $parser = new \Doctrine\ORM\Query\Parser($query); + + // We do NOT test SQL output here. That only unnecessarily slows down the tests! + $parser->setCustomOutputTreeWalker('Doctrine\Tests\Mocks\MockTreeWalker'); + + return $parser->parse(); + } + + public function testEmptyQueryString() + { + $this->assertInvalidDQL(''); + } + + public function testPlainFromClauseWithAlias() + { + $this->assertValidDQL('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testSelectSingleComponentWithAsterisk() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testSelectSingleComponentWithMultipleColumns() + { + $this->assertValidDQL('SELECT u.name, u.username FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testSelectMultipleComponentsUsingMultipleFrom() + { + $this->assertValidDQL('SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE u = p.user'); + } + + public function testSelectMultipleComponentsWithAsterisk() + { + $this->assertValidDQL('SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.phonenumbers p'); + } + + public function testSelectDistinctIsSupported() + { + $this->assertValidDQL('SELECT DISTINCT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testAggregateFunctionInSelect() + { + $this->assertValidDQL('SELECT COUNT(u.id) FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testDuplicatedAliasInAggregateFunction() + { + $this->assertInvalidDQL('SELECT COUNT(u.id) AS num, SUM(u.id) AS num FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testAggregateFunctionWithDistinctInSelect() + { + $this->assertValidDQL('SELECT COUNT(DISTINCT u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testFunctionalExpressionsSupportedInWherePart() + { + $this->assertValidDQL("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(u.name) = 'someone'"); + } + + public function testArithmeticExpressionsSupportedInWherePart() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000'); + } + + public function testInExpressionSupportedInWherePart() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN (1, 2)'); + } + + public function testInExpressionWithoutSpacesSupportedInWherePart() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN (1,2,3)'); + } + + public function testNotInExpressionSupportedInWherePart() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN (1)'); + } + + public function testInExpressionWithSingleValuedAssociationPathExpression() + { + $this->assertValidDQL("SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.avatar IN (?1, ?2)"); + } + + public function testInvalidInExpressionWithCollectionValuedAssociationPathExpression() + { + $this->assertInvalidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.phonenumbers IN (?1, ?2)"); + } + + public function testInstanceOfExpressionSupportedInWherePart() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyEmployee'); + } + + public function testInstanceOfExpressionWithInputParamSupportedInWherePart() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1'); + } + + public function testNotInstanceOfExpressionSupportedInWherePart() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u NOT INSTANCE OF ?1'); + } + + public function testExistsExpressionSupportedInWherePart() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE EXISTS (SELECT p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234)'); + } + + public function testNotExistsExpressionSupportedInWherePart() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT EXISTS (SELECT p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234)'); + } + + public function testAggregateFunctionInHavingClause() + { + $this->assertValidDQL('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p HAVING COUNT(p.phonenumber) > 2'); + $this->assertValidDQL("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p HAVING MAX(u.name) = 'romanb'"); + } + + public function testLeftJoin() + { + $this->assertValidDQL('SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p'); + } + + public function testJoin() + { + $this->assertValidDQL('SELECT u,p FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.phonenumbers p'); + } + + public function testInnerJoin() + { + $this->assertValidDQL('SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.phonenumbers p'); + } + + public function testMultipleLeftJoin() + { + $this->assertValidDQL('SELECT u, a, p FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a LEFT JOIN u.phonenumbers p'); + } + + public function testMultipleInnerJoin() + { + $this->assertValidDQL('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a INNER JOIN u.phonenumbers p'); + } + + public function testMixingOfJoins() + { + $this->assertValidDQL('SELECT u.name, a.topic, p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a LEFT JOIN u.phonenumbers p'); + } + + public function testJoinClassPath() + { + $this->assertValidDQL('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN Doctrine\Tests\Models\CMS\CmsArticle a WITH a.user = u.id'); + } + + public function testOrderBySingleColumn() + { + $this->assertValidDQL('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.name'); + } + + public function testOrderBySingleColumnAscending() + { + $this->assertValidDQL('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.name ASC'); + } + + public function testOrderBySingleColumnDescending() + { + $this->assertValidDQL('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.name DESC'); + } + + public function testOrderByMultipleColumns() + { + $this->assertValidDQL('SELECT u.name, u.username FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username DESC, u.name DESC'); + } + + public function testSubselectInInExpression() + { + $this->assertValidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = 'zYne')"); + } + + public function testSubselectInSelectPart() + { + $this->assertValidDQL("SELECT u.name, (SELECT COUNT(p.phonenumber) FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234) pcount FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'"); + } + + public function testArithmeticExpressionInSelectPart() + { + $this->assertValidDQL("SELECT SUM(u.id) / COUNT(u.id) FROM Doctrine\Tests\Models\CMS\CmsUser u"); + } + + public function testArithmeticExpressionInSubselectPart() + { + $this->assertValidDQL("SELECT (SELECT SUM(u.id) / COUNT(u.id) FROM Doctrine\Tests\Models\CMS\CmsUser u2) value FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'"); + } + + public function testArithmeticExpressionWithParenthesisInSubselectPart() + { + $this->assertValidDQL("SELECT (SELECT (SUM(u.id) / COUNT(u.id)) FROM Doctrine\Tests\Models\CMS\CmsUser u2) value FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'"); + } + + /** + * @group DDC-1079 + */ + public function testSelectLiteralInSubselect() + { + $this->assertValidDQL('SELECT (SELECT 1 FROM Doctrine\Tests\Models\CMS\CmsUser u2) value FROM Doctrine\Tests\Models\CMS\CmsUser u'); + $this->assertValidDQL('SELECT (SELECT 0 FROM Doctrine\Tests\Models\CMS\CmsUser u2) value FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + /** + * @group DDC-1077 + */ + public function testConstantValueInSelect() + { + $this->assertValidDQL("SELECT u.name, 'foo' AS bar FROM Doctrine\Tests\Models\CMS\CmsUser u", true); + } + + public function testDuplicateAliasInSubselectPart() + { + $this->assertInvalidDQL("SELECT (SELECT SUM(u.id) / COUNT(u.id) AS foo FROM Doctrine\Tests\Models\CMS\CmsUser u2) foo FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'"); + } + + public function testPositionalInputParameter() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1'); + } + + public function testNamedInputParameter() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :id'); + } + + public function testJoinConditionOverrideNotSupported() + { + $this->assertInvalidDQL("SELECT u.name, p FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p ON p.phonenumber = '123 123'"); + } + + public function testIndexByClauseWithOneComponent() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id'); + } + + public function testIndexBySupportsJoins() + { + $this->assertValidDQL('SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a INDEX BY a.id'); // INDEX BY is now referring to articles + } + + public function testIndexBySupportsJoins2() + { + $this->assertValidDQL('SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id LEFT JOIN u.phonenumbers p INDEX BY p.phonenumber'); + } + + public function testBetweenExpressionSupported() + { + $this->assertValidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name BETWEEN 'jepso' AND 'zYne'"); + } + + public function testNotBetweenExpressionSupported() + { + $this->assertValidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name NOT BETWEEN 'jepso' AND 'zYne'"); + } + + public function testLikeExpression() + { + $this->assertValidDQL("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name LIKE 'z%'"); + } + + public function testNotLikeExpression() + { + $this->assertValidDQL("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name NOT LIKE 'z%'"); + } + + public function testLikeExpressionWithCustomEscapeCharacter() + { + $this->assertValidDQL("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name LIKE 'z|%' ESCAPE '|'"); + } + + public function testFieldComparisonWithoutAlias() + { + $this->assertInvalidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE id = 1"); + } + + public function testDuplicatedAliasDeclaration() + { + $this->assertInvalidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles u WHERE u.id = 1"); + } + + public function testImplicitJoinInWhereOnSingleValuedAssociationPathExpression() + { + // This should be allowed because avatar is a single-value association. + // SQL: SELECT ... FROM forum_user fu INNER JOIN forum_avatar fa ON fu.avatar_id = fa.id WHERE fa.id = ? + $this->assertValidDQL("SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u JOIN u.avatar a WHERE a.id = ?1"); + } + + public function testImplicitJoinInWhereOnCollectionValuedPathExpression() + { + // This should be forbidden, because articles is a collection + $this->assertInvalidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles a WHERE a.title = ?"); + } + + public function testInvalidSyntaxIsRejected() + { + $this->assertInvalidDQL("FOOBAR CmsUser"); + $this->assertInvalidDQL("DELETE FROM Doctrine\Tests\Models\CMS\CmsUser.articles"); + $this->assertInvalidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles.comments"); + + // Currently UNDEFINED OFFSET error + $this->assertInvalidDQL("SELECT c FROM CmsUser.articles.comments c"); + } + + public function testUpdateWorksWithOneField() + { + $this->assertValidDQL("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = 'someone'"); + } + + public function testUpdateWorksWithMultipleFields() + { + $this->assertValidDQL("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = 'someone', u.username = 'some'"); + } + + public function testUpdateSupportsConditions() + { + $this->assertValidDQL("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = 'someone' WHERE u.id = 5"); + } + + public function testDeleteAll() + { + $this->assertValidDQL('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testDeleteWithCondition() + { + $this->assertValidDQL('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = 3'); + } + + /** + * The main use case for this generalized style of join is when a join condition + * does not involve a foreign key relationship that is mapped to an entity relationship. + */ + public function testImplicitJoinWithCartesianProductAndConditionInWhere() + { + $this->assertValidDQL("SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a WHERE u.name = a.topic"); + } + + public function testAllExpressionWithCorrelatedSubquery() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > ALL (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = u.name)'); + } + + public function testCustomJoinsAndWithKeywordSupported() + { + $this->assertValidDQL('SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.phonenumbers p WITH p.phonenumber = 123 WHERE u.id = 1'); + } + + public function testAnyExpressionWithCorrelatedSubquery() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > ANY (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = u.name)'); + } + + public function testSomeExpressionWithCorrelatedSubquery() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > SOME (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = u.name)'); + } + + public function testArithmeticExpressionWithoutParenthesisInWhereClause() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE SIZE(u.phonenumbers) + 1 > 10'); + } + + public function testMemberOfExpression() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers'); + //$this->assertValidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE 'Joe' MEMBER OF u.nicknames"); + } + + public function testSizeFunction() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE SIZE(u.phonenumbers) > 1'); + } + + public function testEmptyCollectionComparisonExpression() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.phonenumbers IS EMPTY'); + } + + public function testSingleValuedAssociationFieldInWhere() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address = ?1'); + $this->assertValidDQL('SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user = ?1'); + } + + public function testBooleanLiteralInWhere() + { + $this->assertValidDQL('SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = true'); + } + + public function testSubqueryInSelectExpression() + { + $this->assertValidDQL('select u, (select max(p.phonenumber) from Doctrine\Tests\Models\CMS\CmsPhonenumber p) maxId from Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testUsageOfQComponentOutsideSubquery() + { + $this->assertInvalidDQL('select u, (select max(p.phonenumber) from Doctrine\Tests\Models\CMS\CmsPhonenumber p) maxId from Doctrine\Tests\Models\CMS\CmsUser u WHERE p.user = ?1'); + } + + public function testUnknownAbstractSchemaName() + { + $this->assertInvalidDQL('SELECT u FROM UnknownClassName u'); + } + + public function testCorrectPartialObjectLoad() + { + $this->assertValidDQL('SELECT PARTIAL u.{id,name} FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testIncorrectPartialObjectLoadBecauseOfMissingIdentifier() + { + $this->assertInvalidDQL('SELECT PARTIAL u.{name} FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testScalarExpressionInSelect() + { + $this->assertValidDQL('SELECT u, 42 + u.id AS someNumber FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testInputParameterInSelect() + { + $this->assertValidDQL('SELECT u, u.id + ?1 AS someNumber FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + /** + * @group DDC-1091 + */ + public function testCustomFunctionsReturningStringInStringPrimary() + { + $this->_em->getConfiguration()->addCustomStringFunction('CC', 'Doctrine\ORM\Query\AST\Functions\ConcatFunction'); + + $this->assertValidDQL("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CC('%', u.name) LIKE '%foo%'", true); + } + + /** + * @group DDC-505 + */ + public function testDQLKeywordInJoinIsAllowed() + { + $this->assertValidDQL('SELECT u FROM ' . __NAMESPACE__ . '\DQLKeywordsModelUser u JOIN u.group g'); + } + + /** + * @group DDC-505 + */ + public function testDQLKeywordInConditionIsAllowed() + { + $this->assertValidDQL('SELECT g FROM ' . __NAMESPACE__ . '\DQLKeywordsModelGroup g WHERE g.from=0'); + } + + /* The exception is currently thrown in the SQLWalker, not earlier. + public function testInverseSideSingleValuedAssociationPathNotAllowed() + { + $this->assertInvalidDQL('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address = ?1'); + } + */ + + /** + * @group DDC-617 + */ + public function testSelectOnlyNonRootEntityAlias() + { + $this->assertInvalidDQL('SELECT g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g'); + } + + /** + * @group DDC-1108 + */ + public function testInputParameterSingleChar() + { + $this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = :q'); + } + + /** + * @group DDC-1053 + */ + public function testGroupBy() + { + $this->assertValidDQL('SELECT g.id, count(u.id) FROM Doctrine\Tests\Models\CMS\CmsGroup g JOIN g.users u GROUP BY g.id'); + } + + /** + * @group DDC-1053 + */ + public function testGroupByIdentificationVariable() + { + $this->assertValidDQL('SELECT g, count(u.id) FROM Doctrine\Tests\Models\CMS\CmsGroup g JOIN g.users u GROUP BY g'); + } + + /** + * @group DDC-1053 + */ + public function testGroupByUnknownIdentificationVariable() + { + $this->assertInvalidDQL('SELECT g, count(u.id) FROM Doctrine\Tests\Models\CMS\CmsGroup g JOIN g.users u GROUP BY m'); + } + + /** + * @group DDC-117 + */ + public function testSizeOfForeignKeyOneToManyPrimaryKeyEntity() + { + $this->assertValidDQL("SELECT a, t FROM Doctrine\Tests\Models\DDC117\DDC117Article a JOIN a.translations t WHERE SIZE(a.translations) > 0"); + } + + /** + * @group DDC-117 + */ + public function testSizeOfForeignKeyManyToManyPrimaryKeyEntity() + { + $this->assertValidDQL("SELECT e, t FROM Doctrine\Tests\Models\DDC117\DDC117Editor e JOIN e.reviewingTranslations t WHERE SIZE(e.reviewingTranslations) > 0"); + } + + public function testCaseSupportContainingNullIfExpression() + { + $this->assertValidDQL("SELECT u.id, NULLIF(u.name, u.name) AS shouldBeNull FROM Doctrine\Tests\Models\CMS\CmsUser u"); + } + + public function testCaseSupportContainingCoalesceExpression() + { + $this->assertValidDQL("select COALESCE(NULLIF(u.name, ''), u.username) as Display FROM Doctrine\Tests\Models\CMS\CmsUser u"); + } +} + +/** @Entity */ +class DQLKeywordsModelUser +{ + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; + /** @OneToOne(targetEntity="DQLKeywordsModelGroup") */ + private $group; +} + +/** @Entity */ +class DQLKeywordsModelGroup +{ + /** @Id @Column(type="integer") @GeneratedValue */ + private $id; + /** @Column */ + private $from; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/LexerTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/LexerTest.php new file mode 100644 index 0000000..29bba4b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/LexerTest.php @@ -0,0 +1,234 @@ +moveNext(); + $token = $lexer->lookahead; + + $this->assertEquals(Lexer::T_IDENTIFIER, $token['type']); + $this->assertEquals('u', $token['value']); + } + + public function testScannerRecognizesIdentifierConsistingOfLetters() + { + $lexer = new Lexer('someIdentifier'); + + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_IDENTIFIER, $token['type']); + $this->assertEquals('someIdentifier', $token['value']); + } + + public function testScannerRecognizesIdentifierIncludingDigits() + { + $lexer = new Lexer('s0m31d3nt1f13r'); + + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_IDENTIFIER, $token['type']); + $this->assertEquals('s0m31d3nt1f13r', $token['value']); + } + + public function testScannerRecognizesIdentifierIncludingUnderscore() + { + $lexer = new Lexer('some_identifier'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_IDENTIFIER, $token['type']); + $this->assertEquals('some_identifier', $token['value']); + } + + public function testScannerRecognizesDecimalInteger() + { + $lexer = new Lexer('1234'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_INTEGER, $token['type']); + $this->assertEquals(1234, $token['value']); + } + + public function testScannerRecognizesFloat() + { + $lexer = new Lexer('1.234'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_FLOAT, $token['type']); + $this->assertEquals(1.234, $token['value']); + } + + public function testScannerRecognizesFloatWithExponent() + { + $lexer = new Lexer('1.2e3'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_FLOAT, $token['type']); + $this->assertEquals(1.2e3, $token['value']); + } + + public function testScannerRecognizesFloatWithExponent2() + { + $lexer = new Lexer('0.2e3'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_FLOAT, $token['type']); + $this->assertEquals(.2e3, $token['value']); + } + + public function testScannerRecognizesFloatWithNegativeExponent() + { + $lexer = new Lexer('7E-10'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_FLOAT, $token['type']); + $this->assertEquals(7E-10, $token['value']); + } + + public function testScannerRecognizesFloatBig() + { + $lexer = new Lexer('123456789.01'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_FLOAT, $token['type']); + $this->assertEquals(1.2345678901e8, $token['value']); + } + + public function testScannerRecognizesFloatContainingWhitespace() + { + $lexer = new Lexer('- 1.234e2'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_MINUS, $token['type']); + $this->assertEquals('-', $token['value']); + + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_FLOAT, $token['type']); + $this->assertNotEquals(-1.234e2, $token['value']); + $this->assertEquals(1.234e2, $token['value']); + } + + public function testScannerRecognizesStringContainingWhitespace() + { + $lexer = new Lexer("'This is a string.'"); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_STRING, $token['type']); + $this->assertEquals("This is a string.", $token['value']); + } + + public function testScannerRecognizesStringContainingSingleQuotes() + { + $lexer = new Lexer("'abc''defg'''"); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_STRING, $token['type']); + $this->assertEquals("abc'defg'", $token['value']); + } + + public function testScannerRecognizesInputParameter() + { + $lexer = new Lexer('?1'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_INPUT_PARAMETER, $token['type']); + $this->assertEquals('?1', $token['value']); + } + + public function testScannerRecognizesNamedInputParameter() + { + $lexer = new Lexer(':name'); + $lexer->moveNext(); + $token = $lexer->lookahead; + $this->assertEquals(Lexer::T_INPUT_PARAMETER, $token['type']); + $this->assertEquals(':name', $token['value']); + } + + public function testScannerTokenizesASimpleQueryCorrectly() + { + $dql = "SELECT u FROM My\Namespace\User u WHERE u.name = 'Jack O''Neil'"; + $lexer = new Lexer($dql); + + $tokens = array( + array( + 'value' => 'SELECT', + 'type' => Lexer::T_SELECT, + 'position' => 0 + ), + array( + 'value' => 'u', + 'type' => Lexer::T_IDENTIFIER, + 'position' => 7 + ), + array( + 'value' => 'FROM', + 'type' => Lexer::T_FROM, + 'position' => 9 + ), + array( + 'value' => 'My\Namespace\User', + 'type' => Lexer::T_IDENTIFIER, + 'position' => 14 + ), + array( + 'value' => 'u', + 'type' => Lexer::T_IDENTIFIER, + 'position' => 32 + ), + array( + 'value' => 'WHERE', + 'type' => Lexer::T_WHERE, + 'position' => 34 + ), + array( + 'value' => 'u', + 'type' => Lexer::T_IDENTIFIER, + 'position' => 40 + ), + array( + 'value' => '.', + 'type' => Lexer::T_DOT, + 'position' => 41 + ), + array( + 'value' => 'name', + 'type' => Lexer::T_IDENTIFIER, + 'position' => 42 + ), + array( + 'value' => '=', + 'type' => Lexer::T_EQUALS, + 'position' => 47 + ), + array( + 'value' => "Jack O'Neil", + 'type' => Lexer::T_STRING, + 'position' => 49 + ) + ); + + foreach ($tokens as $expected) { + $lexer->moveNext(); + $actual = $lexer->lookahead; + $this->assertEquals($expected['value'], $actual['value']); + $this->assertEquals($expected['type'], $actual['type']); + $this->assertEquals($expected['position'], $actual['position']); + } + + $this->assertFalse($lexer->moveNext()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ParameterTypeInfererTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ParameterTypeInfererTest.php new file mode 100644 index 0000000..60b1185 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ParameterTypeInfererTest.php @@ -0,0 +1,53 @@ +. + */ +namespace Doctrine\Tests\ORM\Query; + +use Doctrine\ORM\Query\ParameterTypeInferer; +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Types\Type; +use PDO; + +require_once __DIR__ . '/../../TestInit.php'; + +class ParameterTypeInfererTest extends \Doctrine\Tests\OrmTestCase +{ + + public function providerParameterTypeInferer() + { + return array( + array(1, Type::INTEGER), + array("bar", PDO::PARAM_STR), + array("1", PDO::PARAM_STR), + array(new \DateTime, Type::DATETIME), + array(array(2), Connection::PARAM_INT_ARRAY), + array(array("foo"), Connection::PARAM_STR_ARRAY), + array(array("1","2"), Connection::PARAM_STR_ARRAY), + array(array(), Connection::PARAM_STR_ARRAY), + ); + } + + /** + * @dataProvider providerParameterTypeInferer + */ + + public function testParameterTypeInferer($value, $expected) + { + $this->assertEquals($expected, ParameterTypeInferer::inferType($value)); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ParserResultTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ParserResultTest.php new file mode 100644 index 0000000..64f3afb --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/ParserResultTest.php @@ -0,0 +1,48 @@ +parserResult = new ParserResult(); + } + + public function testGetRsm() + { + $this->assertInstanceOf( + 'Doctrine\ORM\Query\ResultSetMapping', + $this->parserResult->getResultSetMapping() + ); + } + + public function testSetGetSqlExecutor() + { + $this->assertNull($this->parserResult->getSqlExecutor()); + + $executor = $this->getMock('Doctrine\ORM\Query\Exec\AbstractSqlExecutor', array('execute')); + $this->parserResult->setSqlExecutor($executor); + $this->assertSame($executor, $this->parserResult->getSqlExecutor()); + } + + public function testGetSqlParameterPosition() + { + $this->parserResult->addParameterMapping(1, 1); + $this->parserResult->addParameterMapping(1, 2); + $this->assertEquals(array(1, 2), $this->parserResult->getSqlParameterPositions(1)); + } + + public function testGetParameterMappings() + { + $this->assertInternalType('array', $this->parserResult->getParameterMappings()); + + $this->parserResult->addParameterMapping(1, 1); + $this->parserResult->addParameterMapping(1, 2); + $this->assertEquals(array(1 => array(1, 2)), $this->parserResult->getParameterMappings()); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/QueryTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/QueryTest.php new file mode 100644 index 0000000..de160d0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/QueryTest.php @@ -0,0 +1,166 @@ +_em = $this->_getTestEntityManager(); + } + + public function testGetParameters() + { + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1"); + + $parameters = new ArrayCollection(); + + $this->assertEquals($parameters, $query->getParameters()); + } + + public function testGetParameters_HasSomeAlready() + { + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1"); + $query->setParameter(2, 84); + + $parameters = new ArrayCollection(); + $parameters->add(new Parameter(2, 84)); + + $this->assertEquals($parameters, $query->getParameters()); + } + + public function testSetParameters() + { + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1"); + + $parameters = new ArrayCollection(); + $parameters->add(new Parameter(1, 'foo')); + $parameters->add(new Parameter(2, 'bar')); + + $query->setParameters($parameters); + + $this->assertEquals($parameters, $query->getParameters()); + } + + public function testFree() + { + $query = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1"); + $query->setParameter(2, 84, \PDO::PARAM_INT); + + $query->free(); + + $this->assertEquals(0, count($query->getParameters())); + } + + public function testClone() + { + $dql = "select u from Doctrine\Tests\Models\CMS\CmsUser u where u.username = ?1"; + + $query = $this->_em->createQuery($dql); + $query->setParameter(2, 84, \PDO::PARAM_INT); + $query->setHint('foo', 'bar'); + + $cloned = clone $query; + + $this->assertEquals($dql, $cloned->getDql()); + $this->assertEquals(0, count($cloned->getParameters())); + $this->assertFalse($cloned->getHint('foo')); + } + + public function testFluentQueryInterface() + { + $q = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a"); + $q2 = $q->expireQueryCache(true) + ->setQueryCacheLifetime(3600) + ->setQueryCacheDriver(null) + ->expireResultCache(true) + ->setHint('foo', 'bar') + ->setHint('bar', 'baz') + ->setParameter(1, 'bar') + ->setParameters(new ArrayCollection(array(new Parameter(2, 'baz')))) + ->setResultCacheDriver(null) + ->setResultCacheId('foo') + ->setDql('foo') + ->setFirstResult(10) + ->setMaxResults(10); + + $this->assertSame($q2, $q); + } + + /** + * @group DDC-968 + */ + public function testHints() + { + $q = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a"); + $q->setHint('foo', 'bar')->setHint('bar', 'baz'); + + $this->assertEquals('bar', $q->getHint('foo')); + $this->assertEquals('baz', $q->getHint('bar')); + $this->assertEquals(array('foo' => 'bar', 'bar' => 'baz'), $q->getHints()); + } + + /** + * @group DDC-1588 + */ + public function testQueryDefaultResultCache() + { + $this->_em->getConfiguration()->setResultCacheImpl(new ArrayCache()); + $q = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a"); + $q->useResultCache(true); + $this->assertSame($this->_em->getConfiguration()->getResultCacheImpl(), $q->getQueryCacheProfile()->getResultCacheDriver()); + } + + /** + * @expectedException Doctrine\ORM\Query\QueryException + **/ + public function testIterateWithNoDistinctAndWrongSelectClause() + { + $q = $this->_em->createQuery("select u, a from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a"); + $q->iterate(); + } + + /** + * @expectedException Doctrine\ORM\Query\QueryException + **/ + public function testIterateWithNoDistinctAndWithValidSelectClause() + { + $q = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a"); + $q->iterate(); + } + + public function testIterateWithDistinct() + { + $q = $this->_em->createQuery("SELECT DISTINCT u from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a"); + $q->iterate(); + } + + /** + * @group DDC-1697 + */ + public function testCollectionParameters() + { + $cities = array( + 0 => "Paris", + 3 => "Canne", + 9 => "St Julien" + ); + + $query = $this->_em + ->createQuery("SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.city IN (:cities)") + ->setParameter('cities', $cities); + + $parameters = $query->getParameters(); + $parameter = $parameters->first(); + + $this->assertEquals('cities', $parameter->getName()); + $this->assertEquals($cities, $parameter->getValue()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php new file mode 100644 index 0000000..fa5b06d --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -0,0 +1,1794 @@ +_em = $this->_getTestEntityManager(); + } + + /** + * Assert a valid SQL generation. + * + * @param string $dqlToBeTested + * @param string $sqlToBeConfirmed + * @param array $queryHints + * @param array $queryParams + */ + public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed, array $queryHints = array(), array $queryParams = array()) + { + try { + $query = $this->_em->createQuery($dqlToBeTested); + + foreach ($queryParams AS $name => $value) { + $query->setParameter($name, $value); + } + + $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true) + ->useQueryCache(false); + + foreach ($queryHints AS $name => $value) { + $query->setHint($name, $value); + } + + $sqlGenerated = $query->getSQL(); + + parent::assertEquals( + $sqlToBeConfirmed, + $sqlGenerated, + sprintf('"%s" is not equal of "%s"', $sqlGenerated, $sqlToBeConfirmed) + ); + + $query->free(); + } catch (\Exception $e) { + $this->fail($e->getMessage() ."\n".$e->getTraceAsString()); + } + } + + /** + * Asser an invalid SQL generation. + * + * @param string $dqlToBeTested + * @param string $expectedException + * @param array $queryHints + * @param array $queryParams + */ + public function assertInvalidSqlGeneration($dqlToBeTested, $expectedException, array $queryHints = array(), array $queryParams = array()) + { + $this->setExpectedException($expectedException); + + $query = $this->_em->createQuery($dqlToBeTested); + + foreach ($queryParams AS $name => $value) { + $query->setParameter($name, $value); + } + + $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true) + ->useQueryCache(false); + + foreach ($queryHints AS $name => $value) { + $query->setHint($name, $value); + } + + $sql = $query->getSql(); + $query->free(); + + // If we reached here, test failed + $this->fail($sql); + } + + + public function testSupportsSelectForAllFields() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_' + ); + } + + public function testSupportsSelectForOneField() + { + $this->assertSqlGeneration( + 'SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u', + 'SELECT c0_.id AS id0 FROM cms_users c0_' + ); + } + + public function testSupportsSelectForOneNestedField() + { + $this->assertSqlGeneration( + 'SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsArticle a JOIN a.user u', + 'SELECT c0_.id AS id0 FROM cms_articles c1_ INNER JOIN cms_users c0_ ON c1_.user_id = c0_.id' + ); + } + + public function testSupportsSelectForAllNestedField() + { + $this->assertSqlGeneration( + 'SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a JOIN a.user u ORDER BY u.name ASC', + 'SELECT c0_.id AS id0, c0_.topic AS topic1, c0_.text AS text2, c0_.version AS version3 FROM cms_articles c0_ INNER JOIN cms_users c1_ ON c0_.user_id = c1_.id ORDER BY c1_.name ASC' + ); + } + + public function testSupportsSelectForMultipleColumnsOfASingleComponent() + { + $this->assertSqlGeneration( + 'SELECT u.username, u.name FROM Doctrine\Tests\Models\CMS\CmsUser u', + 'SELECT c0_.username AS username0, c0_.name AS name1 FROM cms_users c0_' + ); + } + + public function testSupportsSelectUsingMultipleFromComponents() + { + $this->assertSqlGeneration( + 'SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE u = p.user', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c1_.phonenumber AS phonenumber4 FROM cms_users c0_, cms_phonenumbers c1_ WHERE c0_.id = c1_.user_id' + ); + } + + public function testSupportsJoinOnMultipleComponents() + { + $this->assertSqlGeneration( + 'SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN Doctrine\Tests\Models\CMS\CmsPhonenumber p WITH u = p.user', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c1_.phonenumber AS phonenumber4 FROM cms_users c0_ INNER JOIN cms_phonenumbers c1_ ON (c0_.id = c1_.user_id)' + ); + } + + public function testSupportsSelectWithCollectionAssociationJoin() + { + $this->assertSqlGeneration( + 'SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.phonenumbers p', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c1_.phonenumber AS phonenumber4 FROM cms_users c0_ INNER JOIN cms_phonenumbers c1_ ON c0_.id = c1_.user_id' + ); + } + + public function testSupportsSelectWithSingleValuedAssociationJoin() + { + $this->assertSqlGeneration( + 'SELECT u, a FROM Doctrine\Tests\Models\Forum\ForumUser u JOIN u.avatar a', + 'SELECT f0_.id AS id0, f0_.username AS username1, f1_.id AS id2 FROM forum_users f0_ INNER JOIN forum_avatars f1_ ON f0_.avatar_id = f1_.id' + ); + } + + public function testSelectCorrelatedSubqueryComplexMathematicalExpression() + { + $this->assertSqlGeneration( + 'SELECT (SELECT (count(p.phonenumber)+5)*10 FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p JOIN p.user ui WHERE ui.id = u.id) AS c FROM Doctrine\Tests\Models\CMS\CmsUser u', + 'SELECT (SELECT (count(c0_.phonenumber) + 5) * 10 AS sclr1 FROM cms_phonenumbers c0_ INNER JOIN cms_users c1_ ON c0_.user_id = c1_.id WHERE c1_.id = c2_.id) AS sclr0 FROM cms_users c2_' + ); + } + + public function testSelectComplexMathematicalExpression() + { + $this->assertSqlGeneration( + 'SELECT (count(p.phonenumber)+5)*10 FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p JOIN p.user ui WHERE ui.id = ?1', + 'SELECT (count(c0_.phonenumber) + 5) * 10 AS sclr0 FROM cms_phonenumbers c0_ INNER JOIN cms_users c1_ ON c0_.user_id = c1_.id WHERE c1_.id = ?' + ); + } + + /* NOT (YET?) SUPPORTED. + Can be supported if SimpleSelectExpresion supports SingleValuedPathExpression instead of StateFieldPathExpression. + + public function testSingleAssociationPathExpressionInSubselect() + { + $this->assertSqlGeneration( + 'SELECT (SELECT p.user FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user = u) user_id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1', + 'SELECT (SELECT c0_.user_id FROM cms_phonenumbers c0_ WHERE c0_.user_id = c1_.id) AS sclr0 FROM cms_users c1_ WHERE c1_.id = ?' + ); + }*/ + + /** + * @group DDC-1077 + */ + public function testConstantValueInSelect() + { + $this->assertSqlGeneration( + "SELECT u.name, 'foo' AS bar FROM Doctrine\Tests\Models\CMS\CmsUser u", + "SELECT c0_.name AS name0, 'foo' AS sclr1 FROM cms_users c0_" + ); + } + + public function testSupportsOrderByWithAscAsDefault() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u ORDER BY u.id', + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ ORDER BY f0_.id ASC' + ); + } + + public function testSupportsOrderByAsc() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u ORDER BY u.id asc', + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ ORDER BY f0_.id ASC' + ); + } + public function testSupportsOrderByDesc() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u ORDER BY u.id desc', + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ ORDER BY f0_.id DESC' + ); + } + + public function testSupportsSelectDistinct() + { + $this->assertSqlGeneration( + 'SELECT DISTINCT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u', + 'SELECT DISTINCT c0_.name AS name0 FROM cms_users c0_' + ); + } + + public function testSupportsAggregateFunctionInSelectedFields() + { + $this->assertSqlGeneration( + 'SELECT COUNT(u.id) FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id', + 'SELECT COUNT(c0_.id) AS sclr0 FROM cms_users c0_ GROUP BY c0_.id' + ); + } + + public function testSupportsAggregateFunctionWithSimpleArithmetic() + { + $this->assertSqlGeneration( + 'SELECT MAX(u.id + 4) * 2 FROM Doctrine\Tests\Models\CMS\CmsUser u', + 'SELECT MAX(c0_.id + 4) * 2 AS sclr0 FROM cms_users c0_' + ); + } + + public function testSupportsWhereClauseWithPositionalParameter() + { + $this->assertSqlGeneration( + 'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.id = ?1', + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.id = ?' + ); + } + + public function testSupportsWhereClauseWithNamedParameter() + { + $this->assertSqlGeneration( + 'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name', + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.username = ?' + ); + } + + public function testSupportsWhereAndClauseWithNamedParameters() + { + $this->assertSqlGeneration( + 'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name and u.username = :name2', + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.username = ? AND f0_.username = ?' + ); + } + + public function testSupportsCombinedWhereClauseWithNamedParameter() + { + $this->assertSqlGeneration( + 'select u from Doctrine\Tests\Models\Forum\ForumUser u where (u.username = :name OR u.username = :name2) AND u.id = :id', + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE (f0_.username = ? OR f0_.username = ?) AND f0_.id = ?' + ); + } + + public function testSupportsAggregateFunctionInASelectDistinct() + { + $this->assertSqlGeneration( + 'SELECT COUNT(DISTINCT u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u', + 'SELECT COUNT(DISTINCT c0_.name) AS sclr0 FROM cms_users c0_' + ); + } + + // Ticket #668 + public function testSupportsASqlKeywordInAStringLiteralParam() + { + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name LIKE '%foo OR bar%'", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE c0_.name LIKE '%foo OR bar%'" + ); + } + + public function testSupportsArithmeticExpressionsInWherePart() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (c0_.id + 5000) * c0_.id + 3 < 10000000' + ); + } + + public function testSupportsMultipleEntitiesInFromClause() + { + $this->assertSqlGeneration( + 'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a JOIN a.user u2 WHERE u.id = u2.id', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c1_.id AS id4, c1_.topic AS topic5, c1_.text AS text6, c1_.version AS version7 FROM cms_users c0_, cms_articles c1_ INNER JOIN cms_users c2_ ON c1_.user_id = c2_.id WHERE c0_.id = c2_.id' + ); + } + + public function testSupportsMultipleEntitiesInFromClauseUsingPathExpression() + { + $this->assertSqlGeneration( + 'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a WHERE u.id = a.user', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c1_.id AS id4, c1_.topic AS topic5, c1_.text AS text6, c1_.version AS version7 FROM cms_users c0_, cms_articles c1_ WHERE c0_.id = c1_.user_id' + ); + } + + public function testSupportsPlainJoinWithoutClause() + { + $this->assertSqlGeneration( + 'SELECT u.id, a.id from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a', + 'SELECT c0_.id AS id0, c1_.id AS id1 FROM cms_users c0_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id' + ); + $this->assertSqlGeneration( + 'SELECT u.id, a.id from Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles a', + 'SELECT c0_.id AS id0, c1_.id AS id1 FROM cms_users c0_ INNER JOIN cms_articles c1_ ON c0_.id = c1_.user_id' + ); + } + + /** + * @group DDC-135 + */ + public function testSupportsJoinAndWithClauseRestriction() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a WITH a.topic LIKE '%foo%'", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE '%foo%')" + ); + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a WITH a.topic LIKE '%foo%'", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ INNER JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE '%foo%')" + ); + } + + /** + * @group DDC-135 + * @group DDC-177 + */ + public function testJoinOnClause_NotYetSupported_ThrowsException() + { + $this->setExpectedException('Doctrine\ORM\Query\QueryException'); + + $sql = $this->_em->createQuery( + "SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a ON a.topic LIKE '%foo%'" + )->getSql(); + } + + public function testSupportsMultipleJoins() + { + $this->assertSqlGeneration( + 'SELECT u.id, a.id, p.phonenumber, c.id from Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles a JOIN u.phonenumbers p JOIN a.comments c', + 'SELECT c0_.id AS id0, c1_.id AS id1, c2_.phonenumber AS phonenumber2, c3_.id AS id3 FROM cms_users c0_ INNER JOIN cms_articles c1_ ON c0_.id = c1_.user_id INNER JOIN cms_phonenumbers c2_ ON c0_.id = c2_.user_id INNER JOIN cms_comments c3_ ON c1_.id = c3_.article_id' + ); + } + + public function testSupportsTrimFunction() + { + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(TRAILING ' ' FROM u.name) = 'someone'", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE TRIM(TRAILING ' ' FROM c0_.name) = 'someone'" + ); + } + + // Ticket 894 + public function testSupportsBetweenClauseWithPositionalParameters() + { + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id BETWEEN ?1 AND ?2", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE c0_.id BETWEEN ? AND ?" + ); + } + + /** + * @group DDC-1802 + */ + public function testSupportsNotBetweenForSizeFunction() + { + $this->assertSqlGeneration( + "SELECT m.name FROM Doctrine\Tests\Models\StockExchange\Market m WHERE SIZE(m.stocks) NOT BETWEEN ?1 AND ?2", + "SELECT e0_.name AS name0 FROM exchange_markets e0_ WHERE (SELECT COUNT(*) FROM exchange_stocks e1_ WHERE e1_.market_id = e0_.id) NOT BETWEEN ? AND ?" + ); + } + + public function testSupportsFunctionalExpressionsInWherePart() + { + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(u.name) = 'someone'", + // String quoting in the SQL usually depends on the database platform. + // This test works with a mock connection which uses ' for string quoting. + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE TRIM(c0_.name) = 'someone'" + ); + } + + public function testSupportsInstanceOfExpressionsInWherePart() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyEmployee", + "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')" + ); + } + + public function testSupportsInstanceOfExpressionInWherePartWithMultipleValues() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF (Doctrine\Tests\Models\Company\CompanyEmployee, \Doctrine\Tests\Models\Company\CompanyManager)", + "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee', 'manager')" + ); + } + + /** + * @group DDC-1194 + */ + public function testSupportsInstanceOfExpressionsInWherePartPrefixedSlash() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF \Doctrine\Tests\Models\Company\CompanyEmployee", + "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')" + ); + } + + /** + * @group DDC-1194 + */ + public function testSupportsInstanceOfExpressionsInWherePartWithUnrelatedClass() + { + $this->assertInvalidSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF \Doctrine\Tests\Models\CMS\CmsUser", + "Doctrine\ORM\Query\QueryException" + ); + } + + public function testSupportsInstanceOfExpressionsInWherePartInDeeperLevel() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\Company\CompanyEmployee u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyManager", + "SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c0_.discr AS discr5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id WHERE c0_.discr IN ('manager')" + ); + } + + public function testSupportsInstanceOfExpressionsInWherePartInDeepestLevel() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\Company\CompanyManager u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyManager", + "SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id WHERE c0_.discr IN ('manager')" + ); + } + + public function testSupportsInstanceOfExpressionsUsingInputParameterInWherePart() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1", + "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')", + array(), array(1 => $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee')) + ); + } + + // Ticket #973 + public function testSupportsSingleValuedInExpressionWithoutSpacesInWherePart() + { + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE IDENTITY(u.email) IN(46)", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE c0_.email_id IN (46)" + ); + } + + public function testSupportsMultipleValuedInExpressionInWherePart() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN (1, 2)', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id IN (1, 2)' + ); + } + + public function testSupportsNotInExpressionInWherePart() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :id NOT IN (1)', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE ? NOT IN (1)' + ); + } + + /** + * @group DDC-1802 + */ + public function testSupportsNotInExpressionForModFunction() + { + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE MOD(u.id, 5) NOT IN(1,3,4)", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE MOD(c0_.id, 5) NOT IN (1, 3, 4)" + ); + } + + public function testInExpressionWithSingleValuedAssociationPathExpressionInWherePart() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.avatar IN (?1, ?2)', + 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.avatar_id IN (?, ?)' + ); + } + + public function testInvalidInExpressionWithSingleValuedAssociationPathExpressionOnInverseSide() + { + // We do not support SingleValuedAssociationPathExpression on inverse side + $this->assertInvalidSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address IN (?1, ?2)", + "Doctrine\ORM\Query\QueryException" + ); + } + + public function testSupportsConcatFunctionForMysqlAndPostgresql() + { + $connMock = $this->_em->getConnection(); + $orgPlatform = $connMock->getDatabasePlatform(); + + $connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\MySqlPlatform); + $this->assertSqlGeneration( + "SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, 's') = ?1", + "SELECT c0_.id AS id0 FROM cms_users c0_ WHERE CONCAT(c0_.name, 's') = ?" + ); + $this->assertSqlGeneration( + "SELECT CONCAT(u.id, u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1", + "SELECT CONCAT(c0_.id, c0_.name) AS sclr0 FROM cms_users c0_ WHERE c0_.id = ?" + ); + + $connMock->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform); + $this->assertSqlGeneration( + "SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, 's') = ?1", + "SELECT c0_.id AS id0 FROM cms_users c0_ WHERE c0_.name || 's' = ?" + ); + $this->assertSqlGeneration( + "SELECT CONCAT(u.id, u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1", + "SELECT c0_.id || c0_.name AS sclr0 FROM cms_users c0_ WHERE c0_.id = ?" + ); + + $connMock->setDatabasePlatform($orgPlatform); + } + + public function testSupportsExistsExpressionInWherePartWithCorrelatedSubquery() + { + $this->assertSqlGeneration( + 'SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE EXISTS (SELECT p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = u.id)', + 'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT c1_.phonenumber FROM cms_phonenumbers c1_ WHERE c1_.phonenumber = c0_.id)' + ); + } + + /** + * @group DDC-593 + */ + public function testSubqueriesInComparisonExpression() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id >= (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = :name)) AND (u.id <= (SELECT u3.id FROM Doctrine\Tests\Models\CMS\CmsUser u3 WHERE u3.name = :name))', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (c0_.id >= (SELECT c1_.id FROM cms_users c1_ WHERE c1_.name = ?)) AND (c0_.id <= (SELECT c2_.id FROM cms_users c2_ WHERE c2_.name = ?))' + ); + } + + public function testSupportsMemberOfExpressionOneToMany() + { + // "Get all users who have $phone as a phonenumber." (*cough* doesnt really make sense...) + $q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers'); + $q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); + + $phone = new \Doctrine\Tests\Models\CMS\CmsPhonenumber; + $phone->phonenumber = 101; + $q->setParameter('param', $phone); + + $this->assertEquals( + 'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_phonenumbers c1_ WHERE c0_.id = c1_.user_id AND c1_.phonenumber = ?)', + $q->getSql() + ); + } + + public function testSupportsMemberOfExpressionManyToMany() + { + // "Get all users who are members of $group." + $q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups'); + $q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); + + $group = new \Doctrine\Tests\Models\CMS\CmsGroup; + $group->id = 101; + $q->setParameter('param', $group); + + $this->assertEquals( + 'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = ?)', + $q->getSql() + ); + } + + public function testSupportsMemberOfExpressionSelfReferencing() + { + // "Get all persons who have $person as a friend." + // Tough one: Many-many self-referencing ("friends") with class table inheritance + $q = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p WHERE :param MEMBER OF p.friends'); + $person = new \Doctrine\Tests\Models\Company\CompanyPerson; + $this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, array('id' => 101)); + $q->setParameter('param', $person); + $this->assertEquals( + 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c1_.car_id AS car_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id = ?)', + $q->getSql() + ); + } + + public function testSupportsMemberOfWithSingleValuedAssociation() + { + // Impossible example, but it illustrates the purpose + $q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.email MEMBER OF u.groups'); + + $this->assertEquals( + 'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = c0_.email_id)', + $q->getSql() + ); + } + + public function testSupportsMemberOfWithIdentificationVariable() + { + // Impossible example, but it illustrates the purpose + $q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u MEMBER OF u.groups'); + + $this->assertEquals( + 'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = c0_.id)', + $q->getSql() + ); + } + + public function testSupportsCurrentDateFunction() + { + $q = $this->_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime > current_date()'); + $q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); + $this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.col_datetime > CURRENT_DATE', $q->getSql()); + } + + public function testSupportsCurrentTimeFunction() + { + $q = $this->_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.time > current_time()'); + $q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); + $this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.col_time > CURRENT_TIME', $q->getSql()); + } + + public function testSupportsCurrentTimestampFunction() + { + $q = $this->_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime > current_timestamp()'); + $q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); + $this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.col_datetime > CURRENT_TIMESTAMP', $q->getSql()); + } + + public function testExistsExpressionInWhereCorrelatedSubqueryAssocCondition() + { + $this->assertSqlGeneration( + // DQL + // The result of this query consists of all employees whose spouses are also employees. + 'SELECT DISTINCT emp FROM Doctrine\Tests\Models\CMS\CmsEmployee emp + WHERE EXISTS ( + SELECT spouseEmp + FROM Doctrine\Tests\Models\CMS\CmsEmployee spouseEmp + WHERE spouseEmp = emp.spouse)', + // SQL + 'SELECT DISTINCT c0_.id AS id0, c0_.name AS name1 FROM cms_employees c0_' + . ' WHERE EXISTS (' + . 'SELECT c1_.id FROM cms_employees c1_ WHERE c1_.id = c0_.spouse_id' + . ')' + ); + } + + public function testExistsExpressionWithSimpleSelectReturningScalar() + { + $this->assertSqlGeneration( + // DQL + // The result of this query consists of all employees whose spouses are also employees. + 'SELECT DISTINCT emp FROM Doctrine\Tests\Models\CMS\CmsEmployee emp + WHERE EXISTS ( + SELECT 1 + FROM Doctrine\Tests\Models\CMS\CmsEmployee spouseEmp + WHERE spouseEmp = emp.spouse)', + // SQL + 'SELECT DISTINCT c0_.id AS id0, c0_.name AS name1 FROM cms_employees c0_' + . ' WHERE EXISTS (' + . 'SELECT 1 AS sclr2 FROM cms_employees c1_ WHERE c1_.id = c0_.spouse_id' + . ')' + ); + } + + public function testLimitFromQueryClass() + { + $q = $this->_em + ->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u') + ->setMaxResults(10); + + $this->assertEquals('SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ LIMIT 10', $q->getSql()); + } + + public function testLimitAndOffsetFromQueryClass() + { + $q = $this->_em + ->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u') + ->setMaxResults(10) + ->setFirstResult(0); + + $this->assertEquals('SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ LIMIT 10 OFFSET 0', $q->getSql()); + } + + public function testSizeFunction() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE SIZE(u.phonenumbers) > 1", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (SELECT COUNT(*) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) > 1" + ); + } + + public function testSizeFunctionSupportsManyToMany() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE SIZE(u.groups) > 1", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (SELECT COUNT(*) FROM cms_users_groups c1_ WHERE c1_.user_id = c0_.id) > 1" + ); + } + + public function testEmptyCollectionComparisonExpression() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.phonenumbers IS EMPTY", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (SELECT COUNT(*) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) = 0" + ); + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.phonenumbers IS NOT EMPTY", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (SELECT COUNT(*) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) > 0" + ); + } + + public function testNestedExpressions() + { + $this->assertSqlGeneration( + "select u from Doctrine\Tests\Models\CMS\CmsUser u where u.id > 10 and u.id < 42 and ((u.id * 2) > 5)", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id > 10 AND c0_.id < 42 AND (c0_.id * 2 > 5)" + ); + } + + public function testNestedExpressions2() + { + $this->assertSqlGeneration( + "select u from Doctrine\Tests\Models\CMS\CmsUser u where (u.id > 10) and (u.id < 42 and ((u.id * 2) > 5)) or u.id <> 42", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (c0_.id > 10) AND (c0_.id < 42 AND (c0_.id * 2 > 5)) OR c0_.id <> 42" + ); + } + + public function testNestedExpressions3() + { + $this->assertSqlGeneration( + "select u from Doctrine\Tests\Models\CMS\CmsUser u where (u.id > 10) and (u.id between 1 and 10 or u.id in (1, 2, 3, 4, 5))", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (c0_.id > 10) AND (c0_.id BETWEEN 1 AND 10 OR c0_.id IN (1, 2, 3, 4, 5))" + ); + } + + public function testOrderByCollectionAssociationSize() + { + $this->assertSqlGeneration( + "select u, size(u.articles) as numArticles from Doctrine\Tests\Models\CMS\CmsUser u order by numArticles", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, (SELECT COUNT(*) FROM cms_articles c1_ WHERE c1_.user_id = c0_.id) AS sclr4 FROM cms_users c0_ ORDER BY sclr4 ASC" + ); + } + + public function testOrderBySupportsSingleValuedPathExpressionOwningSide() + { + $this->assertSqlGeneration( + "select a from Doctrine\Tests\Models\CMS\CmsArticle a order by a.user", + "SELECT c0_.id AS id0, c0_.topic AS topic1, c0_.text AS text2, c0_.version AS version3 FROM cms_articles c0_ ORDER BY c0_.user_id ASC" + ); + } + + /** + * @expectedException Doctrine\ORM\Query\QueryException + */ + public function testOrderBySupportsSingleValuedPathExpressionInverseSide() + { + $q = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u order by u.address"); + $q->getSQL(); + } + + public function testBooleanLiteralInWhereOnSqlite() + { + $oldPlat = $this->_em->getConnection()->getDatabasePlatform(); + $this->_em->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\SqlitePlatform); + + $this->assertSqlGeneration( + "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = true", + "SELECT b0_.id AS id0, b0_.booleanField AS booleanField1 FROM boolean_model b0_ WHERE b0_.booleanField = 1" + ); + + $this->assertSqlGeneration( + "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = false", + "SELECT b0_.id AS id0, b0_.booleanField AS booleanField1 FROM boolean_model b0_ WHERE b0_.booleanField = 0" + ); + + $this->_em->getConnection()->setDatabasePlatform($oldPlat); + } + + public function testBooleanLiteralInWhereOnPostgres() + { + $oldPlat = $this->_em->getConnection()->getDatabasePlatform(); + $this->_em->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform); + + $this->assertSqlGeneration( + "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = true", + "SELECT b0_.id AS id0, b0_.booleanField AS booleanfield1 FROM boolean_model b0_ WHERE b0_.booleanField = true" + ); + + $this->assertSqlGeneration( + "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = false", + "SELECT b0_.id AS id0, b0_.booleanField AS booleanfield1 FROM boolean_model b0_ WHERE b0_.booleanField = false" + ); + + $this->_em->getConnection()->setDatabasePlatform($oldPlat); + } + + public function testSingleValuedAssociationFieldInWhere() + { + $this->assertSqlGeneration( + "SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user = ?1", + "SELECT c0_.phonenumber AS phonenumber0 FROM cms_phonenumbers c0_ WHERE c0_.user_id = ?" + ); + } + + public function testSingleValuedAssociationNullCheckOnOwningSide() + { + $this->assertSqlGeneration( + "SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.user IS NULL", + "SELECT c0_.id AS id0, c0_.country AS country1, c0_.zip AS zip2, c0_.city AS city3 FROM cms_addresses c0_ WHERE c0_.user_id IS NULL" + ); + } + + // Null check on inverse side has to happen through explicit JOIN. + // "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address IS NULL" + // where the CmsUser is the inverse side is not supported. + public function testSingleValuedAssociationNullCheckOnInverseSide() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.address a WHERE a.id IS NULL", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ LEFT JOIN cms_addresses c1_ ON c0_.id = c1_.user_id WHERE c1_.id IS NULL" + ); + } + + /** + * @group DDC-339 + * @group DDC-1572 + */ + public function testStringFunctionLikeExpression() + { + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE LOWER(u.name) LIKE '%foo OR bar%'", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE LOWER(c0_.name) LIKE '%foo OR bar%'" + ); + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE LOWER(u.name) LIKE :str", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE LOWER(c0_.name) LIKE ?" + ); + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(UPPER(u.name), '_moo') LIKE :str", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE UPPER(c0_.name) || '_moo' LIKE ?" + ); + + // DDC-1572 + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE UPPER(u.name) LIKE UPPER(:str)", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE UPPER(c0_.name) LIKE UPPER(?)" + ); + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE UPPER(LOWER(u.name)) LIKE UPPER(LOWER(:str))", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE UPPER(LOWER(c0_.name)) LIKE UPPER(LOWER(?))" + ); + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a WITH a.topic LIKE u.name", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE c0_.name)" + ); + } + + /** + * @group DDC-1802 + */ + public function testStringFunctionNotLikeExpression() + { + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE LOWER(u.name) NOT LIKE '%foo OR bar%'", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE LOWER(c0_.name) NOT LIKE '%foo OR bar%'" + ); + + $this->assertSqlGeneration( + "SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE UPPER(LOWER(u.name)) NOT LIKE UPPER(LOWER(:str))", + "SELECT c0_.name AS name0 FROM cms_users c0_ WHERE UPPER(LOWER(c0_.name)) NOT LIKE UPPER(LOWER(?))" + ); + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a WITH a.topic NOT LIKE u.name", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic NOT LIKE c0_.name)" + ); + } + + /** + * @group DDC-338 + */ + public function testOrderedCollectionFetchJoined() + { + $this->assertSqlGeneration( + "SELECT r, l FROM Doctrine\Tests\Models\Routing\RoutingRoute r JOIN r.legs l", + "SELECT r0_.id AS id0, r1_.id AS id1, r1_.departureDate AS departureDate2, r1_.arrivalDate AS arrivalDate3 FROM RoutingRoute r0_ INNER JOIN RoutingRouteLegs r2_ ON r0_.id = r2_.route_id INNER JOIN RoutingLeg r1_ ON r1_.id = r2_.leg_id ". + "ORDER BY r1_.departureDate ASC" + ); + } + + public function testSubselectInSelect() + { + $this->assertSqlGeneration( + "SELECT u.name, (SELECT COUNT(p.phonenumber) FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234) pcount FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'", + "SELECT c0_.name AS name0, (SELECT COUNT(c1_.phonenumber) AS dctrn__1 FROM cms_phonenumbers c1_ WHERE c1_.phonenumber = 1234) AS sclr1 FROM cms_users c0_ WHERE c0_.name = 'jon'" + ); + } + + /** + * @group locking + * @group DDC-178 + */ + public function testPessimisticWriteLockQueryHint() + { + if ($this->_em->getConnection()->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) { + $this->markTestSkipped('SqLite does not support Row locking at all.'); + } + + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 ". + "FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR UPDATE", + array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ); + } + + /** + * @group locking + * @group DDC-178 + */ + public function testPessimisticReadLockQueryHintPostgreSql() + { + $this->_em->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform); + + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 ". + "FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR SHARE", + array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::PESSIMISTIC_READ) + ); + } + + /** + * @group DDC-1693 + * @group locking + */ + public function testLockModeNoneQueryHint() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 ". + "FROM cms_users c0_ WHERE c0_.username = 'gblanco'", + array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::NONE) + ); + } + + /** + * @group DDC-430 + */ + public function testSupportSelectWithMoreThan10InputParameters() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1 OR u.id = ?2 OR u.id = ?3 OR u.id = ?4 OR u.id = ?5 OR u.id = ?6 OR u.id = ?7 OR u.id = ?8 OR u.id = ?9 OR u.id = ?10 OR u.id = ?11", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ?" + ); + } + + /** + * @group locking + * @group DDC-178 + */ + public function testPessimisticReadLockQueryHintMySql() + { + $this->_em->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\MySqlPlatform); + + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 ". + "FROM cms_users c0_ WHERE c0_.username = 'gblanco' LOCK IN SHARE MODE", + array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::PESSIMISTIC_READ) + ); + } + + /** + * @group locking + * @group DDC-178 + */ + public function testPessimisticReadLockQueryHintOracle() + { + $this->_em->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\OraclePlatform); + + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'", + "SELECT c0_.id AS ID0, c0_.status AS STATUS1, c0_.username AS USERNAME2, c0_.name AS NAME3 ". + "FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR UPDATE", + array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::PESSIMISTIC_READ) + ); + } + + /** + * @group DDC-431 + */ + public function testSupportToCustomDQLFunctions() + { + $config = $this->_em->getConfiguration(); + $config->addCustomNumericFunction('MYABS', 'Doctrine\Tests\ORM\Query\MyAbsFunction'); + + $this->assertSqlGeneration( + 'SELECT MYABS(p.phonenumber) FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p', + 'SELECT ABS(c0_.phonenumber) AS sclr0 FROM cms_phonenumbers c0_' + ); + + $config->setCustomNumericFunctions(array()); + } + + /** + * @group DDC-826 + */ + public function testMappedSuperclassAssociationJoin() + { + $this->assertSqlGeneration( + 'SELECT f FROM Doctrine\Tests\Models\DirectoryTree\File f JOIN f.parentDirectory d WHERE f.id = ?1', + 'SELECT f0_.id AS id0, f0_.extension AS extension1, f0_.name AS name2 FROM "file" f0_ INNER JOIN Directory d1_ ON f0_.parentDirectory_id = d1_.id WHERE f0_.id = ?' + ); + } + + /** + * @group DDC-1053 + */ + public function testGroupBy() + { + $this->assertSqlGeneration( + 'SELECT g.id, count(u.id) FROM Doctrine\Tests\Models\CMS\CmsGroup g JOIN g.users u GROUP BY g.id', + 'SELECT c0_.id AS id0, count(c1_.id) AS sclr1 FROM cms_groups c0_ INNER JOIN cms_users_groups c2_ ON c0_.id = c2_.group_id INNER JOIN cms_users c1_ ON c1_.id = c2_.user_id GROUP BY c0_.id' + ); + } + + /** + * @group DDC-1053 + */ + public function testGroupByIdentificationVariable() + { + $this->assertSqlGeneration( + 'SELECT g, count(u.id) FROM Doctrine\Tests\Models\CMS\CmsGroup g JOIN g.users u GROUP BY g', + 'SELECT c0_.id AS id0, c0_.name AS name1, count(c1_.id) AS sclr2 FROM cms_groups c0_ INNER JOIN cms_users_groups c2_ ON c0_.id = c2_.group_id INNER JOIN cms_users c1_ ON c1_.id = c2_.user_id GROUP BY c0_.id, c0_.name' + ); + } + + public function testCaseContainingNullIf() + { + $this->assertSqlGeneration( + "SELECT NULLIF(g.id, g.name) AS NullIfEqual FROM Doctrine\Tests\Models\CMS\CmsGroup g", + 'SELECT NULLIF(c0_.id, c0_.name) AS sclr0 FROM cms_groups c0_' + ); + } + + public function testCaseContainingCoalesce() + { + $this->assertSqlGeneration( + "SELECT COALESCE(NULLIF(u.name, ''), u.username) as Display FROM Doctrine\Tests\Models\CMS\CmsUser u", + "SELECT COALESCE(NULLIF(c0_.name, ''), c0_.username) AS sclr0 FROM cms_users c0_" + ); + } + + /** + * Test that the right discriminator data is inserted in a subquery. + */ + public function testSubSelectDiscriminator() + { + $this->assertSqlGeneration( + "SELECT u.name, (SELECT COUNT(cfc.id) total FROM Doctrine\Tests\Models\Company\CompanyFixContract cfc) as cfc_count FROM Doctrine\Tests\Models\CMS\CmsUser u", + "SELECT c0_.name AS name0, (SELECT COUNT(c1_.id) AS dctrn__total FROM company_contracts c1_ WHERE c1_.discr IN ('fix')) AS sclr1 FROM cms_users c0_" + ); + } + + public function testIdVariableResultVariableReuse() + { + $exceptionThrown = false; + try { + $query = $this->_em->createQuery("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IN (SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u)"); + + $query->getSql(); + $query->free(); + } catch (\Exception $e) { + $exceptionThrown = true; + } + + $this->assertTrue($exceptionThrown); + + } + + public function testSubSelectAliasesFromOuterQuery() + { + $this->assertSqlGeneration( + "SELECT uo, (SELECT ui.name FROM Doctrine\Tests\Models\CMS\CmsUser ui WHERE ui.id = uo.id) AS bar FROM Doctrine\Tests\Models\CMS\CmsUser uo", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, (SELECT c1_.name FROM cms_users c1_ WHERE c1_.id = c0_.id) AS sclr4 FROM cms_users c0_" + ); + } + + public function testSubSelectAliasesFromOuterQueryWithSubquery() + { + $this->assertSqlGeneration( + "SELECT uo, (SELECT ui.name FROM Doctrine\Tests\Models\CMS\CmsUser ui WHERE ui.id = uo.id AND ui.name IN (SELECT uii.name FROM Doctrine\Tests\Models\CMS\CmsUser uii)) AS bar FROM Doctrine\Tests\Models\CMS\CmsUser uo", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, (SELECT c1_.name FROM cms_users c1_ WHERE c1_.id = c0_.id AND c1_.name IN (SELECT c2_.name FROM cms_users c2_)) AS sclr4 FROM cms_users c0_" + ); + } + + public function testSubSelectAliasesFromOuterQueryReuseInWhereClause() + { + $this->assertSqlGeneration( + "SELECT uo, (SELECT ui.name FROM Doctrine\Tests\Models\CMS\CmsUser ui WHERE ui.id = uo.id) AS bar FROM Doctrine\Tests\Models\CMS\CmsUser uo WHERE bar = ?0", + "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, (SELECT c1_.name FROM cms_users c1_ WHERE c1_.id = c0_.id) AS sclr4 FROM cms_users c0_ WHERE sclr4 = ?" + ); + } + + /** + * @group DDC-1298 + */ + public function testSelectForeignKeyPKWithoutFields() + { + $this->assertSqlGeneration( + "SELECT t, s, l FROM Doctrine\Tests\Models\DDC117\DDC117Link l INNER JOIN l.target t INNER JOIN l.source s", + "SELECT d0_.article_id AS article_id0, d0_.title AS title1, d1_.article_id AS article_id2, d1_.title AS title3, d2_.source_id AS source_id4, d2_.target_id AS target_id5 FROM DDC117Link d2_ INNER JOIN DDC117Article d0_ ON d2_.target_id = d0_.article_id INNER JOIN DDC117Article d1_ ON d2_.source_id = d1_.article_id" + ); + } + + public function testGeneralCaseWithSingleWhenClause() + { + $this->assertSqlGeneration( + "SELECT g.id, CASE WHEN ((g.id / 2) > 18) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g", + "SELECT c0_.id AS id0, CASE WHEN (c0_.id / 2 > 18) THEN 1 ELSE 0 END AS sclr1 FROM cms_groups c0_" + ); + } + + public function testGeneralCaseWithMultipleWhenClause() + { + $this->assertSqlGeneration( + "SELECT g.id, CASE WHEN (g.id / 2 < 10) THEN 2 WHEN ((g.id / 2) > 20) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g", + "SELECT c0_.id AS id0, CASE WHEN (c0_.id / 2 < 10) THEN 2 WHEN (c0_.id / 2 > 20) THEN 1 ELSE 0 END AS sclr1 FROM cms_groups c0_" + ); + } + + public function testSimpleCaseWithSingleWhenClause() + { + $this->assertSqlGeneration( + "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = CASE g.name WHEN 'admin' THEN 1 ELSE 2 END", + "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id = CASE c0_.name WHEN 'admin' THEN 1 ELSE 2 END" + ); + } + + public function testSimpleCaseWithMultipleWhenClause() + { + $this->assertSqlGeneration( + "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = (CASE g.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END)", + "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id = CASE c0_.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END" + ); + } + + public function testGeneralCaseWithSingleWhenClauseInSubselect() + { + $this->assertSqlGeneration( + "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN ((g2.id / 2) > 18) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)", + "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE WHEN (c1_.id / 2 > 18) THEN 2 ELSE 1 END AS sclr2 FROM cms_groups c1_)" + ); + } + + public function testGeneralCaseWithMultipleWhenClauseInSubselect() + { + $this->assertSqlGeneration( + "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN (g.id / 2 < 10) THEN 3 WHEN ((g.id / 2) > 20) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)", + "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE WHEN (c0_.id / 2 < 10) THEN 3 WHEN (c0_.id / 2 > 20) THEN 2 ELSE 1 END AS sclr2 FROM cms_groups c1_)" + ); + } + + public function testSimpleCaseWithSingleWhenClauseInSubselect() + { + $this->assertSqlGeneration( + "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 ELSE 2 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)", + "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE c1_.name WHEN 'admin' THEN 1 ELSE 2 END AS sclr2 FROM cms_groups c1_)" + ); + } + + public function testSimpleCaseWithMultipleWhenClauseInSubselect() + { + $this->assertSqlGeneration( + "SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)", + "SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE c1_.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END AS sclr2 FROM cms_groups c1_)" + ); + } + + /** + * @group DDC-1696 + */ + public function testSimpleCaseWithStringPrimary() + { + $this->assertSqlGeneration( + "SELECT g.id, CASE WHEN ((g.id / 2) > 18) THEN 'Foo' ELSE 'Bar' END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g", + "SELECT c0_.id AS id0, CASE WHEN (c0_.id / 2 > 18) THEN 'Foo' ELSE 'Bar' END AS sclr1 FROM cms_groups c0_" + ); + } + + /** + * @group DDC-1339 + */ + public function testIdentityFunctionInSelectClause() + { + $this->assertSqlGeneration( + "SELECT IDENTITY(u.email) as email_id FROM Doctrine\Tests\Models\CMS\CmsUser u", + "SELECT c0_.email_id AS sclr0 FROM cms_users c0_" + ); + } + + /** + * @group DDC-1339 + */ + public function testIdentityFunctionDoesNotAcceptStateField() + { + $this->assertInvalidSqlGeneration( + "SELECT IDENTITY(u.name) as name FROM Doctrine\Tests\Models\CMS\CmsUser u", + "Doctrine\ORM\Query\QueryException" + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeJoinInRootClassWithDisabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p', + 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c1_.car_id AS car_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id', + array(Query::HINT_FORCE_PARTIAL_LOAD => false) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeJoinInRootClassWithEnabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p', + 'SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_', + array(Query::HINT_FORCE_PARTIAL_LOAD => true) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeJoinInChildClassWithDisabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e', + 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c2_.car_id AS car_id8 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id', + array(Query::HINT_FORCE_PARTIAL_LOAD => false) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeJoinInChildClassWithEnabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e', + 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c0_.discr AS discr5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id', + array(Query::HINT_FORCE_PARTIAL_LOAD => true) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeJoinInLeafClassWithDisabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT m FROM Doctrine\Tests\Models\Company\CompanyManager m', + 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c2_.car_id AS car_id8 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id', + array(Query::HINT_FORCE_PARTIAL_LOAD => false) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeJoinInLeafClassWithEnabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT m FROM Doctrine\Tests\Models\Company\CompanyManager m', + 'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id', + array(Query::HINT_FORCE_PARTIAL_LOAD => true) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeSingleTableInRootClassWithDisabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c', + "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6, c0_.salesPerson_id AS salesPerson_id7 FROM company_contracts c0_ WHERE c0_.discr IN ('fix', 'flexible', 'flexultra')", + array(Query::HINT_FORCE_PARTIAL_LOAD => false) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeSingleTableInRootClassWithEnabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c', + "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_contracts c0_ WHERE c0_.discr IN ('fix', 'flexible', 'flexultra')", + array(Query::HINT_FORCE_PARTIAL_LOAD => true) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeSingleTableInChildClassWithDisabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT fc FROM Doctrine\Tests\Models\Company\CompanyFlexContract fc', + "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5, c0_.salesPerson_id AS salesPerson_id6 FROM company_contracts c0_ WHERE c0_.discr IN ('flexible', 'flexultra')", + array(Query::HINT_FORCE_PARTIAL_LOAD => false) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeSingleTableInChildClassWithEnabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT fc FROM Doctrine\Tests\Models\Company\CompanyFlexContract fc', + "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5 FROM company_contracts c0_ WHERE c0_.discr IN ('flexible', 'flexultra')", + array(Query::HINT_FORCE_PARTIAL_LOAD => true) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeSingleTableInLeafClassWithDisabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT fuc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract fuc', + "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5, c0_.salesPerson_id AS salesPerson_id6 FROM company_contracts c0_ WHERE c0_.discr IN ('flexultra')", + array(Query::HINT_FORCE_PARTIAL_LOAD => false) + ); + } + + /** + * @group DDC-1389 + */ + public function testInheritanceTypeSingleTableInLeafClassWithEnabledForcePartialLoad() + { + $this->assertSqlGeneration( + 'SELECT fuc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract fuc', + "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5 FROM company_contracts c0_ WHERE c0_.discr IN ('flexultra')", + array(Query::HINT_FORCE_PARTIAL_LOAD => true) + ); + } + + /** + * @group DDC-1161 + */ + public function testSelfReferenceWithOneToOneDoesNotDuplicateAlias() + { + $this->assertSqlGeneration( + 'SELECT p, pp FROM Doctrine\Tests\Models\Company\CompanyPerson p JOIN p.spouse pp', + "SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c3_.id AS id6, c3_.name AS name7, c4_.title AS title8, c5_.salary AS salary9, c5_.department AS department10, c5_.startDate AS startDate11, c0_.discr AS discr12, c0_.spouse_id AS spouse_id13, c1_.car_id AS car_id14, c3_.discr AS discr15, c3_.spouse_id AS spouse_id16, c4_.car_id AS car_id17 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ ON c0_.spouse_id = c3_.id LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id", + array(Query::HINT_FORCE_PARTIAL_LOAD => false) + ); + } + + /** + * @group DDC-1384 + */ + public function testAliasDoesNotExceedPlatformDefinedLength() + { + $this->assertSqlGeneration( + 'SELECT m FROM ' . __NAMESPACE__ . '\\DDC1384Model m', + "SELECT d0_.aVeryLongIdentifierThatShouldBeShortenedByTheSQLWalker_fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo AS fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0 FROM DDC1384Model d0_" + ); + } + + /** + * @group DDC-331 + * @group DDC-1384 + */ + public function testIssue331() + { + $this->assertSqlGeneration( + 'SELECT e.name FROM Doctrine\Tests\Models\Company\CompanyEmployee e', + 'SELECT c0_.name AS name0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id' + ); + } + /** + * @group DDC-1435 + */ + public function testForeignKeyAsPrimaryKeySubselect() + { + $this->assertSqlGeneration( + "SELECT s FROM Doctrine\Tests\Models\DDC117\DDC117Article s WHERE EXISTS (SELECT r FROM Doctrine\Tests\Models\DDC117\DDC117Reference r WHERE r.source = s)", + "SELECT d0_.article_id AS article_id0, d0_.title AS title1 FROM DDC117Article d0_ WHERE EXISTS (SELECT d1_.source_id, d1_.target_id FROM DDC117Reference d1_ WHERE d1_.source_id = d0_.article_id)" + ); + } + + /** + * @group DDC-1474 + */ + public function testSelectWithArithmeticExpressionBeforeField() + { + $this->assertSqlGeneration( + 'SELECT - e.value AS value, e.id FROM ' . __NAMESPACE__ . '\DDC1474Entity e', + 'SELECT -d0_.value AS sclr0, d0_.id AS id1 FROM DDC1474Entity d0_' + ); + + $this->assertSqlGeneration( + 'SELECT e.id, + e.value AS value FROM ' . __NAMESPACE__ . '\DDC1474Entity e', + 'SELECT d0_.id AS id0, +d0_.value AS sclr1 FROM DDC1474Entity d0_' + ); + } + + /** + * @group DDC-1430 + */ + public function testGroupByAllFieldsWhenObjectHasForeignKeys() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ GROUP BY c0_.id, c0_.status, c0_.username, c0_.name, c0_.email_id' + ); + + $this->assertSqlGeneration( + 'SELECT e FROM Doctrine\Tests\Models\CMS\CmsEmployee e GROUP BY e', + 'SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_employees c0_ GROUP BY c0_.id, c0_.name, c0_.spouse_id' + ); + } + + /** + * @group DDC-1236 + */ + public function testGroupBySupportsResultVariable() + { + $this->assertSqlGeneration( + 'SELECT u, u.status AS st FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY st', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.status AS status4 FROM cms_users c0_ GROUP BY status4' + ); + } + + /** + * @group DDC-1236 + */ + public function testGroupBySupportsIdentificationVariable() + { + $this->assertSqlGeneration( + 'SELECT u AS user FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY user', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ GROUP BY id0, status1, username2, name3' + ); + } + + /** + * @group DDC-1213 + */ + public function testSupportsBitComparison() + { + $this->assertSqlGeneration( + 'SELECT BIT_OR(4,2), BIT_AND(4,2), u FROM Doctrine\Tests\Models\CMS\CmsUser u', + 'SELECT (4 | 2) AS sclr0, (4 & 2) AS sclr1, c0_.id AS id2, c0_.status AS status3, c0_.username AS username4, c0_.name AS name5 FROM cms_users c0_' + ); + $this->assertSqlGeneration( + 'SELECT BIT_OR(u.id,2), BIT_AND(u.id,2) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE BIT_OR(u.id,2) > 0', + 'SELECT (c0_.id | 2) AS sclr0, (c0_.id & 2) AS sclr1 FROM cms_users c0_ WHERE (c0_.id | 2) > 0' + ); + $this->assertSqlGeneration( + 'SELECT BIT_OR(u.id,2), BIT_AND(u.id,2) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE BIT_AND(u.id , 4) > 0', + 'SELECT (c0_.id | 2) AS sclr0, (c0_.id & 2) AS sclr1 FROM cms_users c0_ WHERE (c0_.id & 4) > 0' + ); + $this->assertSqlGeneration( + 'SELECT BIT_OR(u.id,2), BIT_AND(u.id,2) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE BIT_OR(u.id , 2) > 0 OR BIT_AND(u.id , 4) > 0', + 'SELECT (c0_.id | 2) AS sclr0, (c0_.id & 2) AS sclr1 FROM cms_users c0_ WHERE (c0_.id | 2) > 0 OR (c0_.id & 4) > 0' + ); + } + + /** + * @group DDC-1539 + */ + public function testParenthesesOnTheLeftHandOfComparison() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u where ( (u.id + u.id) * u.id ) > 100', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (c0_.id + c0_.id) * c0_.id > 100' + ); + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u where (u.id + u.id) * u.id > 100', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (c0_.id + c0_.id) * c0_.id > 100' + ); + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u where 100 < (u.id + u.id) * u.id ', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE 100 < (c0_.id + c0_.id) * c0_.id' + ); + } + + /** + * @group DDC-1557 + */ + public function testSupportsSubSqlFunction() + { + $this->assertSqlGeneration( + 'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.name IN ( SELECT TRIM(u2.name) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.name IN (SELECT TRIM(c1_.name) AS sclr4 FROM cms_users c1_)' + ); + $this->assertSqlGeneration( + 'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.name IN ( SELECT TRIM(u2.name) FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE LOWER(u2.name) LIKE \'%fabio%\')', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.name IN (SELECT TRIM(c1_.name) AS sclr4 FROM cms_users c1_ WHERE LOWER(c1_.name) LIKE \'%fabio%\')' + ); + $this->assertSqlGeneration( + 'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.email IN ( SELECT TRIM(IDENTITY(u2.email)) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.email_id IN (SELECT TRIM(c1_.email_id) AS sclr4 FROM cms_users c1_)' + ); + $this->assertSqlGeneration( + 'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.email IN ( SELECT IDENTITY(u2.email) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.email_id IN (SELECT c1_.email_id AS sclr4 FROM cms_users c1_)' + ); + $this->assertSqlGeneration( + 'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE COUNT(u1.id) = ( SELECT SUM(u2.id) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE COUNT(c0_.id) = (SELECT SUM(c1_.id) AS dctrn__1 FROM cms_users c1_)' + ); + $this->assertSqlGeneration( + 'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE COUNT(u1.id) <= ( SELECT SUM(u2.id) + COUNT(u2.email) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE COUNT(c0_.id) <= (SELECT SUM(c1_.id) + COUNT(c1_.email_id) AS sclr4 FROM cms_users c1_)' + ); + } + + public function testCustomTypeValueSql() + { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + + $this->assertSqlGeneration( + 'SELECT p.customInteger FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p WHERE p.id = 1', + 'SELECT -(c0_.customInteger) AS customInteger0 FROM customtype_parents c0_ WHERE c0_.id = 1' + ); + } + + public function testCustomTypeValueSqlIgnoresIdentifierColumn() + { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + + $this->assertSqlGeneration( + 'SELECT p.id FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p WHERE p.id = 1', + 'SELECT c0_.id AS id0 FROM customtype_parents c0_ WHERE c0_.id = 1' + ); + } + + public function testCustomTypeValueSqlForAllFields() + { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + + $this->assertSqlGeneration( + 'SELECT p FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p', + 'SELECT c0_.id AS id0, -(c0_.customInteger) AS customInteger1 FROM customtype_parents c0_' + ); + } + + public function testCustomTypeValueSqlForPartialObject() + { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + + $this->assertSqlGeneration( + 'SELECT partial p.{id, customInteger} FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p', + 'SELECT c0_.id AS id0, -(c0_.customInteger) AS customInteger1 FROM customtype_parents c0_' + ); + } + + /** + * @group DDC-1529 + */ + public function testMultipleFromAndInheritanceCondition() + { + $this->assertSqlGeneration( + 'SELECT fix, flex FROM Doctrine\Tests\Models\Company\CompanyFixContract fix, Doctrine\Tests\Models\Company\CompanyFlexContract flex', + "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c1_.id AS id3, c1_.completed AS completed4, c1_.hoursWorked AS hoursWorked5, c1_.pricePerHour AS pricePerHour6, c1_.maxPrice AS maxPrice7, c0_.discr AS discr8, c1_.discr AS discr9 FROM company_contracts c0_, company_contracts c1_ WHERE (c0_.discr IN ('fix') AND c1_.discr IN ('flexible', 'flexultra'))" + ); + } + + /** + * @group DDC-775 + */ + public function testOrderByClauseSupportsSimpleArithmeticExpression() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.id + 1 ', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY c0_.id + 1 ASC' + ); + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY ( ( (u.id + 1) * (u.id - 1) ) / 2)', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY (c0_.id + 1) * (c0_.id - 1) / 2 ASC' + ); + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY ((u.id + 5000) * u.id + 3) ', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY (c0_.id + 5000) * c0_.id + 3 ASC' + ); + } + + /** + * @group DDC-1719 + */ + public function testStripNonAlphanumericCharactersFromAlias() + { + $this->assertSqlGeneration( + 'SELECT e FROM Doctrine\Tests\Models\Quote\SimpleEntity e', + 'SELECT d0_."simple-entity-id" AS simpleentityid0, d0_."simple-entity-value" AS simpleentityvalue1 FROM "ddc-1719-simple-entity" d0_' + ); + + $this->assertSqlGeneration( + 'SELECT e.value FROM Doctrine\Tests\Models\Quote\SimpleEntity e ORDER BY e.value', + 'SELECT d0_."simple-entity-value" AS simpleentityvalue0 FROM "ddc-1719-simple-entity" d0_ ORDER BY d0_."simple-entity-value" ASC' + ); + + $this->assertSqlGeneration( + 'SELECT TRIM(e.value) FROM Doctrine\Tests\Models\Quote\SimpleEntity e ORDER BY e.value', + 'SELECT TRIM(d0_."simple-entity-value") AS sclr0 FROM "ddc-1719-simple-entity" d0_ ORDER BY d0_."simple-entity-value" ASC' + ); + } + + /** + * @group DDC-1845 + */ + public function testQuotedWalkJoinVariableDeclaration() + { + $this->assertSqlGeneration( + 'SELECT u, a FROM Doctrine\Tests\Models\Quote\User u JOIN u.address a', + 'SELECT q0_."user-id" AS userid0, q0_."user-name" AS username1, q1_."address-id" AS addressid2, q1_."address-zip" AS addresszip3 FROM "quote-user" q0_ INNER JOIN "quote-address" q1_ ON q0_."address-id" = q1_."address-id"' + ); + + $this->assertSqlGeneration( + 'SELECT u, p FROM Doctrine\Tests\Models\Quote\User u JOIN u.phones p', + 'SELECT q0_."user-id" AS userid0, q0_."user-name" AS username1, q1_."phone-number" AS phonenumber2 FROM "quote-user" q0_ INNER JOIN "quote-phone" q1_ ON q0_."user-id" = q1_."user-id"' + ); + + $this->assertSqlGeneration( + 'SELECT u, g FROM Doctrine\Tests\Models\Quote\User u JOIN u.groups g', + 'SELECT q0_."user-id" AS userid0, q0_."user-name" AS username1, q1_."group-id" AS groupid2, q1_."group-name" AS groupname3 FROM "quote-user" q0_ INNER JOIN "quote-users-groups" q2_ ON q0_."user-id" = q2_."user-id" INNER JOIN "quote-group" q1_ ON q1_."group-id" = q2_."group-id"' + ); + + $this->assertSqlGeneration( + 'SELECT a, u FROM Doctrine\Tests\Models\Quote\Address a JOIN a.user u', + 'SELECT q0_."address-id" AS addressid0, q0_."address-zip" AS addresszip1, q1_."user-id" AS userid2, q1_."user-name" AS username3 FROM "quote-address" q0_ INNER JOIN "quote-user" q1_ ON q0_."user-id" = q1_."user-id"' + ); + + $this->assertSqlGeneration( + 'SELECT g, u FROM Doctrine\Tests\Models\Quote\Group g JOIN g.users u', + 'SELECT q0_."group-id" AS groupid0, q0_."group-name" AS groupname1, q1_."user-id" AS userid2, q1_."user-name" AS username3 FROM "quote-group" q0_ INNER JOIN "quote-users-groups" q2_ ON q0_."group-id" = q2_."group-id" INNER JOIN "quote-user" q1_ ON q1_."user-id" = q2_."user-id"' + ); + + $this->assertSqlGeneration( + 'SELECT g, p FROM Doctrine\Tests\Models\Quote\Group g JOIN g.parent p', + 'SELECT q0_."group-id" AS groupid0, q0_."group-name" AS groupname1, q1_."group-id" AS groupid2, q1_."group-name" AS groupname3 FROM "quote-group" q0_ INNER JOIN "quote-group" q1_ ON q0_."parent-id" = q1_."group-id"' + ); + } +} + +class MyAbsFunction extends \Doctrine\ORM\Query\AST\Functions\FunctionNode +{ + public $simpleArithmeticExpression; + + /** + * @override + */ + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + { + return 'ABS(' . $sqlWalker->walkSimpleArithmeticExpression($this->simpleArithmeticExpression) . ')'; + } + + /** + * @override + */ + public function parse(\Doctrine\ORM\Query\Parser $parser) + { + $lexer = $parser->getLexer(); + + $parser->match(\Doctrine\ORM\Query\Lexer::T_IDENTIFIER); + $parser->match(\Doctrine\ORM\Query\Lexer::T_OPEN_PARENTHESIS); + + $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); + + $parser->match(\Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS); + } +} +/** + * @Entity + */ +class DDC1384Model +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + protected $aVeryLongIdentifierThatShouldBeShortenedByTheSQLWalker_fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo; +} + + +/** + * @Entity + */ +class DDC1474Entity +{ + + /** + * @Id + * @Column(type="integer") + * @GeneratedValue() + */ + protected $id; + + /** + * @column(type="float") + */ + private $value; + + /** + * @param string $float + */ + public function __construct($float) + { + $this->value = $float; + } + + /** + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * @return float + */ + public function getValue() + { + return $this->value; + } + + /** + * @param float $value + */ + public function setValue($value) + { + $this->value = $value; + } + +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php new file mode 100644 index 0000000..a65efe0 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php @@ -0,0 +1,205 @@ +. + */ + +namespace Doctrine\Tests\ORM\Query; + +use Doctrine\DBAL\Types\Type as DBALType; + +require_once __DIR__ . '/../../TestInit.php'; + +/** + * Test case for testing the saving and referencing of query identifiers. + * + * @author Guilherme Blanco + * @author Janne Vanhala + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + * @todo 1) [romanb] We might want to split the SQL generation tests into multiple + * testcases later since we'll have a lot of them and we might want to have special SQL + * generation tests for some dbms specific SQL syntaxes. + */ +class UpdateSqlGenerationTest extends \Doctrine\Tests\OrmTestCase +{ + private $_em; + + protected function setUp() { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + + $this->_em = $this->_getTestEntityManager(); + } + + public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed) + { + try { + $query = $this->_em->createQuery($dqlToBeTested); + parent::assertEquals($sqlToBeConfirmed, $query->getSql()); + $query->free(); + } catch (\Exception $e) { + $this->fail($e->getMessage()); + } + } + + public function testSupportsQueriesWithoutWhere() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1', + 'UPDATE cms_users SET name = ?' + ); + } + + public function testSupportsMultipleFieldsWithoutWhere() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1, u.username = ?2', + 'UPDATE cms_users SET name = ?, username = ?' + ); + } + + public function testSupportsWhereClauses() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1 WHERE u.id = ?2', + 'UPDATE cms_users SET name = ? WHERE id = ?' + ); + } + + public function testSupportsWhereClausesOnTheUpdatedField() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1 WHERE u.name = ?2', + 'UPDATE cms_users SET name = ? WHERE name = ?' + ); + } + + public function testSupportsMultipleWhereClause() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1 WHERE u.name = ?2 AND u.status = ?3', + 'UPDATE cms_users SET name = ? WHERE name = ? AND status = ?' + ); + } + + public function testSupportsInClause() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1 WHERE u.id IN (1, 3, 4)', + 'UPDATE cms_users SET name = ? WHERE id IN (1, 3, 4)' + ); + } + + public function testSupportsParametrizedInClause() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1 WHERE u.id IN (?2, ?3, ?4)', + 'UPDATE cms_users SET name = ? WHERE id IN (?, ?, ?)' + ); + } + + public function testSupportsNotInClause() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1 WHERE u.id NOT IN (1, 3, 4)', + 'UPDATE cms_users SET name = ? WHERE id NOT IN (1, 3, 4)' + ); + } + + public function testSupportsGreatherThanClause() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.status = ?1 WHERE u.id > ?2', + 'UPDATE cms_users SET status = ? WHERE id > ?' + ); + } + + public function testSupportsGreatherThanOrEqualToClause() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.status = ?1 WHERE u.id >= ?2', + 'UPDATE cms_users SET status = ? WHERE id >= ?' + ); + } + + public function testSupportsLessThanClause() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.status = ?1 WHERE u.id < ?2', + 'UPDATE cms_users SET status = ? WHERE id < ?' + ); + } + + public function testSupportsLessThanOrEqualToClause() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.status = ?1 WHERE u.id <= ?2', + 'UPDATE cms_users SET status = ? WHERE id <= ?' + ); + } + + public function testSupportsBetweenClause() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.status = ?1 WHERE u.id BETWEEN :from AND :to', + 'UPDATE cms_users SET status = ? WHERE id BETWEEN ? AND ?' + ); + } + + public function testSingleValuedAssociationFieldInWhere() + { + $this->assertSqlGeneration( + "UPDATE Doctrine\Tests\Models\CMS\CmsPhonenumber p SET p.phonenumber = 1234 WHERE p.user = ?1", + "UPDATE cms_phonenumbers SET phonenumber = 1234 WHERE user_id = ?" + ); + } + + public function testSingleValuedAssociationFieldInSetClause() + { + $this->assertSqlGeneration( + "update Doctrine\Tests\Models\CMS\CmsComment c set c.article = null where c.article=?1", + "UPDATE cms_comments SET article_id = NULL WHERE article_id = ?" + ); + } + + /** + * @group DDC-980 + */ + public function testSubselectTableAliasReferencing() + { + $this->assertSqlGeneration( + "UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.status = 'inactive' WHERE SIZE(u.groups) = 10", + "UPDATE cms_users SET status = 'inactive' WHERE (SELECT COUNT(*) FROM cms_users_groups c0_ WHERE c0_.user_id = cms_users.id) = 10" + ); + } + + public function testCustomTypeValueSqlCompletelyIgnoredInUpdateStatements() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CustomType\CustomTypeParent p SET p.customInteger = 1 WHERE p.id = 1', + 'UPDATE customtype_parents SET customInteger = 1 WHERE id = 1' + ); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/QueryBuilderTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/QueryBuilderTest.php new file mode 100644 index 0000000..82ee08b --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/QueryBuilderTest.php @@ -0,0 +1,784 @@ +. + */ + +namespace Doctrine\Tests\ORM; + +use Doctrine\Common\Collections\ArrayCollection; + +use Doctrine\ORM\QueryBuilder, + Doctrine\ORM\Query\Expr, + Doctrine\ORM\Query\Parameter, + Doctrine\ORM\Query\ParameterTypeInferer; + +require_once __DIR__ . '/../TestInit.php'; + +/** + * Test case for the QueryBuilder class used to build DQL query string in a + * object oriented way. + * + * @author Jonathan H. Wage + * @author Roman Borschel _em = $this->_getTestEntityManager(); + } + + protected function assertValidQueryBuilder(QueryBuilder $qb, $expectedDql) + { + $dql = $qb->getDql(); + $q = $qb->getQuery(); + + $this->assertEquals($expectedDql, $dql); + } + + public function testSelectSetsType() + { + $qb = $this->_em->createQueryBuilder() + ->delete('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->select('u.id', 'u.username'); + + $this->assertEquals($qb->getType(), QueryBuilder::SELECT); + } + + public function testEmptySelectSetsType() + { + $qb = $this->_em->createQueryBuilder() + ->delete('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->select(); + + $this->assertEquals($qb->getType(), QueryBuilder::SELECT); + } + + public function testDeleteSetsType() + { + $qb = $this->_em->createQueryBuilder() + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->delete(); + + $this->assertEquals($qb->getType(), QueryBuilder::DELETE); + } + + public function testUpdateSetsType() + { + $qb = $this->_em->createQueryBuilder() + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->update(); + + $this->assertEquals($qb->getType(), QueryBuilder::UPDATE); + } + + public function testSimpleSelect() + { + $qb = $this->_em->createQueryBuilder() + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->select('u.id', 'u.username'); + + $this->assertValidQueryBuilder($qb, 'SELECT u.id, u.username FROM Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testSimpleDelete() + { + $qb = $this->_em->createQueryBuilder() + ->delete('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + + $this->assertValidQueryBuilder($qb, 'DELETE Doctrine\Tests\Models\CMS\CmsUser u'); + } + + public function testSimpleUpdate() + { + $qb = $this->_em->createQueryBuilder() + ->update('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->set('u.username', ':username'); + + $this->assertValidQueryBuilder($qb, 'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.username = :username'); + } + + public function testInnerJoin() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'a') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->innerJoin('u.articles', 'a'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a'); + } + + public function testComplexInnerJoin() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'a') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->innerJoin('u.articles', 'a', 'ON', 'u.id = a.author_id'); + + $this->assertValidQueryBuilder( + $qb, + 'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a ON u.id = a.author_id' + ); + } + + public function testLeftJoin() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'a') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->leftJoin('u.articles', 'a'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a'); + } + + public function testLeftJoinWithIndexBy() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'a') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->leftJoin('u.articles', 'a', null, null, 'a.name'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a INDEX BY a.name'); + } + + public function testMultipleFrom() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'g') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->from('Doctrine\Tests\Models\CMS\CmsGroup', 'g'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, g FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsGroup g'); + } + + public function testMultipleFromWithJoin() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'g') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->from('Doctrine\Tests\Models\CMS\CmsGroup', 'g') + ->innerJoin('u.articles', 'a', 'ON', 'u.id = a.author_id'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, g FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a ON u.id = a.author_id, Doctrine\Tests\Models\CMS\CmsGroup g'); + } + + public function testMultipleFromWithMultipleJoin() + { + $qb = $this->_em->createQueryBuilder() + ->select('u', 'g') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->from('Doctrine\Tests\Models\CMS\CmsArticle', 'a') + ->innerJoin('u.groups', 'g') + ->leftJoin('u.address', 'ad') + ->innerJoin('a.comments', 'c'); + + $this->assertValidQueryBuilder($qb, 'SELECT u, g FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.groups g LEFT JOIN u.address ad, Doctrine\Tests\Models\CMS\CmsArticle a INNER JOIN a.comments c'); + } + + public function testWhere() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid'); + } + + public function testComplexAndWhere() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid OR u.id = :uid2 OR u.id = :uid3') + ->andWhere('u.name = :name'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id = :uid OR u.id = :uid2 OR u.id = :uid3) AND u.name = :name'); + } + + public function testAndWhere() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid') + ->andWhere('u.id = :uid2'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id = :uid2'); + } + + public function testOrWhere() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid') + ->orWhere('u.id = :uid2'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid OR u.id = :uid2'); + } + + public function testComplexAndWhereOrWhereNesting() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid') + ->orWhere('u.id = :uid2') + ->andWhere('u.id = :uid3') + ->orWhere('u.name = :name1', 'u.name = :name2') + ->andWhere('u.name <> :noname'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (((u.id = :uid OR u.id = :uid2) AND u.id = :uid3) OR u.name = :name1 OR u.name = :name2) AND u.name <> :noname'); + } + + public function testAndWhereIn() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid') + ->andWhere($qb->expr()->in('u.id', array(1, 2, 3))); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id IN(1, 2, 3)'); + } + + public function testOrWhereIn() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid') + ->orWhere($qb->expr()->in('u.id', array(1, 2, 3))); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid OR u.id IN(1, 2, 3)'); + } + + public function testAndWhereNotIn() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid') + ->andWhere($qb->expr()->notIn('u.id', array(1, 2, 3))); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id NOT IN(1, 2, 3)'); + } + + public function testOrWhereNotIn() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid') + ->orWhere($qb->expr()->notIn('u.id', array(1, 2, 3))); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid OR u.id NOT IN(1, 2, 3)'); + } + + public function testGroupBy() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->groupBy('u.id') + ->addGroupBy('u.username'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id, u.username'); + } + + public function testHaving() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->groupBy('u.id') + ->having('COUNT(u.id) > 1'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id HAVING COUNT(u.id) > 1'); + } + + public function testAndHaving() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->groupBy('u.id') + ->having('COUNT(u.id) > 1') + ->andHaving('COUNT(u.id) < 1'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id HAVING COUNT(u.id) > 1 AND COUNT(u.id) < 1'); + } + + public function testOrHaving() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->groupBy('u.id') + ->having('COUNT(u.id) > 1') + ->andHaving('COUNT(u.id) < 1') + ->orHaving('COUNT(u.id) > 1'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u.id HAVING (COUNT(u.id) > 1 AND COUNT(u.id) < 1) OR COUNT(u.id) > 1'); + } + + public function testOrderBy() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->orderBy('u.username', 'ASC'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username ASC'); + } + + public function testOrderByWithExpression() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->orderBy($qb->expr()->asc('u.username')); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username ASC'); + } + + public function testAddOrderBy() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->orderBy('u.username', 'ASC') + ->addOrderBy('u.username', 'DESC'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username ASC, u.username DESC'); + } + + public function testGetQuery() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $q = $qb->getQuery(); + + $this->assertEquals('Doctrine\ORM\Query', get_class($q)); + } + + public function testSetParameter() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :id') + ->setParameter('id', 1); + + $parameter = new Parameter('id', 1, ParameterTypeInferer::inferType(1)); + + $this->assertEquals($parameter, $qb->getParameter('id')); + } + + public function testSetParameters() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where($qb->expr()->orx('u.username = :username', 'u.username = :username2')); + + $parameters = new ArrayCollection(); + $parameters->add(new Parameter('username', 'jwage')); + $parameters->add(new Parameter('username2', 'jonwage')); + + $qb->setParameters($parameters); + + $this->assertEquals($parameters, $qb->getQuery()->getParameters()); + } + + + public function testGetParameters() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :id'); + + $parameters = new ArrayCollection(); + $parameters->add(new Parameter('id', 1)); + + $qb->setParameters($parameters); + + $this->assertEquals($parameters, $qb->getParameters()); + } + + public function testGetParameter() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :id'); + + $parameters = new ArrayCollection(); + $parameters->add(new Parameter('id', 1)); + + $qb->setParameters($parameters); + + $this->assertEquals($parameters->first(), $qb->getParameter('id')); + } + + public function testMultipleWhere() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.id = :uid', 'u.id = :uid2'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id = :uid2'); + } + + public function testMultipleAndWhere() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->andWhere('u.id = :uid', 'u.id = :uid2'); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid AND u.id = :uid2'); + } + + public function testMultipleOrWhere() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->orWhere('u.id = :uid', $qb->expr()->eq('u.id', ':uid2')); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid OR u.id = :uid2'); + } + + public function testComplexWhere() + { + $qb = $this->_em->createQueryBuilder(); + $orExpr = $qb->expr()->orX(); + $orExpr->add($qb->expr()->eq('u.id', ':uid3')); + $orExpr->add($qb->expr()->in('u.id', array(1))); + + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where($orExpr); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid3 OR u.id IN(1)'); + } + + public function testWhereInWithStringLiterals() + { + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where($qb->expr()->in('u.name', array('one', 'two', 'three'))); + + $this->assertValidQueryBuilder($qb, "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IN('one', 'two', 'three')"); + + $qb->where($qb->expr()->in('u.name', array("O'Reilly", "O'Neil", 'Smith'))); + + $this->assertValidQueryBuilder($qb, "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IN('O''Reilly', 'O''Neil', 'Smith')"); + } + + public function testWhereInWithObjectLiterals() + { + $qb = $this->_em->createQueryBuilder(); + $expr = $this->_em->getExpressionBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where($expr->in('u.name', array($expr->literal('one'), $expr->literal('two'), $expr->literal('three')))); + + $this->assertValidQueryBuilder($qb, "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IN('one', 'two', 'three')"); + + $qb->where($expr->in('u.name', array($expr->literal("O'Reilly"), $expr->literal("O'Neil"), $expr->literal('Smith')))); + + $this->assertValidQueryBuilder($qb, "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IN('O''Reilly', 'O''Neil', 'Smith')"); + } + + public function testNegation() + { + $expr = $this->_em->getExpressionBuilder(); + $orExpr = $expr->orX(); + $orExpr->add($expr->eq('u.id', ':uid3')); + $orExpr->add($expr->not($expr->in('u.id', array(1)))); + + $qb = $this->_em->createQueryBuilder(); + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where($orExpr); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :uid3 OR NOT(u.id IN(1))'); + } + + public function testSomeAllAny() + { + $qb = $this->_em->createQueryBuilder(); + $expr = $this->_em->getExpressionBuilder(); + + //$subquery = $qb->subquery('Doctrine\Tests\Models\CMS\CmsArticle', 'a')->select('a.id'); + + $qb->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where($expr->gt('u.id', $expr->all('select a.id from Doctrine\Tests\Models\CMS\CmsArticle a'))); + + $this->assertValidQueryBuilder($qb, 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > ALL(select a.id from Doctrine\Tests\Models\CMS\CmsArticle a)'); + + } + + public function testMultipleIsolatedQueryConstruction() + { + $qb = $this->_em->createQueryBuilder(); + $expr = $this->_em->getExpressionBuilder(); + + $qb->select('u')->from('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + $qb->where($expr->eq('u.name', ':name')); + $qb->setParameter('name', 'romanb'); + + $q1 = $qb->getQuery(); + + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = :name', $q1->getDql()); + $this->assertEquals(1, count($q1->getParameters())); + + // add another condition and construct a second query + $qb->andWhere($expr->eq('u.id', ':id')); + $qb->setParameter('id', 42); + + $q2 = $qb->getQuery(); + + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = :name AND u.id = :id', $q2->getDql()); + $this->assertTrue($q1 !== $q2); // two different, independent queries + $this->assertEquals(2, count($q2->getParameters())); + $this->assertEquals(1, count($q1->getParameters())); // $q1 unaffected + } + + public function testGetEntityManager() + { + $qb = $this->_em->createQueryBuilder(); + $this->assertEquals($this->_em, $qb->getEntityManager()); + } + + public function testInitialStateIsClean() + { + $qb = $this->_em->createQueryBuilder(); + $this->assertEquals(QueryBuilder::STATE_CLEAN, $qb->getState()); + } + + public function testAlteringQueryChangesStateToDirty() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + + $this->assertEquals(QueryBuilder::STATE_DIRTY, $qb->getState()); + } + + public function testSelectWithFuncExpression() + { + $qb = $this->_em->createQueryBuilder(); + $expr = $qb->expr(); + $qb->select($expr->count('e.id')); + + $this->assertValidQueryBuilder($qb, 'SELECT COUNT(e.id)'); + } + + public function testResetDQLPart() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.username = ?1')->orderBy('u.username'); + + $this->assertEquals('u.username = ?1', (string)$qb->getDQLPart('where')); + $this->assertEquals(1, count($qb->getDQLPart('orderBy'))); + + $qb->resetDqlPart('where')->resetDqlPart('orderBy'); + + $this->assertNull($qb->getDQLPart('where')); + $this->assertEquals(0, count($qb->getDQLPart('orderBy'))); + } + + public function testResetDQLParts() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.username = ?1')->orderBy('u.username'); + + $qb->resetDQLParts(array('where', 'orderBy')); + + $this->assertEquals(1, count($qb->getDQLPart('select'))); + $this->assertNull($qb->getDQLPart('where')); + $this->assertEquals(0, count($qb->getDQLPart('orderBy'))); + } + + public function testResetAllDQLParts() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where('u.username = ?1')->orderBy('u.username'); + + $qb->resetDQLParts(); + + $this->assertEquals(0, count($qb->getDQLPart('select'))); + $this->assertNull($qb->getDQLPart('where')); + $this->assertEquals(0, count($qb->getDQLPart('orderBy'))); + } + + /** + * @group DDC-867 + */ + public function testDeepClone() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->andWhere('u.username = ?1') + ->andWhere('u.status = ?2'); + + $expr = $qb->getDQLPart('where'); + $this->assertEquals(2, $expr->count(), "Modifying the second query should affect the first one."); + + $qb2 = clone $qb; + $qb2->andWhere('u.name = ?3'); + + $this->assertEquals(2, $expr->count(), "Modifying the second query should affect the first one."); + } + + /** + * @group DDC-1933 + */ + public function testParametersAreCloned() + { + $originalQb = new QueryBuilder($this->_em); + + $originalQb->setParameter('parameter1', 'value1'); + + $copy = clone $originalQb; + $copy->setParameter('parameter2', 'value2'); + + $this->assertCount(1, $originalQb->getParameters()); + $this->assertSame('value1', $copy->getParameter('parameter1')->getValue()); + $this->assertSame('value2', $copy->getParameter('parameter2')->getValue()); + } + + public function testGetRootAlias() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + + $this->assertEquals('u', $qb->getRootAlias()); + } + + public function testGetRootAliases() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + + $this->assertEquals(array('u'), $qb->getRootAliases()); + } + + public function testGetRootEntities() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + + $this->assertEquals(array('Doctrine\Tests\Models\CMS\CmsUser'), $qb->getRootEntities()); + } + + public function testGetSeveralRootAliases() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u2'); + + $this->assertEquals(array('u', 'u2'), $qb->getRootAliases()); + $this->assertEquals('u', $qb->getRootAlias()); + } + + public function testBCAddJoinWithoutRootAlias() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->add('join', array('INNER JOIN u.groups g'), true); + + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.groups g', $qb->getDQL()); + } + + /** + * @group DDC-1211 + */ + public function testEmptyStringLiteral() + { + $expr = $this->_em->getExpressionBuilder(); + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where($expr->eq('u.username', $expr->literal(""))); + + $this->assertEquals("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = ''", $qb->getDQL()); + } + + /** + * @group DDC-1211 + */ + public function testEmptyNumericLiteral() + { + $expr = $this->_em->getExpressionBuilder(); + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u') + ->where($expr->eq('u.username', $expr->literal(0))); + + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 0', $qb->getDQL()); + } + + /** + * @group DDC-1227 + */ + public function testAddFromString() + { + $qb = $this->_em->createQueryBuilder() + ->add('select', 'u') + ->add('from', 'Doctrine\Tests\Models\CMS\CmsUser u'); + + $this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', $qb->getDQL()); + } + + /** + * @group DDC-1619 + */ + public function testAddDistinct() + { + $qb = $this->_em->createQueryBuilder() + ->select('u') + ->distinct() + ->from('Doctrine\Tests\Models\CMS\CmsUser', 'u'); + + $this->assertEquals('SELECT DISTINCT u FROM Doctrine\Tests\Models\CMS\CmsUser u', $qb->getDQL()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommandTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommandTest.php new file mode 100644 index 0000000..a170731 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommandTest.php @@ -0,0 +1,23 @@ +getMock('Doctrine\ORM\Tools\EntityGenerator'); + $metadataExporter = $this->getMock('Doctrine\ORM\Tools\Export\ClassMetadataExporter'); + $command = new ConvertDoctrine1SchemaCommand(); + $command->setEntityGenerator($entityGenerator); + + $output = $this->getMock('Symfony\Component\Console\Output\OutputInterface'); + $output->expects($this->once()) + ->method('write') + ->with($this->equalTo('No Metadata Classes to process.' . PHP_EOL)); + + $command->convertDoctrine1Schema($this->_getTestEntityManager(), array(), sys_get_temp_dir(), 'annotation', 4, null, $output); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/ConvertDoctrine1SchemaTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/ConvertDoctrine1SchemaTest.php new file mode 100644 index 0000000..c0af3a7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/ConvertDoctrine1SchemaTest.php @@ -0,0 +1,108 @@ +. + */ + +namespace Doctrine\Tests\ORM\Tools; + +use Doctrine\ORM\Tools\Export\ClassMetadataExporter; +use Doctrine\ORM\Tools\ConvertDoctrine1Schema; +use Doctrine\Tests\Mocks\MetadataDriverMock; +use Doctrine\Tests\Mocks\DatabasePlatformMock; +use Doctrine\Tests\Mocks\EntityManagerMock; +use Doctrine\Tests\Mocks\ConnectionMock; +use Doctrine\Tests\Mocks\DriverMock; +use Doctrine\Common\EventManager; +use Doctrine\ORM\Tools\DisconnectedClassMetadataFactory; + +require_once __DIR__ . '/../../TestInit.php'; + +/** + * Test case for converting a Doctrine 1 style schema to Doctrine 2 mapping files + * + * @author Jonathan H. Wage + * @author Roman Borschel setProxyDir(__DIR__ . '/../../Proxies'); + $config->setProxyNamespace('Doctrine\Tests\Proxies'); + $eventManager = new EventManager(); + $conn = new ConnectionMock(array(), $driverMock, $config, $eventManager); + $mockDriver = new MetadataDriverMock(); + $config->setMetadataDriverImpl($metadataDriver); + + return EntityManagerMock::create($conn, $config, $eventManager); + } + + public function testTest() + { + if ( ! class_exists('Symfony\Component\Yaml\Yaml', true)) { + $this->markTestSkipped('Please install Symfony YAML Component into the include path of your PHP installation.'); + } + + $cme = new ClassMetadataExporter(); + $converter = new ConvertDoctrine1Schema(__DIR__ . '/doctrine1schema'); + + $exporter = $cme->getExporter('yml', __DIR__ . '/convert'); + $exporter->setOverwriteExistingFiles(true); + $exporter->setMetadata($converter->getMetadata()); + $exporter->export(); + + $this->assertTrue(file_exists(__DIR__ . '/convert/User.dcm.yml')); + $this->assertTrue(file_exists(__DIR__ . '/convert/Profile.dcm.yml')); + + $metadataDriver = new \Doctrine\ORM\Mapping\Driver\YamlDriver(__DIR__ . '/convert'); + $em = $this->_createEntityManager($metadataDriver); + $cmf = new DisconnectedClassMetadataFactory(); + $cmf->setEntityManager($em); + $metadata = $cmf->getAllMetadata(); + $profileClass = $cmf->getMetadataFor('Profile'); + $userClass = $cmf->getMetadataFor('User'); + + $this->assertEquals(2, count($metadata)); + $this->assertEquals('Profile', $profileClass->name); + $this->assertEquals('User', $userClass->name); + $this->assertEquals(4, count($profileClass->fieldMappings)); + $this->assertEquals(5, count($userClass->fieldMappings)); + $this->assertEquals('text', $userClass->fieldMappings['clob']['type']); + $this->assertEquals('test_alias', $userClass->fieldMappings['theAlias']['columnName']); + $this->assertEquals('theAlias', $userClass->fieldMappings['theAlias']['fieldName']); + + $this->assertEquals('Profile', $profileClass->associationMappings['User']['sourceEntity']); + $this->assertEquals('User', $profileClass->associationMappings['User']['targetEntity']); + + $this->assertEquals('username', $userClass->table['uniqueConstraints']['username']['columns'][0]); + } + + public function tearDown() + { + @unlink(__DIR__ . '/convert/User.dcm.yml'); + @unlink(__DIR__ . '/convert/Profile.dcm.yml'); + @rmdir(__DIR__ . '/convert'); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php new file mode 100644 index 0000000..96d078c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/EntityGeneratorTest.php @@ -0,0 +1,444 @@ +_namespace = uniqid("doctrine_"); + $this->_tmpDir = \sys_get_temp_dir(); + \mkdir($this->_tmpDir . \DIRECTORY_SEPARATOR . $this->_namespace); + $this->_generator = new EntityGenerator(); + $this->_generator->setAnnotationPrefix(""); + $this->_generator->setGenerateAnnotations(true); + $this->_generator->setGenerateStubMethods(true); + $this->_generator->setRegenerateEntityIfExists(false); + $this->_generator->setUpdateEntityIfExists(true); + $this->_generator->setFieldVisibility(EntityGenerator::FIELD_VISIBLE_PROTECTED); + } + + public function tearDown() + { + $ri = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->_tmpDir . '/' . $this->_namespace)); + foreach ($ri AS $file) { + /* @var $file \SplFileInfo */ + if ($file->isFile()) { + \unlink($file->getPathname()); + } + } + rmdir($this->_tmpDir . '/' . $this->_namespace); + } + + public function generateBookEntityFixture() + { + $metadata = new ClassMetadataInfo($this->_namespace . '\EntityGeneratorBook'); + $metadata->namespace = $this->_namespace; + $metadata->customRepositoryClassName = $this->_namespace . '\EntityGeneratorBookRepository'; + + $metadata->table['name'] = 'book'; + $metadata->table['uniqueConstraints']['name_uniq'] = array('columns' => array('name')); + $metadata->table['indexes']['status_idx'] = array('columns' => array('status')); + $metadata->mapField(array('fieldName' => 'name', 'type' => 'string')); + $metadata->mapField(array('fieldName' => 'status', 'type' => 'string', 'default' => 'published')); + $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true)); + $metadata->mapOneToOne(array('fieldName' => 'author', 'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorAuthor', 'mappedBy' => 'book')); + $joinColumns = array( + array('name' => 'author_id', 'referencedColumnName' => 'id') + ); + $metadata->mapManyToMany(array( + 'fieldName' => 'comments', + 'targetEntity' => 'Doctrine\Tests\ORM\Tools\EntityGeneratorComment', + 'joinTable' => array( + 'name' => 'book_comment', + 'joinColumns' => array(array('name' => 'book_id', 'referencedColumnName' => 'id')), + 'inverseJoinColumns' => array(array('name' => 'comment_id', 'referencedColumnName' => 'id')), + ), + )); + $metadata->addLifecycleCallback('loading', 'postLoad'); + $metadata->addLifecycleCallback('willBeRemoved', 'preRemove'); + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); + + $this->_generator->writeEntityClass($metadata, $this->_tmpDir); + + return $metadata; + } + + private function generateEntityTypeFixture(array $field) + { + $metadata = new ClassMetadataInfo($this->_namespace . '\EntityType'); + $metadata->namespace = $this->_namespace; + + $metadata->table['name'] = 'entity_type'; + $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true)); + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); + + $name = $field['fieldName']; + $type = $field['dbType']; + $metadata->mapField(array('fieldName' => $name, 'type' => $type)); + + $this->_generator->writeEntityClass($metadata, $this->_tmpDir); + + return $metadata; + } + + /** + * @param ClassMetadataInfo $metadata + * @return EntityGeneratorBook + */ + public function newInstance($metadata) + { + $path = $this->_tmpDir . '/'. $this->_namespace . '/EntityGeneratorBook.php'; + $this->assertFileExists($path); + require_once $path; + + return new $metadata->name; + } + + public function testGeneratedEntityClass() + { + $metadata = $this->generateBookEntityFixture(); + + $book = $this->newInstance($metadata); + $this->assertTrue(class_exists($metadata->name), "Class does not exist."); + $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', '__construct'), "EntityGeneratorBook::__construct() missing."); + $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getId'), "EntityGeneratorBook::getId() missing."); + $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setName'), "EntityGeneratorBook::setName() missing."); + $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getName'), "EntityGeneratorBook::getName() missing."); + $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'setAuthor'), "EntityGeneratorBook::setAuthor() missing."); + $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getAuthor'), "EntityGeneratorBook::getAuthor() missing."); + $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'getComments'), "EntityGeneratorBook::getComments() missing."); + $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'addComment'), "EntityGeneratorBook::addComment() missing."); + $this->assertTrue(method_exists($metadata->namespace . '\EntityGeneratorBook', 'removeComment'), "EntityGeneratorBook::removeComment() missing."); + + $this->assertEquals('published', $book->getStatus()); + + $book->setName('Jonathan H. Wage'); + $this->assertEquals('Jonathan H. Wage', $book->getName()); + + $author = new EntityGeneratorAuthor(); + $book->setAuthor($author); + $this->assertEquals($author, $book->getAuthor()); + + $comment = new EntityGeneratorComment(); + $book->addComment($comment); + $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $book->getComments()); + $this->assertEquals(new \Doctrine\Common\Collections\ArrayCollection(array($comment)), $book->getComments()); + $book->removeComment($comment); + $this->assertEquals(new \Doctrine\Common\Collections\ArrayCollection(array()), $book->getComments()); + } + + public function testEntityUpdatingWorks() + { + $metadata = $this->generateBookEntityFixture(); + $metadata->mapField(array('fieldName' => 'test', 'type' => 'string')); + + $this->_generator->writeEntityClass($metadata, $this->_tmpDir); + + $this->assertFileExists($this->_tmpDir . "/" . $this->_namespace . "/EntityGeneratorBook.php~"); + + $book = $this->newInstance($metadata); + $reflClass = new \ReflectionClass($metadata->name); + + $this->assertTrue($reflClass->hasProperty('name'), "Regenerating keeps property 'name'."); + $this->assertTrue($reflClass->hasProperty('status'), "Regenerating keeps property 'status'."); + $this->assertTrue($reflClass->hasProperty('id'), "Regenerating keeps property 'id'."); + + $this->assertTrue($reflClass->hasProperty('test'), "Check for property test failed."); + $this->assertTrue($reflClass->getProperty('test')->isProtected(), "Check for protected property test failed."); + $this->assertTrue($reflClass->hasMethod('getTest'), "Check for method 'getTest' failed."); + $this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed."); + $this->assertTrue($reflClass->hasMethod('setTest'), "Check for method 'getTest' failed."); + $this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed."); + } + + public function testEntityExtendsStdClass() + { + $this->_generator->setClassToExtend('stdClass'); + $metadata = $this->generateBookEntityFixture(); + + $book = $this->newInstance($metadata); + $this->assertInstanceOf('stdClass', $book); + } + + public function testLifecycleCallbacks() + { + $metadata = $this->generateBookEntityFixture(); + + $book = $this->newInstance($metadata); + $reflClass = new \ReflectionClass($metadata->name); + + $this->assertTrue($reflClass->hasMethod('loading'), "Check for postLoad lifecycle callback."); + $this->assertTrue($reflClass->hasMethod('willBeRemoved'), "Check for preRemove lifecycle callback."); + } + + public function testLoadMetadata() + { + $metadata = $this->generateBookEntityFixture(); + + $book = $this->newInstance($metadata); + + $cm = new \Doctrine\ORM\Mapping\ClassMetadata($metadata->name); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $driver = $this->createAnnotationDriver(); + $driver->loadMetadataForClass($cm->name, $cm); + + $this->assertEquals($cm->columnNames, $metadata->columnNames); + $this->assertEquals($cm->getTableName(), $metadata->getTableName()); + $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks); + $this->assertEquals($cm->identifier, $metadata->identifier); + $this->assertEquals($cm->idGenerator, $metadata->idGenerator); + $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName); + } + + public function testLoadPrefixedMetadata() + { + $this->_generator->setAnnotationPrefix('ORM\\'); + $metadata = $this->generateBookEntityFixture(); + + $reader = new \Doctrine\Common\Annotations\AnnotationReader(); + $driver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, array()); + + $book = $this->newInstance($metadata); + + $cm = new \Doctrine\ORM\Mapping\ClassMetadata($metadata->name); + $cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService); + + $driver->loadMetadataForClass($cm->name, $cm); + + $this->assertEquals($cm->columnNames, $metadata->columnNames); + $this->assertEquals($cm->getTableName(), $metadata->getTableName()); + $this->assertEquals($cm->lifecycleCallbacks, $metadata->lifecycleCallbacks); + $this->assertEquals($cm->identifier, $metadata->identifier); + $this->assertEquals($cm->idGenerator, $metadata->idGenerator); + $this->assertEquals($cm->customRepositoryClassName, $metadata->customRepositoryClassName); + } + + /** + * @dataProvider getParseTokensInEntityFileData + */ + public function testParseTokensInEntityFile($php, $classes) + { + $r = new \ReflectionObject($this->_generator); + $m = $r->getMethod('parseTokensInEntityFile'); + $m->setAccessible(true); + + $p = $r->getProperty('staticReflection'); + $p->setAccessible(true); + + $ret = $m->invoke($this->_generator, $php); + $this->assertEquals($classes, array_keys($p->getValue($this->_generator))); + } + + /** + * @group DDC-1784 + */ + public function testGenerateEntityWithSequenceGenerator() + { + $metadata = new ClassMetadataInfo($this->_namespace . '\DDC1784Entity'); + $metadata->namespace = $this->_namespace; + $metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true)); + $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE); + $metadata->setSequenceGeneratorDefinition(array( + 'sequenceName' => 'DDC1784_ID_SEQ', + 'allocationSize' => 1, + 'initialValue' => 2 + )); + $this->_generator->writeEntityClass($metadata, $this->_tmpDir); + + $filename = $this->_tmpDir . DIRECTORY_SEPARATOR + . $this->_namespace . DIRECTORY_SEPARATOR . 'DDC1784Entity.php'; + + $this->assertFileExists($filename); + require_once $filename; + + + $reflection = new \ReflectionProperty($metadata->name, 'id'); + $docComment = $reflection->getDocComment(); + + $this->assertContains('@Id', $docComment); + $this->assertContains('@Column(name="id", type="integer")', $docComment); + $this->assertContains('@GeneratedValue(strategy="SEQUENCE")', $docComment); + $this->assertContains('@SequenceGenerator(sequenceName="DDC1784_ID_SEQ", allocationSize=1, initialValue=2)', $docComment); + } + + /** + * @dataProvider getEntityTypeAliasDataProvider + * + * @group DDC-1694 + */ + public function testEntityTypeAlias(array $field) + { + $metadata = $this->generateEntityTypeFixture($field); + $path = $this->_tmpDir . '/'. $this->_namespace . '/EntityType.php'; + + $this->assertFileExists($path); + require_once $path; + + $entity = new $metadata->name; + $reflClass = new \ReflectionClass($metadata->name); + + $type = $field['phpType']; + $name = $field['fieldName']; + $value = $field['value']; + $getter = "get" . ucfirst($name); + $setter = "set" . ucfirst($name); + + $this->assertPhpDocVarType($type, $reflClass->getProperty($name)); + $this->assertPhpDocParamType($type, $reflClass->getMethod($setter)); + $this->assertPhpDocReturnType($type, $reflClass->getMethod($getter)); + + $this->assertSame($entity, $entity->{$setter}($value)); + $this->assertEquals($value, $entity->{$getter}()); + } + + /** + * @return array + */ + public function getEntityTypeAliasDataProvider() + { + return array( + array(array( + 'fieldName' => 'datetimetz', + 'phpType' => '\\DateTime', + 'dbType' => 'datetimetz', + 'value' => new \DateTime + )), + array(array( + 'fieldName' => 'datetime', + 'phpType' => '\\DateTime', + 'dbType' => 'datetime', + 'value' => new \DateTime + )), + array(array( + 'fieldName' => 'date', + 'phpType' => '\\DateTime', + 'dbType' => 'date', + 'value' => new \DateTime + )), + array(array( + 'fieldName' => 'time', + 'phpType' => '\DateTime', + 'dbType' => 'time', + 'value' => new \DateTime + )), + array(array( + 'fieldName' => 'object', + 'phpType' => '\stdClass', + 'dbType' => 'object', + 'value' => new \stdClass() + )), + array(array( + 'fieldName' => 'bigint', + 'phpType' => 'integer', + 'dbType' => 'bigint', + 'value' => 11 + )), + array(array( + 'fieldName' => 'smallint', + 'phpType' => 'integer', + 'dbType' => 'smallint', + 'value' => 22 + )), + array(array( + 'fieldName' => 'text', + 'phpType' => 'string', + 'dbType' => 'text', + 'value' => 'text' + )), + array(array( + 'fieldName' => 'blob', + 'phpType' => 'string', + 'dbType' => 'blob', + 'value' => 'blob' + )), + array(array( + 'fieldName' => 'decimal', + 'phpType' => 'float', + 'dbType' => 'decimal', + 'value' => 33.33 + ), + )); + } + + public function getParseTokensInEntityFileData() + { + return array( + array( + 'assertEquals(1, preg_match('/@var\s+([^\s]+)/',$property->getDocComment(), $matches)); + $this->assertEquals($type, $matches[1]); + } + + /** + * @param string $type + * @param \ReflectionProperty $method + */ + private function assertPhpDocReturnType($type, \ReflectionMethod $method) + { + $this->assertEquals(1, preg_match('/@return\s+([^\s]+)/', $method->getDocComment(), $matches)); + $this->assertEquals($type, $matches[1]); + } + + /** + * @param string $type + * @param \ReflectionProperty $method + */ + private function assertPhpDocParamType($type, \ReflectionMethod $method) + { + $this->assertEquals(1, preg_match('/@param\s+([^\s]+)/', $method->getDocComment(), $matches)); + $this->assertEquals($type, $matches[1]); + } +} + +class EntityGeneratorAuthor {} +class EntityGeneratorComment {} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/AbstractClassMetadataExporterTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/AbstractClassMetadataExporterTest.php new file mode 100644 index 0000000..525bdaa --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/AbstractClassMetadataExporterTest.php @@ -0,0 +1,391 @@ +. + */ + +namespace Doctrine\Tests\ORM\Tools\Export; + +use Doctrine\ORM\Tools\Export\ClassMetadataExporter; +use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Tools\EntityGenerator; +use Doctrine\Tests\Mocks\MetadataDriverMock; +use Doctrine\Tests\Mocks\DatabasePlatformMock; +use Doctrine\Tests\Mocks\EntityManagerMock; +use Doctrine\Tests\Mocks\ConnectionMock; +use Doctrine\Tests\Mocks\DriverMock; +use Doctrine\Common\EventManager; +use Doctrine\ORM\Tools\DisconnectedClassMetadataFactory; +use Doctrine\ORM\Mapping\ClassMetadataFactory; + +require_once __DIR__ . '/../../../TestInit.php'; + +/** + * Test case for ClassMetadataExporter + * + * @author Jonathan H. Wage + * @author Roman Borschel setProxyDir(__DIR__ . '/../../Proxies'); + $config->setProxyNamespace('Doctrine\Tests\Proxies'); + $eventManager = new EventManager(); + $conn = new ConnectionMock(array(), $driverMock, $config, $eventManager); + $mockDriver = new MetadataDriverMock(); + $config->setMetadataDriverImpl($metadataDriver); + + return EntityManagerMock::create($conn, $config, $eventManager); + } + + protected function _createMetadataDriver($type, $path) + { + $mappingDriver = array( + 'php' => 'Doctrine\Common\Persistence\Mapping\Driver\PHPDriver', + 'annotation' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver', + 'xml' => 'Doctrine\ORM\Mapping\Driver\XmlDriver', + 'yaml' => 'Doctrine\ORM\Mapping\Driver\YamlDriver', + ); + $this->assertArrayHasKey($type, $mappingDriver, "There is no metadata driver for the type '" . $type . "'."); + $class = $mappingDriver[$type]; + + if ($type === 'annotation') { + $driver = $this->createAnnotationDriver(array($path)); + } else { + $driver = new $class($path); + } + return $driver; + } + + protected function _createClassMetadataFactory($em, $type) + { + if ($type === 'annotation') { + $factory = new ClassMetadataFactory(); + } else { + $factory = new DisconnectedClassMetadataFactory(); + } + $factory->setEntityManager($em); + return $factory; + } + + public function testExportDirectoryAndFilesAreCreated() + { + $this->_deleteDirectory(__DIR__ . '/export/'.$this->_getType()); + + $type = $this->_getType(); + $metadataDriver = $this->_createMetadataDriver($type, __DIR__ . '/' . $type); + $em = $this->_createEntityManager($metadataDriver); + $cmf = $this->_createClassMetadataFactory($em, $type); + $metadata = $cmf->getAllMetadata(); + + $metadata[0]->name = 'Doctrine\Tests\ORM\Tools\Export\ExportedUser'; + + $this->assertEquals('Doctrine\Tests\ORM\Tools\Export\ExportedUser', $metadata[0]->name); + + $type = $this->_getType(); + $cme = new ClassMetadataExporter(); + $exporter = $cme->getExporter($type, __DIR__ . '/export/' . $type); + if ($type === 'annotation') { + $entityGenerator = new EntityGenerator(); + $entityGenerator->setAnnotationPrefix(""); + $exporter->setEntityGenerator($entityGenerator); + } + $this->_extension = $exporter->getExtension(); + + $exporter->setMetadata($metadata); + $exporter->export(); + + if ($type == 'annotation') { + $this->assertTrue(file_exists(__DIR__ . '/export/' . $type . '/'.str_replace('\\', '/', 'Doctrine\Tests\ORM\Tools\Export\ExportedUser').$this->_extension)); + } else { + $this->assertTrue(file_exists(__DIR__ . '/export/' . $type . '/Doctrine.Tests.ORM.Tools.Export.ExportedUser'.$this->_extension)); + } + } + + /** + * @depends testExportDirectoryAndFilesAreCreated + */ + public function testExportedMetadataCanBeReadBackIn() + { + $type = $this->_getType(); + + $metadataDriver = $this->_createMetadataDriver($type, __DIR__ . '/export/' . $type); + $em = $this->_createEntityManager($metadataDriver); + $cmf = $this->_createClassMetadataFactory($em, $type); + $metadata = $cmf->getAllMetadata(); + + $this->assertEquals(1, count($metadata)); + + $class = current($metadata); + + $this->assertEquals('Doctrine\Tests\ORM\Tools\Export\ExportedUser', $class->name); + + return $class; + } + + /** + * @depends testExportedMetadataCanBeReadBackIn + * @param ClassMetadataInfo $class + */ + public function testTableIsExported($class) + { + $this->assertEquals('cms_users', $class->table['name']); + + return $class; + } + + /** + * @depends testTableIsExported + * @param ClassMetadataInfo $class + */ + public function testTypeIsExported($class) + { + $this->assertFalse($class->isMappedSuperclass); + + return $class; + } + + /** + * @depends testTypeIsExported + * @param ClassMetadataInfo $class + */ + public function testIdentifierIsExported($class) + { + $this->assertEquals(ClassMetadataInfo::GENERATOR_TYPE_IDENTITY, $class->generatorType); + $this->assertEquals(array('id'), $class->identifier); + $this->assertTrue(isset($class->fieldMappings['id']['id']) && $class->fieldMappings['id']['id'] === true); + + return $class; + } + + /** + * @depends testIdentifierIsExported + * @param ClassMetadataInfo $class + */ + public function testFieldsAreExported($class) + { + $this->assertTrue(isset($class->fieldMappings['id']['id']) && $class->fieldMappings['id']['id'] === true); + $this->assertEquals('id', $class->fieldMappings['id']['fieldName']); + $this->assertEquals('integer', $class->fieldMappings['id']['type']); + $this->assertEquals('id', $class->fieldMappings['id']['columnName']); + + $this->assertEquals('name', $class->fieldMappings['name']['fieldName']); + $this->assertEquals('string', $class->fieldMappings['name']['type']); + $this->assertEquals(50, $class->fieldMappings['name']['length']); + $this->assertEquals('name', $class->fieldMappings['name']['columnName']); + + $this->assertEquals('email', $class->fieldMappings['email']['fieldName']); + $this->assertEquals('string', $class->fieldMappings['email']['type']); + $this->assertEquals('user_email', $class->fieldMappings['email']['columnName']); + $this->assertEquals('CHAR(32) NOT NULL', $class->fieldMappings['email']['columnDefinition']); + + return $class; + } + + /** + * @depends testFieldsAreExported + * @param ClassMetadataInfo $class + */ + public function testOneToOneAssociationsAreExported($class) + { + $this->assertTrue(isset($class->associationMappings['address'])); + $this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Address', $class->associationMappings['address']['targetEntity']); + $this->assertEquals('address_id', $class->associationMappings['address']['joinColumns'][0]['name']); + $this->assertEquals('id', $class->associationMappings['address']['joinColumns'][0]['referencedColumnName']); + $this->assertEquals('CASCADE', $class->associationMappings['address']['joinColumns'][0]['onDelete']); + + $this->assertTrue($class->associationMappings['address']['isCascadeRemove']); + $this->assertTrue($class->associationMappings['address']['isCascadePersist']); + $this->assertFalse($class->associationMappings['address']['isCascadeRefresh']); + $this->assertFalse($class->associationMappings['address']['isCascadeMerge']); + $this->assertFalse($class->associationMappings['address']['isCascadeDetach']); + $this->assertTrue($class->associationMappings['address']['orphanRemoval']); + + return $class; + } + + /** + * @depends testFieldsAreExported + */ + public function testManyToOneAssociationsAreExported($class) + { + $this->assertTrue(isset($class->associationMappings['mainGroup'])); + $this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Group', $class->associationMappings['mainGroup']['targetEntity']); + } + + /** + * @depends testOneToOneAssociationsAreExported + * @param ClassMetadataInfo $class + */ + public function testOneToManyAssociationsAreExported($class) + { + $this->assertTrue(isset($class->associationMappings['phonenumbers'])); + //$this->assertInstanceOf('Doctrine\ORM\Mapping\OneToManyMapping', $class->associationMappings['phonenumbers']); + $this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Phonenumber', $class->associationMappings['phonenumbers']['targetEntity']); + $this->assertEquals('user', $class->associationMappings['phonenumbers']['mappedBy']); + $this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']['orderBy']); + + $this->assertTrue($class->associationMappings['phonenumbers']['isCascadeRemove']); + $this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']); + $this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']); + $this->assertTrue($class->associationMappings['phonenumbers']['isCascadeMerge']); + $this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']); + $this->assertTrue($class->associationMappings['phonenumbers']['orphanRemoval']); + + return $class; + } + + /** + * @depends testOneToManyAssociationsAreExported + * @param ClassMetadataInfo $metadata + */ + public function testManyToManyAssociationsAreExported($class) + { + $this->assertTrue(isset($class->associationMappings['groups'])); + //$this->assertInstanceOf('Doctrine\ORM\Mapping\ManyToManyMapping', $class->associationMappings['groups']); + $this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Group', $class->associationMappings['groups']['targetEntity']); + $this->assertEquals('cms_users_groups', $class->associationMappings['groups']['joinTable']['name']); + + $this->assertEquals('user_id', $class->associationMappings['groups']['joinTable']['joinColumns'][0]['name']); + $this->assertEquals('id', $class->associationMappings['groups']['joinTable']['joinColumns'][0]['referencedColumnName']); + + $this->assertEquals('group_id', $class->associationMappings['groups']['joinTable']['inverseJoinColumns'][0]['name']); + $this->assertEquals('id', $class->associationMappings['groups']['joinTable']['inverseJoinColumns'][0]['referencedColumnName']); + $this->assertEquals('INT NULL', $class->associationMappings['groups']['joinTable']['inverseJoinColumns'][0]['columnDefinition']); + + $this->assertTrue($class->associationMappings['groups']['isCascadeRemove']); + $this->assertTrue($class->associationMappings['groups']['isCascadePersist']); + $this->assertTrue($class->associationMappings['groups']['isCascadeRefresh']); + $this->assertTrue($class->associationMappings['groups']['isCascadeMerge']); + $this->assertTrue($class->associationMappings['groups']['isCascadeDetach']); + + return $class; + } + + /** + * @depends testManyToManyAssociationsAreExported + * @param ClassMetadataInfo $class + */ + public function testLifecycleCallbacksAreExported($class) + { + $this->assertTrue(isset($class->lifecycleCallbacks['prePersist'])); + $this->assertEquals(2, count($class->lifecycleCallbacks['prePersist'])); + $this->assertEquals('doStuffOnPrePersist', $class->lifecycleCallbacks['prePersist'][0]); + $this->assertEquals('doOtherStuffOnPrePersistToo', $class->lifecycleCallbacks['prePersist'][1]); + + $this->assertTrue(isset($class->lifecycleCallbacks['postPersist'])); + $this->assertEquals(1, count($class->lifecycleCallbacks['postPersist'])); + $this->assertEquals('doStuffOnPostPersist', $class->lifecycleCallbacks['postPersist'][0]); + + return $class; + } + + /** + * @depends testLifecycleCallbacksAreExported + * @param ClassMetadataInfo $class + */ + public function testCascadeIsExported($class) + { + $this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']); + $this->assertTrue($class->associationMappings['phonenumbers']['isCascadeMerge']); + $this->assertTrue($class->associationMappings['phonenumbers']['isCascadeRemove']); + $this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']); + $this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']); + $this->assertTrue($class->associationMappings['phonenumbers']['orphanRemoval']); + + return $class; + } + + /** + * @depends testCascadeIsExported + * @param ClassMetadataInfo $class + */ + public function testInversedByIsExported($class) + { + $this->assertEquals('user', $class->associationMappings['address']['inversedBy']); + } + /** + * @depends testExportDirectoryAndFilesAreCreated + */ + public function testCascadeAllCollapsed() + { + $type = $this->_getType(); + if ($type == 'xml') { + $xml = simplexml_load_file(__DIR__ . '/export/'.$type.'/Doctrine.Tests.ORM.Tools.Export.ExportedUser.dcm.xml'); + + $xml->registerXPathNamespace("d", "http://doctrine-project.org/schemas/orm/doctrine-mapping"); + $nodes = $xml->xpath("/d:doctrine-mapping/d:entity/d:one-to-many[@field='interests']/d:cascade/d:*"); + $this->assertEquals(1, count($nodes)); + + $this->assertEquals('cascade-all', $nodes[0]->getName()); + } elseif ($type == 'yaml') { + + $yaml = new \Symfony\Component\Yaml\Parser(); + $value = $yaml->parse(file_get_contents(__DIR__ . '/export/'.$type.'/Doctrine.Tests.ORM.Tools.Export.ExportedUser.dcm.yml')); + + $this->assertTrue(isset($value['Doctrine\Tests\ORM\Tools\Export\ExportedUser']['oneToMany']['interests']['cascade'])); + $this->assertEquals(1, count($value['Doctrine\Tests\ORM\Tools\Export\ExportedUser']['oneToMany']['interests']['cascade'])); + $this->assertEquals('all', $value['Doctrine\Tests\ORM\Tools\Export\ExportedUser']['oneToMany']['interests']['cascade'][0]); + + } else { + $this->markTestSkipped('Test aviable only for '.$type.' dirver'); + } + } + public function __destruct() + { +# $this->_deleteDirectory(__DIR__ . '/export/'.$this->_getType()); + } + + protected function _deleteDirectory($path) + { + if (is_file($path)) { + return unlink($path); + } else if (is_dir($path)) { + $files = glob(rtrim($path,'/').'/*'); + foreach ($files as $file){ + $this->_deleteDirectory($file); + } + return rmdir($path); + } + } +} + +class Address +{ + +} +class Phonenumber +{ + +} +class Group +{ + +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/AnnotationClassMetadataExporterTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/AnnotationClassMetadataExporterTest.php new file mode 100644 index 0000000..c60281c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/AnnotationClassMetadataExporterTest.php @@ -0,0 +1,42 @@ +. + */ + +namespace Doctrine\Tests\ORM\Tools\Export; + +require_once __DIR__ . '/../../../TestInit.php'; + +/** + * Test case for AnnotationClassMetadataExporterTest + * + * @author Jonathan H. Wage + * @author Roman Borschel . + */ + +namespace Doctrine\Tests\ORM\Tools\Export; + +require_once __DIR__ . '/../../../TestInit.php'; + +/** + * Test case for PhpClassMetadataExporterTest + * + * @author Jonathan H. Wage + * @author Roman Borschel . + */ + +namespace Doctrine\Tests\ORM\Tools\Export; + +require_once __DIR__ . '/../../../TestInit.php'; + +/** + * Test case for XmlClassMetadataExporterTest + * + * @author Jonathan H. Wage + * @author Roman Borschel . + */ + +namespace Doctrine\Tests\ORM\Tools\Export; + +require_once __DIR__ . '/../../../TestInit.php'; + +/** + * Test case for YamlClassMetadataExporterTest + * + * @author Jonathan H. Wage + * @author Roman Borschel markTestSkipped('Please install Symfony YAML Component into the include path of your PHP installation.'); + } + + return 'yaml'; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/annotation/Doctrine.Tests.ORM.Tools.Export.User.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/annotation/Doctrine.Tests.ORM.Tools.Export.User.php new file mode 100644 index 0000000..5a82cc6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/annotation/Doctrine.Tests.ORM.Tools.Export.User.php @@ -0,0 +1,73 @@ +setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE); +$metadata->setPrimaryTable(array( + 'name' => 'cms_users', + )); +$metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT); +$metadata->addLifecycleCallback('doStuffOnPrePersist', 'prePersist'); +$metadata->addLifecycleCallback('doOtherStuffOnPrePersistToo', 'prePersist'); +$metadata->addLifecycleCallback('doStuffOnPostPersist', 'postPersist'); +$metadata->mapField(array( + 'id' => true, + 'fieldName' => 'id', + 'type' => 'integer', + 'columnName' => 'id', + )); +$metadata->mapField(array( + 'fieldName' => 'name', + 'type' => 'string', + 'length' => 50, + 'unique' => true, + 'nullable' => true, + 'columnName' => 'name', + )); +$metadata->mapField(array( + 'fieldName' => 'email', + 'type' => 'string', + 'columnName' => 'user_email', + 'columnDefinition' => 'CHAR(32) NOT NULL', + )); +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); +$metadata->mapManyToOne(array( + 'fieldName' => 'mainGroup', + 'targetEntity' => 'Doctrine\\Tests\\ORM\Tools\\Export\\Group', +)); +$metadata->mapOneToOne(array( + 'fieldName' => 'address', + 'targetEntity' => 'Doctrine\\Tests\\ORM\\Tools\\Export\\Address', + 'inversedBy' => 'user', + 'cascade' => + array( + 0 => 'persist', + ), + 'mappedBy' => NULL, + 'joinColumns' => + array( + 0 => + array( + 'name' => 'address_id', + 'referencedColumnName' => 'id', + 'onDelete' => 'CASCADE', + ), + ), + 'orphanRemoval' => true, + )); +$metadata->mapOneToMany(array( + 'fieldName' => 'phonenumbers', + 'targetEntity' => 'Doctrine\\Tests\\ORM\\Tools\\Export\\Phonenumber', + 'cascade' => + array( + 1 => 'persist', + 2 => 'merge', + ), + 'mappedBy' => 'user', + 'orphanRemoval' => true, + 'orderBy' => + array( + 'number' => 'ASC', + ), + )); +$metadata->mapManyToMany(array( + 'fieldName' => 'groups', + 'targetEntity' => 'Doctrine\\Tests\\ORM\\Tools\\Export\\Group', + 'cascade' => + array( + 0 => 'remove', + 1 => 'persist', + 2 => 'refresh', + 3 => 'merge', + 4 => 'detach', + ), + 'mappedBy' => NULL, + 'joinTable' => + array( + 'name' => 'cms_users_groups', + 'joinColumns' => + array( + 0 => + array( + 'name' => 'user_id', + 'referencedColumnName' => 'id', + 'unique' => false, + 'nullable' => false, + ), + ), + 'inverseJoinColumns' => + array( + 0 => + array( + 'name' => 'group_id', + 'referencedColumnName' => 'id', + 'columnDefinition' => 'INT NULL', + ), + ), + ), + 'orderBy' => NULL, + )); diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml new file mode 100644 index 0000000..22d2852 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/yaml/Doctrine.Tests.ORM.Tools.Export.User.dcm.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/yaml/Doctrine.Tests.ORM.Tools.Export.User.dcm.yml new file mode 100644 index 0000000..25071d9 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Export/yaml/Doctrine.Tests.ORM.Tools.Export.User.dcm.yml @@ -0,0 +1,63 @@ +Doctrine\Tests\ORM\Tools\Export\User: + type: entity + table: cms_users + id: + id: + type: integer + generator: + strategy: AUTO + fields: + name: + type: string + length: 50 + nullable: true + unique: true + email: + type: string + column: user_email + columnDefinition: CHAR(32) NOT NULL + oneToOne: + address: + targetEntity: Doctrine\Tests\ORM\Tools\Export\Address + joinColumn: + name: address_id + referencedColumnName: id + onDelete: CASCADE + cascade: [ persist ] + inversedBy: user + orphanRemoval: true + manyToOne: + mainGroup: + targetEntity: Doctrine\Tests\ORM\Tools\Export\Group + oneToMany: + phonenumbers: + targetEntity: Doctrine\Tests\ORM\Tools\Export\Phonenumber + mappedBy: user + orderBy: + number: ASC + cascade: [ persist, merge ] + orphanRemoval: true + interests: + targetEntity: Doctrine\Tests\ORM\Tools\Export\Interests + mappedBy: user + cascade: [ persist, merge, remove, refresh, detach ] + orphanRemoval: true + manyToMany: + groups: + targetEntity: Doctrine\Tests\ORM\Tools\Export\Group + joinTable: + name: cms_users_groups + joinColumns: + user_id: + referencedColumnName: id + nullable: false + unique: false + inverseJoinColumns: + group_id: + referencedColumnName: id + columnDefinition: INT NULL + cascade: + - all + lifecycleCallbacks: + prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ] + postPersist: [ doStuffOnPostPersist ] diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/CountOutputWalkerTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/CountOutputWalkerTest.php new file mode 100644 index 0000000..688f101 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/CountOutputWalkerTest.php @@ -0,0 +1,45 @@ +entityManager->createQuery( + 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p JOIN p.category c JOIN p.author a'); + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker'); + $query->setFirstResult(null)->setMaxResults(null); + + $this->assertEquals( + "SELECT COUNT(*) AS dctrn_count FROM (SELECT DISTINCT id0 FROM (SELECT b0_.id AS id0, c1_.id AS id1, a2_.id AS id2, a2_.name AS name3, b0_.author_id AS author_id4, b0_.category_id AS category_id5 FROM BlogPost b0_ INNER JOIN Category c1_ ON b0_.category_id = c1_.id INNER JOIN Author a2_ ON b0_.author_id = a2_.id) dctrn_result) dctrn_table", $query->getSql() + ); + } + + public function testCountQuery_MixedResultsWithName() + { + $query = $this->entityManager->createQuery( + 'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a'); + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker'); + $query->setFirstResult(null)->setMaxResults(null); + + $this->assertEquals( + "SELECT COUNT(*) AS dctrn_count FROM (SELECT DISTINCT id0 FROM (SELECT a0_.id AS id0, a0_.name AS name1, sum(a0_.name) AS sclr2 FROM Author a0_) dctrn_result) dctrn_table", $query->getSql() + ); + } + + public function testCountQuery_Having() + { + $query = $this->entityManager->createQuery( + 'SELECT g, u, count(u.id) AS userCount FROM Doctrine\Tests\ORM\Tools\Pagination\Group g LEFT JOIN g.users u GROUP BY g.id HAVING userCount > 0'); + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker'); + $query->setFirstResult(null)->setMaxResults(null); + + $this->assertEquals( + "SELECT COUNT(*) AS dctrn_count FROM (SELECT DISTINCT id1 FROM (SELECT count(u0_.id) AS sclr0, g1_.id AS id1, u0_.id AS id2 FROM groups g1_ LEFT JOIN user_group u2_ ON g1_.id = u2_.group_id LEFT JOIN User u0_ ON u0_.id = u2_.user_id GROUP BY g1_.id HAVING sclr0 > 0) dctrn_result) dctrn_table", $query->getSql() + ); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/CountWalkerTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/CountWalkerTest.php new file mode 100644 index 0000000..405b63a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/CountWalkerTest.php @@ -0,0 +1,94 @@ +entityManager->createQuery( + 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p JOIN p.category c JOIN p.author a'); + $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker')); + $query->setHint(CountWalker::HINT_DISTINCT, true); + $query->setFirstResult(null)->setMaxResults(null); + + $this->assertEquals( + "SELECT count(DISTINCT b0_.id) AS sclr0 FROM BlogPost b0_ INNER JOIN Category c1_ ON b0_.category_id = c1_.id INNER JOIN Author a2_ ON b0_.author_id = a2_.id", $query->getSql() + ); + } + + public function testCountQuery_MixedResultsWithName() + { + $query = $this->entityManager->createQuery( + 'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a'); + $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker')); + $query->setHint(CountWalker::HINT_DISTINCT, true); + $query->setFirstResult(null)->setMaxResults(null); + + $this->assertEquals( + "SELECT count(DISTINCT a0_.id) AS sclr0 FROM Author a0_", $query->getSql() + ); + } + + public function testCountQuery_KeepsGroupBy() + { + $query = $this->entityManager->createQuery( + 'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost b GROUP BY b.id'); + $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker')); + $query->setHint(CountWalker::HINT_DISTINCT, true); + $query->setFirstResult(null)->setMaxResults(null); + + $this->assertEquals( + "SELECT count(DISTINCT b0_.id) AS sclr0 FROM BlogPost b0_ GROUP BY b0_.id", $query->getSql() + ); + } + + public function testCountQuery_RemovesOrderBy() + { + $query = $this->entityManager->createQuery( + 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p JOIN p.category c JOIN p.author a ORDER BY a.name'); + $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker')); + $query->setHint(CountWalker::HINT_DISTINCT, true); + $query->setFirstResult(null)->setMaxResults(null); + + $this->assertEquals( + "SELECT count(DISTINCT b0_.id) AS sclr0 FROM BlogPost b0_ INNER JOIN Category c1_ ON b0_.category_id = c1_.id INNER JOIN Author a2_ ON b0_.author_id = a2_.id", $query->getSql() + ); + } + + public function testCountQuery_RemovesLimits() + { + $query = $this->entityManager->createQuery( + 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p JOIN p.category c JOIN p.author a'); + $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker')); + $query->setHint(CountWalker::HINT_DISTINCT, true); + $query->setFirstResult(null)->setMaxResults(null); + + $this->assertEquals( + "SELECT count(DISTINCT b0_.id) AS sclr0 FROM BlogPost b0_ INNER JOIN Category c1_ ON b0_.category_id = c1_.id INNER JOIN Author a2_ ON b0_.author_id = a2_.id", $query->getSql() + ); + } + + public function testCountQuery_HavingException() + { + $query = $this->entityManager->createQuery( + "SELECT g, COUNT(u.id) AS userCount FROM Doctrine\Tests\Models\CMS\CmsGroup g LEFT JOIN g.users u GROUP BY g.id HAVING userCount > 0" + ); + $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker')); + $query->setFirstResult(null)->setMaxResults(null); + + $this->setExpectedException( + 'RuntimeException', + 'Cannot count query that uses a HAVING clause. Use the output walkers for pagination' + ); + + $query->getSql(); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php new file mode 100644 index 0000000..92c262c --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php @@ -0,0 +1,33 @@ +entityManager->createQuery( + 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a'); + $limitQuery = clone $query; + $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker'); + + $this->assertEquals( + "SELECT DISTINCT id0 FROM (SELECT m0_.id AS id0, c1_.id AS id1, a2_.id AS id2, a2_.name AS name3, m0_.author_id AS author_id4, m0_.category_id AS category_id5 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result", $limitQuery->getSql() + ); + } + + public function testCountQuery_MixedResultsWithName() + { + $query = $this->entityManager->createQuery( + 'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a'); + $limitQuery = clone $query; + $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker'); + + $this->assertEquals( + "SELECT DISTINCT id0 FROM (SELECT a0_.id AS id0, a0_.name AS name1, sum(a0_.name) AS sclr2 FROM Author a0_) dctrn_result", $limitQuery->getSql() + ); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryWalkerTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryWalkerTest.php new file mode 100644 index 0000000..2fd6046 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryWalkerTest.php @@ -0,0 +1,36 @@ +entityManager->createQuery( + 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a'); + $limitQuery = clone $query; + $limitQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker')); + + $this->assertEquals( + "SELECT DISTINCT m0_.id AS id0 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id", $limitQuery->getSql() + ); + } + + public function testCountQuery_MixedResultsWithName() + { + $query = $this->entityManager->createQuery( + 'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a'); + $limitQuery = clone $query; + $limitQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker')); + + $this->assertEquals( + "SELECT DISTINCT a0_.id AS id0, sum(a0_.name) AS sclr1 FROM Author a0_", $limitQuery->getSql() + ); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/PaginationTestCase.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/PaginationTestCase.php new file mode 100644 index 0000000..a6e4c67 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/PaginationTestCase.php @@ -0,0 +1,142 @@ +entityManager = $this->_getTestEntityManager(); + } +} + + +/** +* @Entity +*/ +class MyBlogPost +{ + + /** @Id @column(type="integer") @generatedValue */ + public $id; + /** + * @ManyToOne(targetEntity="Author") + */ + public $author; + /** + * @ManyToOne(targetEntity="Category") + */ + public $category; +} + +/** + * @Entity + */ +class MyAuthor +{ + + /** @Id @column(type="integer") @generatedValue */ + public $id; + +} + +/** +* @Entity +*/ +class MyCategory +{ + + /** @id @column(type="integer") @generatedValue */ + public $id; + +} + + +/** + * @Entity + */ +class BlogPost +{ + + /** @Id @column(type="integer") @generatedValue */ + public $id; + /** + * @ManyToOne(targetEntity="Author") + */ + public $author; + /** + * @ManyToOne(targetEntity="Category") + */ + public $category; +} + +/** + * @Entity + */ +class Author +{ + + /** @Id @column(type="integer") @generatedValue */ + public $id; + /** @Column(type="string") */ + public $name; + +} + +/** + * @Entity + */ +class Person +{ + + /** @Id @column(type="integer") @generatedValue */ + public $id; + /** @Column(type="string") */ + public $name; + /** @Column(type="string") */ + public $biography; + +} + +/** + * @Entity + */ +class Category +{ + + /** @id @column(type="integer") @generatedValue */ + public $id; + +} + + +/** @Entity @Table(name="groups") */ +class Group +{ + + /** @Id @column(type="integer") @generatedValue */ + public $id; + /** @ManyToMany(targetEntity="User", mappedBy="groups") */ + public $users; +} + +/** @Entity */ +class User +{ + + /** @Id @column(type="integer") @generatedValue */ + public $id; + /** + * @ManyToMany(targetEntity="Group", inversedBy="users") + * @JoinTable( + * name="user_group", + * joinColumns = {@JoinColumn(name="user_id", referencedColumnName="id")}, + * inverseJoinColumns = {@JoinColumn(name="group_id", referencedColumnName="id")} + * ) + */ + public $groups; +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/WhereInWalkerTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/WhereInWalkerTest.php new file mode 100644 index 0000000..b813c62 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/Pagination/WhereInWalkerTest.php @@ -0,0 +1,125 @@ +entityManager->createQuery( + 'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g' + ); + $whereInQuery = clone $query; + $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker')); + $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10); + + $this->assertEquals( + "SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql() + ); + } + + public function testCountQuery_MixedResultsWithName() + { + $query = $this->entityManager->createQuery( + 'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a' + ); + $whereInQuery = clone $query; + $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker')); + $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10); + + $this->assertEquals( + "SELECT a0_.id AS id0, a0_.name AS name1, sum(a0_.name) AS sclr2 FROM Author a0_ WHERE a0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql() + ); + } + + public function testWhereInQuery_SingleWhere() + { + $query = $this->entityManager->createQuery( + 'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE 1 = 1' + ); + $whereInQuery = clone $query; + $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker')); + $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10); + + $this->assertEquals( + "SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE 1 = 1 AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql() + ); + } + + public function testWhereInQuery_MultipleWhereWithAnd() + { + $query = $this->entityManager->createQuery( + 'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE 1 = 1 AND 2 = 2' + ); + $whereInQuery = clone $query; + $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker')); + $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10); + + $this->assertEquals( + "SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE 1 = 1 AND 2 = 2 AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql() + ); + } + + public function testWhereInQuery_MultipleWhereWithOr() + { + $query = $this->entityManager->createQuery( + 'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE 1 = 1 OR 2 = 2' + ); + $whereInQuery = clone $query; + $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker')); + $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10); + + $this->assertEquals( + "SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE (1 = 1 OR 2 = 2) AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql() + ); + } + + public function testWhereInQuery_MultipleWhereWithMixed_1() + { + $query = $this->entityManager->createQuery( + 'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE (1 = 1 OR 2 = 2) AND 3 = 3' + ); + $whereInQuery = clone $query; + $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker')); + $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10); + + $this->assertEquals( + "SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE (1 = 1 OR 2 = 2) AND 3 = 3 AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql() + ); + } + + public function testWhereInQuery_MultipleWhereWithMixed_2() + { + $query = $this->entityManager->createQuery( + 'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE 1 = 1 AND 2 = 2 OR 3 = 3' + ); + $whereInQuery = clone $query; + $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker')); + $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10); + + $this->assertEquals( + "SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE (1 = 1 AND 2 = 2 OR 3 = 3) AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql() + ); + } + + public function testWhereInQuery_WhereNot() + { + $query = $this->entityManager->createQuery( + 'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE NOT 1 = 2' + ); + $whereInQuery = clone $query; + $whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker')); + $whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10); + + $this->assertEquals( + "SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE (NOT 1 = 2) AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql() + ); + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/ResolveTargetEntityListenerTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/ResolveTargetEntityListenerTest.php new file mode 100644 index 0000000..3cb627f --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/ResolveTargetEntityListenerTest.php @@ -0,0 +1,129 @@ +createAnnotationDriver(); + + $this->em = $this->_getTestEntityManager(); + $this->em->getConfiguration()->setMetadataDriverImpl($annotationDriver); + $this->factory = new ClassMetadataFactory; + $this->factory->setEntityManager($this->em); + $this->listener = new ResolveTargetEntityListener; + } + + /** + * @group DDC-1544 + */ + public function testResolveTargetEntityListenerCanResolveTargetEntity() + { + $evm = $this->em->getEventManager(); + $this->listener->addResolveTargetEntity( + 'Doctrine\Tests\ORM\Tools\ResolveTargetInterface', + 'Doctrine\Tests\ORM\Tools\ResolveTargetEntity', + array() + ); + $this->listener->addResolveTargetEntity( + 'Doctrine\Tests\ORM\Tools\TargetInterface', + 'Doctrine\Tests\ORM\Tools\TargetEntity', + array() + ); + $evm->addEventListener(Events::loadClassMetadata, $this->listener); + $cm = $this->factory->getMetadataFor('Doctrine\Tests\ORM\Tools\ResolveTargetEntity'); + $meta = $cm->associationMappings; + $this->assertSame('Doctrine\Tests\ORM\Tools\TargetEntity', $meta['manyToMany']['targetEntity']); + $this->assertSame('Doctrine\Tests\ORM\Tools\ResolveTargetEntity', $meta['manyToOne']['targetEntity']); + $this->assertSame('Doctrine\Tests\ORM\Tools\ResolveTargetEntity', $meta['oneToMany']['targetEntity']); + $this->assertSame('Doctrine\Tests\ORM\Tools\TargetEntity', $meta['oneToOne']['targetEntity']); + } +} + +interface ResolveTargetInterface +{ + public function getId(); +} + +interface TargetInterface extends ResolveTargetInterface +{ +} + +/** + * @Entity + */ +class ResolveTargetEntity implements ResolveTargetInterface +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @ManyToMany(targetEntity="Doctrine\Tests\ORM\Tools\TargetInterface") + */ + private $manyToMany; + + /** + * @ManyToOne(targetEntity="Doctrine\Tests\ORM\Tools\ResolveTargetInterface", inversedBy="oneToMany") + */ + private $manyToOne; + + /** + * @OneToMany(targetEntity="Doctrine\Tests\ORM\Tools\ResolveTargetInterface", mappedBy="manyToOne") + */ + private $oneToMany; + + /** + * @OneToOne(targetEntity="Doctrine\Tests\ORM\Tools\TargetInterface") + * @JoinColumn(name="target_entity_id", referencedColumnName="id") + */ + private $oneToOne; + + public function getId() + { + return $this->id; + } +} + +/** + * @Entity + */ +class TargetEntity implements TargetInterface +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + public function getId() + { + return $this->id; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SchemaToolTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SchemaToolTest.php new file mode 100644 index 0000000..66093a3 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SchemaToolTest.php @@ -0,0 +1,135 @@ +_getTestEntityManager(); + $schemaTool = new SchemaTool($em); + + $classes = array( + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsComment'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsEmployee'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), + ); + + $schema = $schemaTool->getSchemaFromMetadata($classes); + + $this->assertTrue($schema->hasTable('cms_users'), "Table cms_users should exist."); + $this->assertTrue($schema->getTable('cms_users')->columnsAreIndexed(array('username')), "username column should be indexed."); + } + + public function testAnnotationOptionsAttribute() + { + $em = $this->_getTestEntityManager(); + $schemaTool = new SchemaTool($em); + + $classes = array( + $em->getClassMetadata(__NAMESPACE__ . '\\TestEntityWithAnnotationOptionsAttribute'), + ); + + $schema = $schemaTool->getSchemaFromMetadata($classes); + + $expected = array('foo' => 'bar', 'baz' => array('key' => 'val')); + + $this->assertEquals($expected, $schema->getTable('TestEntityWithAnnotationOptionsAttribute')->getOptions(), "options annotation are passed to the tables optionss"); + $this->assertEquals($expected, $schema->getTable('TestEntityWithAnnotationOptionsAttribute')->getColumn('test')->getCustomSchemaOptions(), "options annotation are passed to the columns customSchemaOptions"); + } + + /** + * @group DDC-200 + */ + public function testPassColumnDefinitionToJoinColumn() + { + $customColumnDef = "MEDIUMINT(6) UNSIGNED NOT NULL"; + + $em = $this->_getTestEntityManager(); + $schemaTool = new SchemaTool($em); + + $avatar = $em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumAvatar'); + $avatar->fieldMappings['id']['columnDefinition'] = $customColumnDef; + $user = $em->getClassMetadata('Doctrine\Tests\Models\Forum\ForumUser'); + + $classes = array($avatar, $user); + + $schema = $schemaTool->getSchemaFromMetadata($classes); + + $this->assertTrue($schema->hasTable('forum_users')); + $table = $schema->getTable("forum_users"); + $this->assertTrue($table->hasColumn('avatar_id')); + $this->assertEquals($customColumnDef, $table->getColumn('avatar_id')->getColumnDefinition()); + } + + /** + * @group DDC-283 + */ + public function testPostGenerateEvents() + { + $listener = new GenerateSchemaEventListener(); + + $em = $this->_getTestEntityManager(); + $em->getEventManager()->addEventListener( + array(ToolEvents::postGenerateSchemaTable, ToolEvents::postGenerateSchema), $listener + ); + $schemaTool = new SchemaTool($em); + + $classes = array( + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsArticle'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsComment'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsEmployee'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), + $em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), + ); + + $schema = $schemaTool->getSchemaFromMetadata($classes); + + $this->assertEquals(count($classes), $listener->tableCalls); + $this->assertTrue($listener->schemaCalled); + } +} + +/** + * @Entity + * @Table(options={"foo": "bar", "baz": {"key": "val"}}) + */ +class TestEntityWithAnnotationOptionsAttribute +{ + /** @Id @Column */ + private $id; + + /** + * @Column(type="string", options={"foo": "bar", "baz": {"key": "val"}}) + */ + private $test; +} + +class GenerateSchemaEventListener +{ + public $tableCalls = 0; + public $schemaCalled = false; + + public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs) + { + $this->tableCalls++; + } + + public function postGenerateSchema(GenerateSchemaEventArgs $eventArgs) + { + $this->schemaCalled = true; + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php new file mode 100644 index 0000000..6f2e912 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php @@ -0,0 +1,267 @@ +em = $this->_getTestEntityManager(); + $this->validator = new SchemaValidator($this->em); + } + + public function testCmsModelSet() + { + $this->em->getConfiguration()->getMetadataDriverImpl()->addPaths(array( + __DIR__ . "/../../Models/CMS" + )); + $this->validator->validateMapping(); + } + + public function testCompanyModelSet() + { + $this->em->getConfiguration()->getMetadataDriverImpl()->addPaths(array( + __DIR__ . "/../../Models/Company" + )); + $this->validator->validateMapping(); + } + + public function testECommerceModelSet() + { + $this->em->getConfiguration()->getMetadataDriverImpl()->addPaths(array( + __DIR__ . "/../../Models/ECommerce" + )); + $this->validator->validateMapping(); + } + + public function testForumModelSet() + { + $this->em->getConfiguration()->getMetadataDriverImpl()->addPaths(array( + __DIR__ . "/../../Models/Forum" + )); + $this->validator->validateMapping(); + } + + public function testNavigationModelSet() + { + $this->em->getConfiguration()->getMetadataDriverImpl()->addPaths(array( + __DIR__ . "/../../Models/Navigation" + )); + $this->validator->validateMapping(); + } + + public function testRoutingModelSet() + { + $this->em->getConfiguration()->getMetadataDriverImpl()->addPaths(array( + __DIR__ . "/../../Models/Routing" + )); + $this->validator->validateMapping(); + } + + /** + * @group DDC-1439 + */ + public function testInvalidManyToManyJoinColumnSchema() + { + $class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity1'); + $class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity2'); + + $ce = $this->validator->validateClass($class1); + + $this->assertEquals( + array( + "The inverse join columns of the many-to-many table 'Entity1Entity2' have to contain to ALL identifier columns of the target entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key4' are missing.", + "The join columns of the many-to-many table 'Entity1Entity2' have to contain to ALL identifier columns of the source entity 'Doctrine\Tests\ORM\Tools\InvalidEntity1', however 'key2' are missing." + ), + $ce + ); + } + + /** + * @group DDC-1439 + */ + public function testInvalidToOneJoinColumnSchema() + { + $class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity1'); + $class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity2'); + + $ce = $this->validator->validateClass($class2); + + $this->assertEquals( + array( + "The referenced column name 'id' has to be a primary key column on the target entity class 'Doctrine\Tests\ORM\Tools\InvalidEntity1'.", + "The join columns of the association 'assoc' have to match to ALL identifier columns of the target entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key1, key2' are missing." + ), + $ce + ); + } + + /** + * @group DDC-1587 + */ + public function testValidOneToOneAsIdentifierSchema() + { + $class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\DDC1587ValidEntity2'); + $class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\DDC1587ValidEntity1'); + + $ce = $this->validator->validateClass($class1); + + $this->assertEquals(array(), $ce); + } + + /** + * @group DDC-1649 + */ + public function testInvalidTripleAssociationAsKeyMapping() + { + $classThree = $this->em->getClassMetadata(__NAMESPACE__ . '\DDC1649Three'); + $ce = $this->validator->validateClass($classThree); + + $this->assertEquals(Array( + "Cannot map association 'Doctrine\Tests\ORM\Tools\DDC1649Three#two as identifier, because the target entity 'Doctrine\Tests\ORM\Tools\DDC1649Two' also maps an association as identifier.", + "The referenced column name 'id' has to be a primary key column on the target entity class 'Doctrine\Tests\ORM\Tools\DDC1649Two'." + ), $ce); + } +} + +/** + * @Entity + */ +class InvalidEntity1 +{ + /** + * @Id @Column + */ + protected $key1; + /** + * @Id @Column + */ + protected $key2; + /** + * @ManyToMany (targetEntity="InvalidEntity2") + * @JoinTable (name="Entity1Entity2", + * joinColumns={@JoinColumn(name="key1", referencedColumnName="key1")}, + * inverseJoinColumns={@JoinColumn(name="key3", referencedColumnName="key3")} + * ) + */ + protected $entity2; +} + +/** + * @Entity + */ +class InvalidEntity2 +{ + /** + * @Id @Column + */ + protected $key3; + + /** + * @Id @Column + */ + protected $key4; + + /** + * @ManyToOne(targetEntity="InvalidEntity1") + */ + protected $assoc; +} + +/** + * @Entity(repositoryClass="Entity\Repository\Agent") + * @Table(name="agent") + */ +class DDC1587ValidEntity1 +{ + /** + * @var int + * + * @Id @GeneratedValue + * @Column(name="pk", type="integer") + */ + private $pk; + + /** + * @var string + * + * @Column(name="name", type="string", length=32) + */ + private $name; + + /** + * @var Identifier + * + * @OneToOne(targetEntity="DDC1587ValidEntity2", cascade={"all"}, mappedBy="agent") + * @JoinColumn(name="pk", referencedColumnName="pk_agent") + */ + private $identifier; +} + +/** + * @Entity + * @Table + */ +class DDC1587ValidEntity2 +{ + /** + * @var DDC1587ValidEntity1 + * + * @Id + * @OneToOne(targetEntity="DDC1587ValidEntity1", inversedBy="identifier") + * @JoinColumn(name="pk_agent", referencedColumnName="pk", nullable=false) + */ + private $agent; + + /** + * @var string + * + * @Column(name="num", type="string", length=16, nullable=true) + */ + private $num; +} + +/** + * @Entity + */ +class DDC1649One +{ + /** + * @Id @Column @GeneratedValue + */ + public $id; +} + +/** + * @Entity + */ +class DDC1649Two +{ + /** @Id @ManyToOne(targetEntity="DDC1649One")@JoinColumn(name="id", referencedColumnName="id") */ + public $one; +} + +/** + * @Entity + */ +class DDC1649Three +{ + /** @Id @ManyToOne(targetEntity="DDC1649Two") @JoinColumn(name="id", + * referencedColumnName="id") */ + private $two; +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SetupTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SetupTest.php new file mode 100644 index 0000000..50db4b2 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/SetupTest.php @@ -0,0 +1,110 @@ +markTestSkipped("Test only runs in a dev-installation from Github"); + } + + $this->originalAutoloaderCount = count(spl_autoload_functions()); + $this->originalIncludePath = get_include_path(); + } + + public function tearDown() + { + if ( ! $this->originalIncludePath) { + return; + } + + set_include_path($this->originalIncludePath); + $loaders = spl_autoload_functions(); + for ($i = 0; $i < count($loaders); $i++) { + if ($i > $this->originalAutoloaderCount+1) { + spl_autoload_unregister($loaders[$i]); + } + } + } + + public function testGitAutoload() + { + Setup::registerAutoloadGit(__DIR__ . "/../../../../../"); + + $this->assertEquals($this->originalAutoloaderCount + 4, count(spl_autoload_functions())); + } + + public function testPEARAutoload() + { + set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . "/../../../../../lib/vendor/doctrine-common/lib"); + + Setup::registerAutoloadPEAR(); + + $this->assertEquals($this->originalAutoloaderCount + 2, count(spl_autoload_functions())); + } + + public function testDirectoryAutoload() + { + Setup::registerAutoloadDirectory(__DIR__ . "/../../../../../lib/vendor/doctrine-common/lib"); + + $this->assertEquals($this->originalAutoloaderCount + 2, count(spl_autoload_functions())); + } + + public function testAnnotationConfiguration() + { + $config = Setup::createAnnotationMetadataConfiguration(array(), true); + + $this->assertInstanceOf('Doctrine\ORM\Configuration', $config); + $this->assertEquals(sys_get_temp_dir(), $config->getProxyDir()); + $this->assertEquals('DoctrineProxies', $config->getProxyNamespace()); + $this->assertInstanceOf('Doctrine\ORM\Mapping\Driver\AnnotationDriver', $config->getMetadataDriverImpl()); + } + + public function testXMLConfiguration() + { + $config = Setup::createXMLMetadataConfiguration(array(), true); + + $this->assertInstanceOf('Doctrine\ORM\Configuration', $config); + $this->assertInstanceOf('Doctrine\ORM\Mapping\Driver\XmlDriver', $config->getMetadataDriverImpl()); + } + + public function testYAMLConfiguration() + { + $config = Setup::createYAMLMetadataConfiguration(array(), true); + + $this->assertInstanceOf('Doctrine\ORM\Configuration', $config); + $this->assertInstanceOf('Doctrine\ORM\Mapping\Driver\YamlDriver', $config->getMetadataDriverImpl()); + } + + /** + * @group DDC-1350 + */ + public function testConfigureProxyDir() + { + $config = Setup::createAnnotationMetadataConfiguration(array(), true, "/foo"); + $this->assertEquals('/foo', $config->getProxyDir()); + } + + /** + * @group DDC-1350 + */ + public function testConfigureCache() + { + $cache = new ArrayCache(); + $config = Setup::createAnnotationMetadataConfiguration(array(), true, null, $cache); + + $this->assertSame($cache, $config->getResultCacheImpl()); + $this->assertSame($cache, $config->getMetadataCacheImpl()); + $this->assertSame($cache, $config->getQueryCacheImpl()); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/doctrine1schema/schema.yml b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/doctrine1schema/schema.yml new file mode 100644 index 0000000..efa24c7 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/Tools/doctrine1schema/schema.yml @@ -0,0 +1,28 @@ +User: + tableName: users + columns: + username: + type: string(255) + length: 100 + notnull: true + unique: true + password: + type: string(255) + clob: clob + test_alias as theAlias: + type: string(255) + indexes: + username: + fields: [username] + type: unique + +Profile: + columns: + first_name: string(255) + last_name: string(255) + user_id: integer + relations: + User: + onDelete: CASCADE + foreignType: one + type: one \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php new file mode 100644 index 0000000..9cc20ad --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php @@ -0,0 +1,312 @@ +_connectionMock = new ConnectionMock(array(), new \Doctrine\Tests\Mocks\DriverMock()); + $this->_emMock = EntityManagerMock::create($this->_connectionMock); + // SUT + $this->_unitOfWork = new UnitOfWorkMock($this->_emMock); + $this->_emMock->setUnitOfWork($this->_unitOfWork); + } + + protected function tearDown() { + } + + public function testRegisterRemovedOnNewEntityIsIgnored() + { + $user = new ForumUser(); + $user->username = 'romanb'; + $this->assertFalse($this->_unitOfWork->isScheduledForDelete($user)); + $this->_unitOfWork->scheduleForDelete($user); + $this->assertFalse($this->_unitOfWork->isScheduledForDelete($user)); + } + + + /* Operational tests */ + + public function testSavingSingleEntityWithIdentityColumnForcesInsert() + { + // Setup fake persister and id generator for identity generation + $userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser")); + $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister); + //$idGeneratorMock = new IdentityIdGeneratorMock($this->_emMock); + //$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $idGeneratorMock); + $userPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY); + + // Test + $user = new ForumUser(); + $user->username = 'romanb'; + $this->_unitOfWork->persist($user); + + // Check + $this->assertEquals(0, count($userPersister->getInserts())); + $this->assertEquals(0, count($userPersister->getUpdates())); + $this->assertEquals(0, count($userPersister->getDeletes())); + $this->assertFalse($this->_unitOfWork->isInIdentityMap($user)); + // should no longer be scheduled for insert + $this->assertTrue($this->_unitOfWork->isScheduledForInsert($user)); + + // Now lets check whether a subsequent commit() does anything + $userPersister->reset(); + + // Test + $this->_unitOfWork->commit(); + + // Check. + $this->assertEquals(1, count($userPersister->getInserts())); + $this->assertEquals(0, count($userPersister->getUpdates())); + $this->assertEquals(0, count($userPersister->getDeletes())); + + // should have an id + $this->assertTrue(is_numeric($user->id)); + } + + /** + * Tests a scenario where a save() operation is cascaded from a ForumUser + * to its associated ForumAvatar, both entities using IDENTITY id generation. + */ + public function testCascadedIdentityColumnInsert() + { + // Setup fake persister and id generator for identity generation + //ForumUser + $userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser")); + $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister); + //$userIdGeneratorMock = new IdentityIdGeneratorMock($this->_emMock); + //$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumUser', $userIdGeneratorMock); + $userPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY); + // ForumAvatar + $avatarPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumAvatar")); + $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarPersister); + //$avatarIdGeneratorMock = new IdentityIdGeneratorMock($this->_emMock); + //$this->_emMock->setIdGenerator('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarIdGeneratorMock); + $avatarPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY); + + // Test + $user = new ForumUser(); + $user->username = 'romanb'; + $avatar = new ForumAvatar(); + $user->avatar = $avatar; + $this->_unitOfWork->persist($user); // save cascaded to avatar + + $this->_unitOfWork->commit(); + + $this->assertTrue(is_numeric($user->id)); + $this->assertTrue(is_numeric($avatar->id)); + + $this->assertEquals(1, count($userPersister->getInserts())); + $this->assertEquals(0, count($userPersister->getUpdates())); + $this->assertEquals(0, count($userPersister->getDeletes())); + + $this->assertEquals(1, count($avatarPersister->getInserts())); + $this->assertEquals(0, count($avatarPersister->getUpdates())); + $this->assertEquals(0, count($avatarPersister->getDeletes())); + } + + public function testChangeTrackingNotify() + { + $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\ORM\NotifyChangedEntity")); + $this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedEntity', $persister); + $itemPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\ORM\NotifyChangedRelatedItem")); + $this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedRelatedItem', $itemPersister); + + $entity = new NotifyChangedEntity; + $entity->setData('thedata'); + $this->_unitOfWork->persist($entity); + + $this->_unitOfWork->commit(); + $this->assertEquals(1, count($persister->getInserts())); + $persister->reset(); + + $this->assertTrue($this->_unitOfWork->isInIdentityMap($entity)); + + $entity->setData('newdata'); + $entity->setTransient('newtransientvalue'); + + $this->assertTrue($this->_unitOfWork->isScheduledForDirtyCheck($entity)); + + $this->assertEquals(array('data' => array('thedata', 'newdata')), $this->_unitOfWork->getEntityChangeSet($entity)); + + $item = new NotifyChangedRelatedItem(); + $entity->getItems()->add($item); + $item->setOwner($entity); + $this->_unitOfWork->persist($item); + + $this->_unitOfWork->commit(); + $this->assertEquals(1, count($itemPersister->getInserts())); + $persister->reset(); + $itemPersister->reset(); + + + $entity->getItems()->removeElement($item); + $item->setOwner(null); + $this->assertTrue($entity->getItems()->isDirty()); + $this->_unitOfWork->commit(); + $updates = $itemPersister->getUpdates(); + $this->assertEquals(1, count($updates)); + $this->assertTrue($updates[0] === $item); + } + + public function testGetEntityStateOnVersionedEntityWithAssignedIdentifier() + { + $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\ORM\VersionedAssignedIdentifierEntity")); + $this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\VersionedAssignedIdentifierEntity', $persister); + + $e = new VersionedAssignedIdentifierEntity(); + $e->id = 42; + $this->assertEquals(UnitOfWork::STATE_NEW, $this->_unitOfWork->getEntityState($e)); + $this->assertFalse($persister->isExistsCalled()); + } + + public function testGetEntityStateWithAssignedIdentity() + { + $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\CMS\CmsPhonenumber")); + $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\CMS\CmsPhonenumber', $persister); + + $ph = new \Doctrine\Tests\Models\CMS\CmsPhonenumber(); + $ph->phonenumber = '12345'; + + $this->assertEquals(UnitOfWork::STATE_NEW, $this->_unitOfWork->getEntityState($ph)); + $this->assertTrue($persister->isExistsCalled()); + + $persister->reset(); + + // if the entity is already managed the exists() check should be skipped + $this->_unitOfWork->registerManaged($ph, array('phonenumber' => '12345'), array()); + $this->assertEquals(UnitOfWork::STATE_MANAGED, $this->_unitOfWork->getEntityState($ph)); + $this->assertFalse($persister->isExistsCalled()); + $ph2 = new \Doctrine\Tests\Models\CMS\CmsPhonenumber(); + $ph2->phonenumber = '12345'; + $this->assertEquals(UnitOfWork::STATE_DETACHED, $this->_unitOfWork->getEntityState($ph2)); + $this->assertFalse($persister->isExistsCalled()); + } +} + +/** + * @Entity + */ +class NotifyChangedEntity implements \Doctrine\Common\NotifyPropertyChanged +{ + private $_listeners = array(); + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + private $id; + /** + * @Column(type="string") + */ + private $data; + + private $transient; // not persisted + + /** @OneToMany(targetEntity="NotifyChangedRelatedItem", mappedBy="owner") */ + private $items; + + public function __construct() { + $this->items = new \Doctrine\Common\Collections\ArrayCollection; + } + + public function getId() { + return $this->id; + } + + public function getItems() { + return $this->items; + } + + public function setTransient($value) { + if ($value != $this->transient) { + $this->_onPropertyChanged('transient', $this->transient, $value); + $this->transient = $value; + } + } + + public function getData() { + return $this->data; + } + + public function setData($data) { + if ($data != $this->data) { + $this->_onPropertyChanged('data', $this->data, $data); + $this->data = $data; + } + } + + public function addPropertyChangedListener(\Doctrine\Common\PropertyChangedListener $listener) + { + $this->_listeners[] = $listener; + } + + protected function _onPropertyChanged($propName, $oldValue, $newValue) { + if ($this->_listeners) { + foreach ($this->_listeners as $listener) { + $listener->propertyChanged($this, $propName, $oldValue, $newValue); + } + } + } +} + +/** @Entity */ +class NotifyChangedRelatedItem +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + */ + private $id; + + /** @ManyToOne(targetEntity="NotifyChangedEntity", inversedBy="items") */ + private $owner; + + public function getId() { + return $this->id; + } + + public function getOwner() { + return $this->owner; + } + + public function setOwner($owner) { + $this->owner = $owner; + } +} + +/** @Entity */ +class VersionedAssignedIdentifierEntity +{ + /** + * @Id @Column(type="integer") + */ + public $id; + /** + * @Version @Column(type="integer") + */ + public $version; +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/vendor/doctrine/orm/tests/Doctrine/Tests/OrmFunctionalTestCase.php new file mode 100644 index 0000000..4b72a9a --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -0,0 +1,416 @@ + array( + 'Doctrine\Tests\Models\CMS\CmsUser', + 'Doctrine\Tests\Models\CMS\CmsPhonenumber', + 'Doctrine\Tests\Models\CMS\CmsAddress', + 'Doctrine\Tests\Models\CMS\CmsEmail', + 'Doctrine\Tests\Models\CMS\CmsGroup', + 'Doctrine\Tests\Models\CMS\CmsArticle', + 'Doctrine\Tests\Models\CMS\CmsComment', + ), + 'forum' => array(), + 'company' => array( + 'Doctrine\Tests\Models\Company\CompanyPerson', + 'Doctrine\Tests\Models\Company\CompanyEmployee', + 'Doctrine\Tests\Models\Company\CompanyManager', + 'Doctrine\Tests\Models\Company\CompanyOrganization', + 'Doctrine\Tests\Models\Company\CompanyEvent', + 'Doctrine\Tests\Models\Company\CompanyAuction', + 'Doctrine\Tests\Models\Company\CompanyRaffle', + 'Doctrine\Tests\Models\Company\CompanyCar', + 'Doctrine\Tests\Models\Company\CompanyContract', + ), + 'ecommerce' => array( + 'Doctrine\Tests\Models\ECommerce\ECommerceCart', + 'Doctrine\Tests\Models\ECommerce\ECommerceCustomer', + 'Doctrine\Tests\Models\ECommerce\ECommerceProduct', + 'Doctrine\Tests\Models\ECommerce\ECommerceShipping', + 'Doctrine\Tests\Models\ECommerce\ECommerceFeature', + 'Doctrine\Tests\Models\ECommerce\ECommerceCategory' + ), + 'generic' => array( + 'Doctrine\Tests\Models\Generic\BooleanModel', + 'Doctrine\Tests\Models\Generic\DateTimeModel', + 'Doctrine\Tests\Models\Generic\DecimalModel', + 'Doctrine\Tests\Models\Generic\SerializationModel', + ), + 'routing' => array( + 'Doctrine\Tests\Models\Routing\RoutingLeg', + 'Doctrine\Tests\Models\Routing\RoutingLocation', + 'Doctrine\Tests\Models\Routing\RoutingRoute', + 'Doctrine\Tests\Models\Routing\RoutingRouteBooking', + ), + 'navigation' => array( + 'Doctrine\Tests\Models\Navigation\NavUser', + 'Doctrine\Tests\Models\Navigation\NavCountry', + 'Doctrine\Tests\Models\Navigation\NavPhotos', + 'Doctrine\Tests\Models\Navigation\NavTour', + 'Doctrine\Tests\Models\Navigation\NavPointOfInterest', + ), + 'directorytree' => array( + 'Doctrine\Tests\Models\DirectoryTree\AbstractContentItem', + 'Doctrine\Tests\Models\DirectoryTree\File', + 'Doctrine\Tests\Models\DirectoryTree\Directory', + ), + 'ddc117' => array( + 'Doctrine\Tests\Models\DDC117\DDC117Article', + 'Doctrine\Tests\Models\DDC117\DDC117Reference', + 'Doctrine\Tests\Models\DDC117\DDC117Translation', + 'Doctrine\Tests\Models\DDC117\DDC117ArticleDetails', + 'Doctrine\Tests\Models\DDC117\DDC117ApproveChanges', + 'Doctrine\Tests\Models\DDC117\DDC117Editor', + 'Doctrine\Tests\Models\DDC117\DDC117Link', + ), + 'stockexchange' => array( + 'Doctrine\Tests\Models\StockExchange\Bond', + 'Doctrine\Tests\Models\StockExchange\Stock', + 'Doctrine\Tests\Models\StockExchange\Market', + ), + 'legacy' => array( + 'Doctrine\Tests\Models\Legacy\LegacyUser', + 'Doctrine\Tests\Models\Legacy\LegacyUserReference', + 'Doctrine\Tests\Models\Legacy\LegacyArticle', + 'Doctrine\Tests\Models\Legacy\LegacyCar', + ), + 'customtype' => array( + 'Doctrine\Tests\Models\CustomType\CustomTypeChild', + 'Doctrine\Tests\Models\CustomType\CustomTypeParent', + 'Doctrine\Tests\Models\CustomType\CustomTypeUpperCase', + ), + ); + + protected function useModelSet($setName) + { + $this->_usedModelSets[$setName] = true; + } + + /** + * Sweeps the database tables and clears the EntityManager. + */ + protected function tearDown() + { + $conn = static::$_sharedConn; + + $this->_sqlLoggerStack->enabled = false; + + if (isset($this->_usedModelSets['cms'])) { + $conn->executeUpdate('DELETE FROM cms_users_groups'); + $conn->executeUpdate('DELETE FROM cms_groups'); + $conn->executeUpdate('DELETE FROM cms_addresses'); + $conn->executeUpdate('DELETE FROM cms_phonenumbers'); + $conn->executeUpdate('DELETE FROM cms_comments'); + $conn->executeUpdate('DELETE FROM cms_articles'); + $conn->executeUpdate('DELETE FROM cms_users'); + $conn->executeUpdate('DELETE FROM cms_emails'); + } + + if (isset($this->_usedModelSets['ecommerce'])) { + $conn->executeUpdate('DELETE FROM ecommerce_carts_products'); + $conn->executeUpdate('DELETE FROM ecommerce_products_categories'); + $conn->executeUpdate('DELETE FROM ecommerce_products_related'); + $conn->executeUpdate('DELETE FROM ecommerce_carts'); + $conn->executeUpdate('DELETE FROM ecommerce_customers'); + $conn->executeUpdate('DELETE FROM ecommerce_features'); + $conn->executeUpdate('DELETE FROM ecommerce_products'); + $conn->executeUpdate('DELETE FROM ecommerce_shippings'); + $conn->executeUpdate('UPDATE ecommerce_categories SET parent_id = NULL'); + $conn->executeUpdate('DELETE FROM ecommerce_categories'); + } + + if (isset($this->_usedModelSets['company'])) { + $conn->executeUpdate('DELETE FROM company_contract_employees'); + $conn->executeUpdate('DELETE FROM company_contract_managers'); + $conn->executeUpdate('DELETE FROM company_contracts'); + $conn->executeUpdate('DELETE FROM company_persons_friends'); + $conn->executeUpdate('DELETE FROM company_managers'); + $conn->executeUpdate('DELETE FROM company_employees'); + $conn->executeUpdate('UPDATE company_persons SET spouse_id = NULL'); + $conn->executeUpdate('DELETE FROM company_persons'); + $conn->executeUpdate('DELETE FROM company_raffles'); + $conn->executeUpdate('DELETE FROM company_auctions'); + $conn->executeUpdate('UPDATE company_organizations SET main_event_id = NULL'); + $conn->executeUpdate('DELETE FROM company_events'); + $conn->executeUpdate('DELETE FROM company_organizations'); + } + + if (isset($this->_usedModelSets['generic'])) { + $conn->executeUpdate('DELETE FROM boolean_model'); + $conn->executeUpdate('DELETE FROM date_time_model'); + $conn->executeUpdate('DELETE FROM decimal_model'); + $conn->executeUpdate('DELETE FROM serialize_model'); + } + + if (isset($this->_usedModelSets['routing'])) { + $conn->executeUpdate('DELETE FROM RoutingRouteLegs'); + $conn->executeUpdate('DELETE FROM RoutingRouteBooking'); + $conn->executeUpdate('DELETE FROM RoutingRoute'); + $conn->executeUpdate('DELETE FROM RoutingLeg'); + $conn->executeUpdate('DELETE FROM RoutingLocation'); + } + + if(isset($this->_usedModelSets['navigation'])) { + $conn->executeUpdate('DELETE FROM navigation_tour_pois'); + $conn->executeUpdate('DELETE FROM navigation_photos'); + $conn->executeUpdate('DELETE FROM navigation_pois'); + $conn->executeUpdate('DELETE FROM navigation_tours'); + $conn->executeUpdate('DELETE FROM navigation_countries'); + } + if (isset($this->_usedModelSets['directorytree'])) { + $conn->executeUpdate('DELETE FROM ' . $this->_em->getConnection()->getDatabasePlatform()->quoteIdentifier("file")); + // MySQL doesnt know deferred deletions therefore only executing the second query gives errors. + $conn->executeUpdate('DELETE FROM Directory WHERE parentDirectory_id IS NOT NULL'); + $conn->executeUpdate('DELETE FROM Directory'); + } + if (isset($this->_usedModelSets['ddc117'])) { + $conn->executeUpdate('DELETE FROM ddc117editor_ddc117translation'); + $conn->executeUpdate('DELETE FROM DDC117Editor'); + $conn->executeUpdate('DELETE FROM DDC117ApproveChanges'); + $conn->executeUpdate('DELETE FROM DDC117Link'); + $conn->executeUpdate('DELETE FROM DDC117Reference'); + $conn->executeUpdate('DELETE FROM DDC117ArticleDetails'); + $conn->executeUpdate('DELETE FROM DDC117Translation'); + $conn->executeUpdate('DELETE FROM DDC117Article'); + } + if (isset($this->_usedModelSets['stockexchange'])) { + $conn->executeUpdate('DELETE FROM exchange_bonds_stocks'); + $conn->executeUpdate('DELETE FROM exchange_bonds'); + $conn->executeUpdate('DELETE FROM exchange_stocks'); + $conn->executeUpdate('DELETE FROM exchange_markets'); + } + if (isset($this->_usedModelSets['legacy'])) { + $conn->executeUpdate('DELETE FROM legacy_users_cars'); + $conn->executeUpdate('DELETE FROM legacy_users_reference'); + $conn->executeUpdate('DELETE FROM legacy_articles'); + $conn->executeUpdate('DELETE FROM legacy_cars'); + $conn->executeUpdate('DELETE FROM legacy_users'); + } + + if (isset($this->_usedModelSets['customtype'])) { + $conn->executeUpdate('DELETE FROM customtype_parent_friends'); + $conn->executeUpdate('DELETE FROM customtype_parents'); + $conn->executeUpdate('DELETE FROM customtype_children'); + $conn->executeUpdate('DELETE FROM customtype_uppercases'); + } + + $this->_em->clear(); + } + + protected function setUpEntitySchema(array $classNames) + { + if ($this->_em === null) { + throw new \RuntimeException("EntityManager not set, you have to call parent::setUp() before invoking this method."); + } + + $classes = array(); + foreach ($classNames as $className) { + if ( ! isset(static::$_entityTablesCreated[$className])) { + static::$_entityTablesCreated[$className] = true; + $classes[] = $this->_em->getClassMetadata($className); + } + } + + if ($classes) { + $this->_schemaTool->createSchema($classes); + } + } + + /** + * Creates a connection to the test database, if there is none yet, and + * creates the necessary tables. + */ + protected function setUp() + { + $forceCreateTables = false; + + if ( ! isset(static::$_sharedConn)) { + static::$_sharedConn = TestUtil::getConnection(); + + if (static::$_sharedConn->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) { + $forceCreateTables = true; + } + } + + if (isset($GLOBALS['DOCTRINE_MARK_SQL_LOGS'])) { + if (in_array(static::$_sharedConn->getDatabasePlatform()->getName(), array("mysql", "postgresql"))) { + static::$_sharedConn->executeQuery('SELECT 1 /*' . get_class($this) . '*/'); + } else if (static::$_sharedConn->getDatabasePlatform()->getName() == "oracle") { + static::$_sharedConn->executeQuery('SELECT 1 /*' . get_class($this) . '*/ FROM dual'); + } + } + + if ( ! $this->_em) { + $this->_em = $this->_getEntityManager(); + $this->_schemaTool = new \Doctrine\ORM\Tools\SchemaTool($this->_em); + } + + $classes = array(); + + foreach ($this->_usedModelSets as $setName => $bool) { + if ( ! isset(static::$_tablesCreated[$setName])/* || $forceCreateTables*/) { + foreach (static::$_modelSets[$setName] as $className) { + $classes[] = $this->_em->getClassMetadata($className); + } + + static::$_tablesCreated[$setName] = true; + } + } + + if ($classes) { + $this->_schemaTool->createSchema($classes); + } + + $this->_sqlLoggerStack->enabled = true; + } + + /** + * Gets an EntityManager for testing purposes. + * + * @param Configuration $config The Configuration to pass to the EntityManager. + * @param EventManager $eventManager The EventManager to pass to the EntityManager. + * @return EntityManager + */ + protected function _getEntityManager($config = null, $eventManager = null) { + // NOTE: Functional tests use their own shared metadata cache, because + // the actual database platform used during execution has effect on some + // metadata mapping behaviors (like the choice of the ID generation). + if (is_null(self::$_metadataCacheImpl)) { + if (isset($GLOBALS['DOCTRINE_CACHE_IMPL'])) { + self::$_metadataCacheImpl = new $GLOBALS['DOCTRINE_CACHE_IMPL']; + } else { + self::$_metadataCacheImpl = new \Doctrine\Common\Cache\ArrayCache; + } + } + + if (is_null(self::$_queryCacheImpl)) { + self::$_queryCacheImpl = new \Doctrine\Common\Cache\ArrayCache; + } + + $this->_sqlLoggerStack = new \Doctrine\DBAL\Logging\DebugStack(); + $this->_sqlLoggerStack->enabled = false; + + //FIXME: two different configs! $conn and the created entity manager have + // different configs. + $config = new \Doctrine\ORM\Configuration(); + $config->setMetadataCacheImpl(self::$_metadataCacheImpl); + $config->setQueryCacheImpl(self::$_queryCacheImpl); + $config->setProxyDir(__DIR__ . '/Proxies'); + $config->setProxyNamespace('Doctrine\Tests\Proxies'); + + $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver(array(), true)); + + $conn = static::$_sharedConn; + $conn->getConfiguration()->setSQLLogger($this->_sqlLoggerStack); + + // get rid of more global state + $evm = $conn->getEventManager(); + foreach ($evm->getListeners() AS $event => $listeners) { + foreach ($listeners AS $listener) { + $evm->removeEventListener(array($event), $listener); + } + } + + if (isset($GLOBALS['db_event_subscribers'])) { + foreach (explode(",", $GLOBALS['db_event_subscribers']) AS $subscriberClass) { + $subscriberInstance = new $subscriberClass(); + $evm->addEventSubscriber($subscriberInstance); + } + } + + if (isset($GLOBALS['debug_uow_listener'])) { + $evm->addEventListener(array('onFlush'), new \Doctrine\ORM\Tools\DebugUnitOfWorkListener()); + } + + return \Doctrine\ORM\EntityManager::create($conn, $config); + } + + protected function onNotSuccessfulTest(\Exception $e) + { + if ($e instanceof \PHPUnit_Framework_AssertionFailedError) { + throw $e; + } + + if(isset($this->_sqlLoggerStack->queries) && count($this->_sqlLoggerStack->queries)) { + $queries = ""; + for($i = count($this->_sqlLoggerStack->queries)-1; $i > max(count($this->_sqlLoggerStack->queries)-25, 0) && isset($this->_sqlLoggerStack->queries[$i]); $i--) { + $query = $this->_sqlLoggerStack->queries[$i]; + $params = array_map(function($p) { if (is_object($p)) return get_class($p); else return "'".$p."'"; }, $query['params'] ?: array()); + $queries .= ($i+1).". SQL: '".$query['sql']."' Params: ".implode(", ", $params).PHP_EOL; + } + + $trace = $e->getTrace(); + $traceMsg = ""; + foreach($trace AS $part) { + if(isset($part['file'])) { + if(strpos($part['file'], "PHPUnit/") !== false) { + // Beginning with PHPUnit files we don't print the trace anymore. + break; + } + + $traceMsg .= $part['file'].":".$part['line'].PHP_EOL; + } + } + + $message = "[".get_class($e)."] ".$e->getMessage().PHP_EOL.PHP_EOL."With queries:".PHP_EOL.$queries.PHP_EOL."Trace:".PHP_EOL.$traceMsg; + + throw new \Exception($message, (int)$e->getCode(), $e); + } + throw $e; + } + + /** + * Using the SQL Logger Stack this method retrieves the current query count executed in this test. + * + * @return int + */ + protected function getCurrentQueryCount() + { + return count($this->_sqlLoggerStack->queries); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/OrmPerformanceTestCase.php b/vendor/doctrine/orm/tests/Doctrine/Tests/OrmPerformanceTestCase.php new file mode 100644 index 0000000..ab8fcf5 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/OrmPerformanceTestCase.php @@ -0,0 +1,60 @@ +maxRunningTime != 0 && $time > $this->maxRunningTime) { + $this->fail( + sprintf( + 'expected running time: <= %s but was: %s', + + $this->maxRunningTime, + $time + ) + ); + } + } + + /** + * @param integer $maxRunningTime + * @throws InvalidArgumentException + * @since Method available since Release 2.3.0 + */ + public function setMaxRunningTime($maxRunningTime) + { + if (is_integer($maxRunningTime) && $maxRunningTime >= 0) { + $this->maxRunningTime = $maxRunningTime; + } else { + throw new \InvalidArgumentException; + } + } + + /** + * @return integer + * @since Method available since Release 2.3.0 + */ + public function getMaxRunningTime() + { + return $this->maxRunningTime; + } +} + diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/OrmTestCase.php b/vendor/doctrine/orm/tests/Doctrine/Tests/OrmTestCase.php new file mode 100644 index 0000000..4ad60d6 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/OrmTestCase.php @@ -0,0 +1,117 @@ +=')) { + $reader = new \Doctrine\Common\Annotations\CachedReader( + new \Doctrine\Common\Annotations\AnnotationReader(), new ArrayCache() + ); + } + else if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) { + // Register the ORM Annotations in the AnnotationRegistry + $reader = new \Doctrine\Common\Annotations\SimpleAnnotationReader(); + $reader->addNamespace('Doctrine\ORM\Mapping'); + $reader = new \Doctrine\Common\Annotations\CachedReader($reader, new ArrayCache()); + } + else if (version_compare(\Doctrine\Common\Version::VERSION, '2.1.0-BETA3-DEV', '>=')) { + $reader = new \Doctrine\Common\Annotations\AnnotationReader(); + $reader->setIgnoreNotImportedAnnotations(true); + $reader->setEnableParsePhpImports(false); + if ($alias) { + $reader->setAnnotationNamespaceAlias('Doctrine\ORM\Mapping\\', $alias); + } else { + $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); + } + $reader = new \Doctrine\Common\Annotations\CachedReader( + new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache() + ); + } else { + $reader = new \Doctrine\Common\Annotations\AnnotationReader(); + if ($alias) { + $reader->setAnnotationNamespaceAlias('Doctrine\ORM\Mapping\\', $alias); + } else { + $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\'); + } + } + \Doctrine\Common\Annotations\AnnotationRegistry::registerFile( + __DIR__ . "/../../../lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php"); + return new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, (array)$paths); + } + + /** + * Creates an EntityManager for testing purposes. + * + * NOTE: The created EntityManager will have its dependant DBAL parts completely + * mocked out using a DriverMock, ConnectionMock, etc. These mocks can then + * be configured in the tests to simulate the DBAL behavior that is desired + * for a particular test, + * + * @return Doctrine\ORM\EntityManager + */ + protected function _getTestEntityManager($conn = null, $conf = null, $eventManager = null, $withSharedMetadata = true) + { + $metadataCache = $withSharedMetadata + ? self::getSharedMetadataCacheImpl() + : new \Doctrine\Common\Cache\ArrayCache; + + $config = new \Doctrine\ORM\Configuration(); + + $config->setMetadataCacheImpl($metadataCache); + $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver(array(), true)); + $config->setQueryCacheImpl(self::getSharedQueryCacheImpl()); + $config->setProxyDir(__DIR__ . '/Proxies'); + $config->setProxyNamespace('Doctrine\Tests\Proxies'); + + if ($conn === null) { + $conn = array( + 'driverClass' => 'Doctrine\Tests\Mocks\DriverMock', + 'wrapperClass' => 'Doctrine\Tests\Mocks\ConnectionMock', + 'user' => 'john', + 'password' => 'wayne' + ); + } + + if (is_array($conn)) { + $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager); + } + + return \Doctrine\Tests\Mocks\EntityManagerMock::create($conn, $config, $eventManager); + } + + private static function getSharedMetadataCacheImpl() + { + if (self::$_metadataCacheImpl === null) { + self::$_metadataCacheImpl = new \Doctrine\Common\Cache\ArrayCache; + } + + return self::$_metadataCacheImpl; + } + + private static function getSharedQueryCacheImpl() + { + if (self::$_queryCacheImpl === null) { + self::$_queryCacheImpl = new \Doctrine\Common\Cache\ArrayCache; + } + + return self::$_queryCacheImpl; + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/TestInit.php b/vendor/doctrine/orm/tests/Doctrine/Tests/TestInit.php new file mode 100644 index 0000000..3a35c21 --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/TestInit.php @@ -0,0 +1,43 @@ +register(); + +if (isset($GLOBALS['DOCTRINE_DBAL_PATH'])) { + $classLoader = new \Doctrine\Common\ClassLoader('Doctrine\DBAL', $GLOBALS['DOCTRINE_DBAL_PATH']); +} else { + $classLoader = new \Doctrine\Common\ClassLoader('Doctrine\DBAL', __DIR__ . '/../../../lib/vendor/doctrine-dbal/lib'); +} +$classLoader->register(); + +$classLoader = new \Doctrine\Common\ClassLoader('Doctrine\ORM', __DIR__ . '/../../../lib'); +$classLoader->register(); + +$classLoader = new \Doctrine\Common\ClassLoader('Doctrine\Tests', __DIR__ . '/../../'); +$classLoader->register(); + +$classLoader = new \Doctrine\Common\ClassLoader('Symfony', __DIR__ . "/../../../lib/vendor"); +$classLoader->register(); + +if (!file_exists(__DIR__."/Proxies")) { + if (!mkdir(__DIR__."/Proxies")) { + throw new Exception("Could not create " . __DIR__."/Proxies Folder."); + } +} +if (!file_exists(__DIR__."/ORM/Proxy/generated")) { + if (!mkdir(__DIR__."/ORM/Proxy/generated")) { + throw new Exception("Could not create " . __DIR__."/ORM/Proxy/generated Folder."); + } +} diff --git a/vendor/doctrine/orm/tests/Doctrine/Tests/TestUtil.php b/vendor/doctrine/orm/tests/Doctrine/Tests/TestUtil.php new file mode 100644 index 0000000..b78d06e --- /dev/null +++ b/vendor/doctrine/orm/tests/Doctrine/Tests/TestUtil.php @@ -0,0 +1,119 @@ +real database connection using the following parameters + * of the $GLOBALS array: + * + * 'db_type' : The name of the Doctrine DBAL database driver to use. + * 'db_username' : The username to use for connecting. + * 'db_password' : The password to use for connecting. + * 'db_host' : The hostname of the database to connect to. + * 'db_name' : The name of the database to connect to. + * 'db_port' : The port of the database to connect to. + * + * Usually these variables of the $GLOBALS array are filled by PHPUnit based + * on an XML configuration file. If no such parameters exist, an SQLite + * in-memory database is used. + * + * IMPORTANT: + * 1) Each invocation of this method returns a NEW database connection. + * 2) The database is dropped and recreated to ensure it's clean. + * + * @return Doctrine\DBAL\Connection The database connection instance. + */ + public static function getConnection() + { + if (isset($GLOBALS['db_type'], $GLOBALS['db_username'], $GLOBALS['db_password'], + $GLOBALS['db_host'], $GLOBALS['db_name'], $GLOBALS['db_port']) && + isset($GLOBALS['tmpdb_type'], $GLOBALS['tmpdb_username'], $GLOBALS['tmpdb_password'], + $GLOBALS['tmpdb_host'], $GLOBALS['tmpdb_name'], $GLOBALS['tmpdb_port'])) { + $realDbParams = array( + 'driver' => $GLOBALS['db_type'], + 'user' => $GLOBALS['db_username'], + 'password' => $GLOBALS['db_password'], + 'host' => $GLOBALS['db_host'], + 'dbname' => $GLOBALS['db_name'], + 'port' => $GLOBALS['db_port'] + ); + $tmpDbParams = array( + 'driver' => $GLOBALS['tmpdb_type'], + 'user' => $GLOBALS['tmpdb_username'], + 'password' => $GLOBALS['tmpdb_password'], + 'host' => $GLOBALS['tmpdb_host'], + 'dbname' => $GLOBALS['tmpdb_name'], + 'port' => $GLOBALS['tmpdb_port'] + ); + + $realConn = \Doctrine\DBAL\DriverManager::getConnection($realDbParams); + + $platform = $realConn->getDatabasePlatform(); + + if ($platform->supportsCreateDropDatabase()) { + $dbname = $realConn->getDatabase(); + // Connect to tmpdb in order to drop and create the real test db. + $tmpConn = \Doctrine\DBAL\DriverManager::getConnection($tmpDbParams); + $realConn->close(); + + $tmpConn->getSchemaManager()->dropDatabase($dbname); + $tmpConn->getSchemaManager()->createDatabase($dbname); + + $tmpConn->close(); + } else { + $sm = $realConn->getSchemaManager(); + + /* @var $schema Schema */ + $schema = $sm->createSchema(); + $stmts = $schema->toDropSql($realConn->getDatabasePlatform()); + + foreach ($stmts AS $stmt) { + try { + $realConn->exec($stmt); + } catch(\Exception $e) { + // TODO: Now is this a real good idea? + } + } + } + + $conn = \Doctrine\DBAL\DriverManager::getConnection($realDbParams, null, null); + } else { + $params = array( + 'driver' => 'pdo_sqlite', + 'memory' => true + ); + if (isset($GLOBALS['db_path'])) { + $params['path'] = $GLOBALS['db_path']; + unlink($GLOBALS['db_path']); + } + $conn = \Doctrine\DBAL\DriverManager::getConnection($params); + } + + return $conn; + } + + /** + * @return \Doctrine\DBAL\Connection + */ + public static function getTempConnection() + { + $tmpDbParams = array( + 'driver' => $GLOBALS['tmpdb_type'], + 'user' => $GLOBALS['tmpdb_username'], + 'password' => $GLOBALS['tmpdb_password'], + 'host' => $GLOBALS['tmpdb_host'], + 'dbname' => $GLOBALS['tmpdb_name'], + 'port' => $GLOBALS['tmpdb_port'] + ); + + // Connect to tmpdb in order to drop and create the real test db. + return \Doctrine\DBAL\DriverManager::getConnection($tmpDbParams); + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/NativePhpunitTask.php b/vendor/doctrine/orm/tests/NativePhpunitTask.php new file mode 100644 index 0000000..8a3b190 --- /dev/null +++ b/vendor/doctrine/orm/tests/NativePhpunitTask.php @@ -0,0 +1,249 @@ + + */ +class NativePhpunitTask extends Task +{ + private $test; + private $testfile; + private $testdirectory; + private $configuration = null; + private $coverageClover = null; + private $junitlogfile = null; + private $haltonfailure = true; + private $haltonerror = true; + + public function setTestdirectory($directory) { + $this->testdirectory = $directory; + } + + public function setTest($test) { + $this->test = $test; + } + + public function setTestfile($testfile) { + $this->testfile = $testfile; + } + + public function setJunitlogfile($junitlogfile) { + if (strlen($junitlogfile) == 0) { + $junitlogfile = NULL; + } + + $this->junitlogfile = $junitlogfile; + } + + public function setConfiguration($configuration) { + if (strlen($configuration) == 0) { + $configuration = NULL; + } + + $this->configuration = $configuration; + } + + public function setCoverageClover($coverageClover) { + if (strlen($coverageClover) == 0) { + $coverageClover = NULL; + } + + $this->coverageClover = $coverageClover; + } + + public function setHaltonfailure($haltonfailures) { + $this->haltonfailure = $haltonfailures; + } + + public function setHaltonerror($haltonerrors) { + $this->haltonerror = $haltonerrors; + } + + public function init() + { + require_once "PHPUnit/Runner/Version.php"; + $version = PHPUnit_Runner_Version::id(); + + if (version_compare($version, '3.4.0') < 0) + { + throw new BuildException("NativePHPUnitTask requires PHPUnit version >= 3.2.0", $this->getLocation()); + } + + require_once 'PHPUnit/Util/Filter.php'; + + // point PHPUnit_MAIN_METHOD define to non-existing method + if (!defined('PHPUnit_MAIN_METHOD')) + { + define('PHPUnit_MAIN_METHOD', 'PHPUnitTask::undefined'); + } + } + + public function main() + { + if (!is_dir(realpath($this->testdirectory))) { + throw new BuildException("NativePHPUnitTask requires a Test Directory path given, '".$this->testdirectory."' given."); + } + set_include_path(realpath($this->testdirectory) . PATH_SEPARATOR . get_include_path()); + + $printer = new NativePhpunitPrinter(); + + $arguments = array( + 'configuration' => $this->configuration, + 'coverageClover' => $this->coverageClover, + 'junitLogfile' => $this->junitlogfile, + 'printer' => $printer, + ); + + require_once "PHPUnit/TextUI/TestRunner.php"; + $runner = new PHPUnit_TextUI_TestRunner(); + $suite = $runner->getTest($this->test, $this->testfile, true); + + try { + $result = $runner->doRun($suite, $arguments); + /* @var $result PHPUnit_Framework_TestResult */ + + if ( ($this->haltonfailure && $result->failureCount() > 0) || ($this->haltonerror && $result->errorCount() > 0) ) { + throw new BuildException("PHPUnit: ".$result->failureCount()." Failures and ".$result->errorCount()." Errors, ". + "last failure message: ".$printer->getMessages()); + } + + $this->log("PHPUnit Success: ".count($result->passed())." tests passed, no ". + "failures (".$result->skippedCount()." skipped, ".$result->notImplementedCount()." not implemented)"); + + // Hudson for example doesn't like the backslash in class names + if (file_exists($this->coverageClover)) { + $this->log("Generated Clover Coverage XML to: ".$this->coverageClover); + $content = file_get_contents($this->coverageClover); + $content = str_replace("\\", ".", $content); + file_put_contents($this->coverageClover, $content); + unset($content); + } + + } catch(\Exception $e) { + throw new BuildException("NativePhpunitTask failed: ".$e->getMessage()); + } + } +} + +class NativePhpunitPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener +{ + private $_messages = array(); + + public function write($buffer) + { + // do nothing + } + + public function getMessages() + { + return $this->_messages; + } + + /** + * An error occurred. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) + { + $this->_messages[] = "Test ERROR: ".$test->getName().": ".$e->getMessage(); + } + + /** + * A failure occurred. + * + * @param PHPUnit_Framework_Test $test + * @param PHPUnit_Framework_AssertionFailedError $e + * @param float $time + */ + public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) + { + $this->_messages[] = "Test FAILED: ".$test->getName().": ".$e->getMessage(); + } + + /** + * Incomplete test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + */ + public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + + } + + /** + * Skipped test. + * + * @param PHPUnit_Framework_Test $test + * @param Exception $e + * @param float $time + * @since Method available since Release 3.0.0 + */ + public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) + { + + } + + /** + * A test suite started. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function startTestSuite(PHPUnit_Framework_TestSuite $suite) + { + + } + + /** + * A test suite ended. + * + * @param PHPUnit_Framework_TestSuite $suite + * @since Method available since Release 2.2.0 + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + + } + + /** + * A test started. + * + * @param PHPUnit_Framework_Test $test + */ + public function startTest(PHPUnit_Framework_Test $test) + { + + } + + /** + * A test ended. + * + * @param PHPUnit_Framework_Test $test + * @param float $time + */ + public function endTest(PHPUnit_Framework_Test $test, $time) + { + + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/README.markdown b/vendor/doctrine/orm/tests/README.markdown new file mode 100644 index 0000000..c1027ac --- /dev/null +++ b/vendor/doctrine/orm/tests/README.markdown @@ -0,0 +1,25 @@ +# Running the Doctrine 2 Testsuite + +## Setting up a PHPUnit Configuration XML + +.. + +## Testing Lock-Support + +The Lock support in Doctrine 2 is tested using Gearman, which allows to run concurrent tasks in parallel. +Install Gearman with PHP as follows: + +1. Go to http://www.gearman.org and download the latest Gearman Server +2. Compile it and then call ldconfig +3. Start it up "gearmand -vvvv" +4. Install pecl/gearman by calling "gearman-beta" + +You can then go into tests/ and start up two workers: + + php Doctrine/Tests/ORM/Functional/Locking/LockAgentWorker.php + +Then run the locking test-suite: + + phpunit --configuration Doctrine/Tests/ORM/Functional/Locking/GearmanLockTest.php + +This can run considerable time, because it is using sleep() to test for the timing ranges of locks. \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/dbproperties.xml.dev b/vendor/doctrine/orm/tests/dbproperties.xml.dev new file mode 100644 index 0000000..503cb85 --- /dev/null +++ b/vendor/doctrine/orm/tests/dbproperties.xml.dev @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/travis/mysql.travis.xml b/vendor/doctrine/orm/tests/travis/mysql.travis.xml new file mode 100644 index 0000000..f17a4b8 --- /dev/null +++ b/vendor/doctrine/orm/tests/travis/mysql.travis.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + ./../Doctrine/Tests/ORM + + + + + performance + locking_functional + + + + + diff --git a/vendor/doctrine/orm/tests/travis/pgsql.travis.xml b/vendor/doctrine/orm/tests/travis/pgsql.travis.xml new file mode 100644 index 0000000..fa0581a --- /dev/null +++ b/vendor/doctrine/orm/tests/travis/pgsql.travis.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + ./../Doctrine/Tests/ORM + + + + + + performance + locking_functional + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tests/travis/sqlite.travis.xml b/vendor/doctrine/orm/tests/travis/sqlite.travis.xml new file mode 100644 index 0000000..5d310c3 --- /dev/null +++ b/vendor/doctrine/orm/tests/travis/sqlite.travis.xml @@ -0,0 +1,15 @@ + + + + + ./../Doctrine/Tests/ORM + + + + + performance + locking_functional + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tools/sandbox/Entities/Address.php b/vendor/doctrine/orm/tools/sandbox/Entities/Address.php new file mode 100644 index 0000000..717ea63 --- /dev/null +++ b/vendor/doctrine/orm/tools/sandbox/Entities/Address.php @@ -0,0 +1,45 @@ +id; + } + + public function getStreet() + { + return $this->street; + } + + public function setStreet($street) + { + $this->street = $street; + } + + public function getUser() + { + return $this->user; + } + + public function setUser(User $user) + { + if ($this->user !== $user) { + $this->user = $user; + $user->setAddress($this); + } + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tools/sandbox/Entities/User.php b/vendor/doctrine/orm/tools/sandbox/Entities/User.php new file mode 100644 index 0000000..cd18421 --- /dev/null +++ b/vendor/doctrine/orm/tools/sandbox/Entities/User.php @@ -0,0 +1,48 @@ +id; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + } + + public function getAddress() + { + return $this->address; + } + + public function setAddress(Address $address) + { + if ($this->address !== $address) { + $this->address = $address; + $address->setUser($this); + } + } +} \ No newline at end of file diff --git a/vendor/doctrine/orm/tools/sandbox/cli-config.php b/vendor/doctrine/orm/tools/sandbox/cli-config.php new file mode 100644 index 0000000..2a34fd8 --- /dev/null +++ b/vendor/doctrine/orm/tools/sandbox/cli-config.php @@ -0,0 +1,36 @@ +register(); +$classLoader = new \Doctrine\Common\ClassLoader('Doctrine\DBAL', realpath(__DIR__ . '/../../lib/vendor/doctrine-dbal/lib')); +$classLoader->register(); +$classLoader = new \Doctrine\Common\ClassLoader('Doctrine\Common', realpath(__DIR__ . '/../../lib/vendor/doctrine-common/lib')); +$classLoader->register(); +$classLoader = new \Doctrine\Common\ClassLoader('Symfony', realpath(__DIR__ . '/../../lib/vendor')); +$classLoader->register(); +$classLoader = new \Doctrine\Common\ClassLoader('Entities', __DIR__); +$classLoader->register(); +$classLoader = new \Doctrine\Common\ClassLoader('Proxies', __DIR__); +$classLoader->register(); + +$config = new \Doctrine\ORM\Configuration(); +$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache); +$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities")); +$config->setMetadataDriverImpl($driverImpl); + +$config->setProxyDir(__DIR__ . '/Proxies'); +$config->setProxyNamespace('Proxies'); + +$connectionOptions = array( + 'driver' => 'pdo_sqlite', + 'path' => 'database.sqlite' +); + +$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config); + +$helpers = new Symfony\Component\Console\Helper\HelperSet(array( + 'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()), + 'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em) +)); \ No newline at end of file diff --git a/vendor/doctrine/orm/tools/sandbox/doctrine b/vendor/doctrine/orm/tools/sandbox/doctrine new file mode 100644 index 0000000..92f323f --- /dev/null +++ b/vendor/doctrine/orm/tools/sandbox/doctrine @@ -0,0 +1,4 @@ +#!/usr/bin/env php +register(); +$classLoader = new \Doctrine\Common\ClassLoader('Doctrine\DBAL', realpath(__DIR__ . '/../../lib/vendor/doctrine-dbal/lib')); +$classLoader->register(); +$classLoader = new \Doctrine\Common\ClassLoader('Doctrine\Common', realpath(__DIR__ . '/../../lib/vendor/doctrine-common/lib')); +$classLoader->register(); +$classLoader = new \Doctrine\Common\ClassLoader('Symfony', realpath(__DIR__ . '/../../lib/vendor')); +$classLoader->register(); +$classLoader = new \Doctrine\Common\ClassLoader('Entities', __DIR__); +$classLoader->register(); +$classLoader = new \Doctrine\Common\ClassLoader('Proxies', __DIR__); +$classLoader->register(); + +// Variable $helperSet is defined inside cli-config.php +require __DIR__ . '/cli-config.php'; + +$cli = new \Symfony\Component\Console\Application('Doctrine Command Line Interface', Doctrine\Common\Version::VERSION); +$cli->setCatchExceptions(true); +$helperSet = $cli->getHelperSet(); +foreach ($helpers as $name => $helper) { + $helperSet->set($helper, $name); +} +$cli->addCommands(array( + // DBAL Commands + new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(), + new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(), + + // ORM Commands + new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(), + new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(), + new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(), + new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(), + new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(), + new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(), + new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(), + new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(), + new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(), + new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(), + new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(), + new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(), + new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(), + new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(), + +)); +$cli->run(); diff --git a/vendor/doctrine/orm/tools/sandbox/index.php b/vendor/doctrine/orm/tools/sandbox/index.php new file mode 100644 index 0000000..ad1cb9d --- /dev/null +++ b/vendor/doctrine/orm/tools/sandbox/index.php @@ -0,0 +1,62 @@ +register(); +$classLoader = new ClassLoader('Doctrine\DBAL', realpath(__DIR__ . '/../../lib/vendor/doctrine-dbal/lib')); +$classLoader->register(); +$classLoader = new ClassLoader('Doctrine\Common', realpath(__DIR__ . '/../../lib/vendor/doctrine-common/lib')); +$classLoader->register(); +$classLoader = new ClassLoader('Symfony', realpath(__DIR__ . '/../../lib/vendor')); +$classLoader->register(); +$classLoader = new ClassLoader('Entities', __DIR__); +$classLoader->register(); +$classLoader = new ClassLoader('Proxies', __DIR__); +$classLoader->register(); + +// Set up caches +$config = new Configuration; +$cache = new ApcCache; +$config->setMetadataCacheImpl($cache); +$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities")); +$config->setMetadataDriverImpl($driverImpl); +$config->setQueryCacheImpl($cache); + +// Proxy configuration +$config->setProxyDir(__DIR__ . '/Proxies'); +$config->setProxyNamespace('Proxies'); +$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache); + +// Database connection information +$connectionOptions = array( + 'driver' => 'pdo_sqlite', + 'path' => 'database.sqlite' +); + +// Create EntityManager +$em = EntityManager::create($connectionOptions, $config); + +## PUT YOUR TEST CODE BELOW + +$user = new User; +$address = new Address; + +echo 'Hello World!' . PHP_EOL; diff --git a/vendor/doctrine/orm/tools/sandbox/xml/Entities.Address.dcm.xml b/vendor/doctrine/orm/tools/sandbox/xml/Entities.Address.dcm.xml new file mode 100644 index 0000000..7e8dd01 --- /dev/null +++ b/vendor/doctrine/orm/tools/sandbox/xml/Entities.Address.dcm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/doctrine/orm/tools/sandbox/xml/Entities.User.dcm.xml b/vendor/doctrine/orm/tools/sandbox/xml/Entities.User.dcm.xml new file mode 100644 index 0000000..e548fd1 --- /dev/null +++ b/vendor/doctrine/orm/tools/sandbox/xml/Entities.User.dcm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/vendor/doctrine/orm/tools/sandbox/yaml/Entities.Address.dcm.yml b/vendor/doctrine/orm/tools/sandbox/yaml/Entities.Address.dcm.yml new file mode 100644 index 0000000..140e902 --- /dev/null +++ b/vendor/doctrine/orm/tools/sandbox/yaml/Entities.Address.dcm.yml @@ -0,0 +1,16 @@ +Entities\Address: + type: entity + table: addresses + id: + id: + type: integer + generator: + strategy: AUTO + fields: + street: + type: string + length: 255 + oneToOne: + user: + targetEntity: User + mappedBy: address \ No newline at end of file diff --git a/vendor/doctrine/orm/tools/sandbox/yaml/Entities.User.dcm.yml b/vendor/doctrine/orm/tools/sandbox/yaml/Entities.User.dcm.yml new file mode 100644 index 0000000..a93d48f --- /dev/null +++ b/vendor/doctrine/orm/tools/sandbox/yaml/Entities.User.dcm.yml @@ -0,0 +1,18 @@ +Entities\User: + type: entity + table: users + id: + id: + type: integer + generator: + strategy: AUTO + fields: + name: + type: string + length: 50 + oneToOne: + address: + targetEntity: Address + joinColumn: + name: address_id + referencedColumnName: id diff --git a/vendor/symfony/console/Symfony/Component/Console/Application.php b/vendor/symfony/console/Symfony/Component/Console/Application.php new file mode 100644 index 0000000..63f16e8 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Application.php @@ -0,0 +1,1089 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Command\HelpCommand; +use Symfony\Component\Console\Command\ListCommand; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Helper\FormatterHelper; +use Symfony\Component\Console\Helper\DialogHelper; + +/** + * An Application is the container for a collection of commands. + * + * It is the main entry point of a Console application. + * + * This class is optimized for a standard CLI environment. + * + * Usage: + * + * $app = new Application('myapp', '1.0 (stable)'); + * $app->add(new SimpleCommand()); + * $app->run(); + * + * @author Fabien Potencier + * + * @api + */ +class Application +{ + private $commands; + private $wantHelps = false; + private $runningCommand; + private $name; + private $version; + private $catchExceptions; + private $autoExit; + private $definition; + private $helperSet; + + /** + * Constructor. + * + * @param string $name The name of the application + * @param string $version The version of the application + * + * @api + */ + public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') + { + $this->name = $name; + $this->version = $version; + $this->catchExceptions = true; + $this->autoExit = true; + $this->commands = array(); + $this->helperSet = $this->getDefaultHelperSet(); + $this->definition = $this->getDefaultInputDefinition(); + + foreach ($this->getDefaultCommands() as $command) { + $this->add($command); + } + } + + /** + * Runs the current application. + * + * @param InputInterface $input An Input instance + * @param OutputInterface $output An Output instance + * + * @return integer 0 if everything went fine, or an error code + * + * @throws \Exception When doRun returns Exception + * + * @api + */ + public function run(InputInterface $input = null, OutputInterface $output = null) + { + if (null === $input) { + $input = new ArgvInput(); + } + + if (null === $output) { + $output = new ConsoleOutput(); + } + + try { + $statusCode = $this->doRun($input, $output); + } catch (\Exception $e) { + if (!$this->catchExceptions) { + throw $e; + } + + if ($output instanceof ConsoleOutputInterface) { + $this->renderException($e, $output->getErrorOutput()); + } else { + $this->renderException($e, $output); + } + $statusCode = $e->getCode(); + + $statusCode = is_numeric($statusCode) && $statusCode ? $statusCode : 1; + } + + if ($this->autoExit) { + if ($statusCode > 255) { + $statusCode = 255; + } + // @codeCoverageIgnoreStart + exit($statusCode); + // @codeCoverageIgnoreEnd + } + + return $statusCode; + } + + /** + * Runs the current application. + * + * @param InputInterface $input An Input instance + * @param OutputInterface $output An Output instance + * + * @return integer 0 if everything went fine, or an error code + */ + public function doRun(InputInterface $input, OutputInterface $output) + { + $name = $this->getCommandName($input); + + if (true === $input->hasParameterOption(array('--ansi'))) { + $output->setDecorated(true); + } elseif (true === $input->hasParameterOption(array('--no-ansi'))) { + $output->setDecorated(false); + } + + if (true === $input->hasParameterOption(array('--help', '-h'))) { + if (!$name) { + $name = 'help'; + $input = new ArrayInput(array('command' => 'help')); + } else { + $this->wantHelps = true; + } + } + + if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) { + $input->setInteractive(false); + } + + if (function_exists('posix_isatty') && $this->getHelperSet()->has('dialog')) { + $inputStream = $this->getHelperSet()->get('dialog')->getInputStream(); + if (!posix_isatty($inputStream)) { + $input->setInteractive(false); + } + } + + if (true === $input->hasParameterOption(array('--quiet', '-q'))) { + $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + } elseif (true === $input->hasParameterOption(array('--verbose', '-v'))) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + } + + if (true === $input->hasParameterOption(array('--version', '-V'))) { + $output->writeln($this->getLongVersion()); + + return 0; + } + + if (!$name) { + $name = 'list'; + $input = new ArrayInput(array('command' => 'list')); + } + + // the command name MUST be the first element of the input + $command = $this->find($name); + + $this->runningCommand = $command; + $statusCode = $command->run($input, $output); + $this->runningCommand = null; + + return is_numeric($statusCode) ? $statusCode : 0; + } + + /** + * Set a helper set to be used with the command. + * + * @param HelperSet $helperSet The helper set + * + * @api + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + + /** + * Get the helper set associated with the command. + * + * @return HelperSet The HelperSet instance associated with this command + * + * @api + */ + public function getHelperSet() + { + return $this->helperSet; + } + + /** + * Gets the InputDefinition related to this Application. + * + * @return InputDefinition The InputDefinition instance + */ + public function getDefinition() + { + return $this->definition; + } + + /** + * Gets the help message. + * + * @return string A help message. + */ + public function getHelp() + { + $messages = array( + $this->getLongVersion(), + '', + 'Usage:', + sprintf(" [options] command [arguments]\n"), + 'Options:', + ); + + foreach ($this->getDefinition()->getOptions() as $option) { + $messages[] = sprintf(' %-29s %s %s', + '--'.$option->getName().'', + $option->getShortcut() ? '-'.$option->getShortcut().'' : ' ', + $option->getDescription() + ); + } + + return implode(PHP_EOL, $messages); + } + + /** + * Sets whether to catch exceptions or not during commands execution. + * + * @param Boolean $boolean Whether to catch exceptions or not during commands execution + * + * @api + */ + public function setCatchExceptions($boolean) + { + $this->catchExceptions = (Boolean) $boolean; + } + + /** + * Sets whether to automatically exit after a command execution or not. + * + * @param Boolean $boolean Whether to automatically exit after a command execution or not + * + * @api + */ + public function setAutoExit($boolean) + { + $this->autoExit = (Boolean) $boolean; + } + + /** + * Gets the name of the application. + * + * @return string The application name + * + * @api + */ + public function getName() + { + return $this->name; + } + + /** + * Sets the application name. + * + * @param string $name The application name + * + * @api + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Gets the application version. + * + * @return string The application version + * + * @api + */ + public function getVersion() + { + return $this->version; + } + + /** + * Sets the application version. + * + * @param string $version The application version + * + * @api + */ + public function setVersion($version) + { + $this->version = $version; + } + + /** + * Returns the long version of the application. + * + * @return string The long application version + * + * @api + */ + public function getLongVersion() + { + if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) { + return sprintf('%s version %s', $this->getName(), $this->getVersion()); + } + + return 'Console Tool'; + } + + /** + * Registers a new command. + * + * @param string $name The command name + * + * @return Command The newly created command + * + * @api + */ + public function register($name) + { + return $this->add(new Command($name)); + } + + /** + * Adds an array of command objects. + * + * @param Command[] $commands An array of commands + * + * @api + */ + public function addCommands(array $commands) + { + foreach ($commands as $command) { + $this->add($command); + } + } + + /** + * Adds a command object. + * + * If a command with the same name already exists, it will be overridden. + * + * @param Command $command A Command object + * + * @return Command The registered command + * + * @api + */ + public function add(Command $command) + { + $command->setApplication($this); + + if (!$command->isEnabled()) { + $command->setApplication(null); + + return; + } + + $this->commands[$command->getName()] = $command; + + foreach ($command->getAliases() as $alias) { + $this->commands[$alias] = $command; + } + + return $command; + } + + /** + * Returns a registered command by name or alias. + * + * @param string $name The command name or alias + * + * @return Command A Command object + * + * @throws \InvalidArgumentException When command name given does not exist + * + * @api + */ + public function get($name) + { + if (!isset($this->commands[$name])) { + throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name)); + } + + $command = $this->commands[$name]; + + if ($this->wantHelps) { + $this->wantHelps = false; + + $helpCommand = $this->get('help'); + $helpCommand->setCommand($command); + + return $helpCommand; + } + + return $command; + } + + /** + * Returns true if the command exists, false otherwise. + * + * @param string $name The command name or alias + * + * @return Boolean true if the command exists, false otherwise + * + * @api + */ + public function has($name) + { + return isset($this->commands[$name]); + } + + /** + * Returns an array of all unique namespaces used by currently registered commands. + * + * It does not returns the global namespace which always exists. + * + * @return array An array of namespaces + */ + public function getNamespaces() + { + $namespaces = array(); + foreach ($this->commands as $command) { + $namespaces[] = $this->extractNamespace($command->getName()); + + foreach ($command->getAliases() as $alias) { + $namespaces[] = $this->extractNamespace($alias); + } + } + + return array_values(array_unique(array_filter($namespaces))); + } + + /** + * Finds a registered namespace by a name or an abbreviation. + * + * @param string $namespace A namespace or abbreviation to search for + * + * @return string A registered namespace + * + * @throws \InvalidArgumentException When namespace is incorrect or ambiguous + */ + public function findNamespace($namespace) + { + $allNamespaces = array(); + foreach ($this->getNamespaces() as $n) { + $allNamespaces[$n] = explode(':', $n); + } + + $found = array(); + foreach (explode(':', $namespace) as $i => $part) { + $abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $allNamespaces))))); + + if (!isset($abbrevs[$part])) { + $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); + + if (1 <= $i) { + $part = implode(':', $found).':'.$part; + } + + if ($alternatives = $this->findAlternativeNamespace($part, $abbrevs)) { + if (1 == count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + + $message .= implode("\n ", $alternatives); + } + + throw new \InvalidArgumentException($message); + } + + if (count($abbrevs[$part]) > 1) { + throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$part]))); + } + + $found[] = $abbrevs[$part][0]; + } + + return implode(':', $found); + } + + /** + * Finds a command by name or alias. + * + * Contrary to get, this command tries to find the best + * match if you give it an abbreviation of a name or alias. + * + * @param string $name A command name or a command alias + * + * @return Command A Command instance + * + * @throws \InvalidArgumentException When command name is incorrect or ambiguous + * + * @api + */ + public function find($name) + { + // namespace + $namespace = ''; + $searchName = $name; + if (false !== $pos = strrpos($name, ':')) { + $namespace = $this->findNamespace(substr($name, 0, $pos)); + $searchName = $namespace.substr($name, $pos); + } + + // name + $commands = array(); + foreach ($this->commands as $command) { + if ($this->extractNamespace($command->getName()) == $namespace) { + $commands[] = $command->getName(); + } + } + + $abbrevs = static::getAbbreviations(array_unique($commands)); + if (isset($abbrevs[$searchName]) && 1 == count($abbrevs[$searchName])) { + return $this->get($abbrevs[$searchName][0]); + } + + if (isset($abbrevs[$searchName]) && count($abbrevs[$searchName]) > 1) { + $suggestions = $this->getAbbreviationSuggestions($abbrevs[$searchName]); + + throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions)); + } + + // aliases + $aliases = array(); + foreach ($this->commands as $command) { + foreach ($command->getAliases() as $alias) { + if ($this->extractNamespace($alias) == $namespace) { + $aliases[] = $alias; + } + } + } + + $aliases = static::getAbbreviations(array_unique($aliases)); + if (!isset($aliases[$searchName])) { + $message = sprintf('Command "%s" is not defined.', $name); + + if ($alternatives = $this->findAlternativeCommands($searchName, $abbrevs)) { + if (1 == count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + $message .= implode("\n ", $alternatives); + } + + throw new \InvalidArgumentException($message); + } + + if (count($aliases[$searchName]) > 1) { + throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $this->getAbbreviationSuggestions($aliases[$searchName]))); + } + + return $this->get($aliases[$searchName][0]); + } + + /** + * Gets the commands (registered in the given namespace if provided). + * + * The array keys are the full names and the values the command instances. + * + * @param string $namespace A namespace name + * + * @return array An array of Command instances + * + * @api + */ + public function all($namespace = null) + { + if (null === $namespace) { + return $this->commands; + } + + $commands = array(); + foreach ($this->commands as $name => $command) { + if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) { + $commands[$name] = $command; + } + } + + return $commands; + } + + /** + * Returns an array of possible abbreviations given a set of names. + * + * @param array $names An array of names + * + * @return array An array of abbreviations + */ + public static function getAbbreviations($names) + { + $abbrevs = array(); + foreach ($names as $name) { + for ($len = strlen($name) - 1; $len > 0; --$len) { + $abbrev = substr($name, 0, $len); + if (!isset($abbrevs[$abbrev])) { + $abbrevs[$abbrev] = array($name); + } else { + $abbrevs[$abbrev][] = $name; + } + } + } + + // Non-abbreviations always get entered, even if they aren't unique + foreach ($names as $name) { + $abbrevs[$name] = array($name); + } + + return $abbrevs; + } + + /** + * Returns a text representation of the Application. + * + * @param string $namespace An optional namespace name + * @param boolean $raw Whether to return raw command list + * + * @return string A string representing the Application + */ + public function asText($namespace = null, $raw = false) + { + $commands = $namespace ? $this->all($this->findNamespace($namespace)) : $this->commands; + + $width = 0; + foreach ($commands as $command) { + $width = strlen($command->getName()) > $width ? strlen($command->getName()) : $width; + } + $width += 2; + + if ($raw) { + $messages = array(); + foreach ($this->sortCommands($commands) as $space => $commands) { + foreach ($commands as $name => $command) { + $messages[] = sprintf("%-${width}s %s", $name, $command->getDescription()); + } + } + + return implode(PHP_EOL, $messages); + } + + $messages = array($this->getHelp(), ''); + if ($namespace) { + $messages[] = sprintf("Available commands for the \"%s\" namespace:", $namespace); + } else { + $messages[] = 'Available commands:'; + } + + // add commands by namespace + foreach ($this->sortCommands($commands) as $space => $commands) { + if (!$namespace && '_global' !== $space) { + $messages[] = ''.$space.''; + } + + foreach ($commands as $name => $command) { + $messages[] = sprintf(" %-${width}s %s", $name, $command->getDescription()); + } + } + + return implode(PHP_EOL, $messages); + } + + /** + * Returns an XML representation of the Application. + * + * @param string $namespace An optional namespace name + * @param Boolean $asDom Whether to return a DOM or an XML string + * + * @return string|DOMDocument An XML string representing the Application + */ + public function asXml($namespace = null, $asDom = false) + { + $commands = $namespace ? $this->all($this->findNamespace($namespace)) : $this->commands; + + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = true; + $dom->appendChild($xml = $dom->createElement('symfony')); + + $xml->appendChild($commandsXML = $dom->createElement('commands')); + + if ($namespace) { + $commandsXML->setAttribute('namespace', $namespace); + } else { + $namespacesXML = $dom->createElement('namespaces'); + $xml->appendChild($namespacesXML); + } + + // add commands by namespace + foreach ($this->sortCommands($commands) as $space => $commands) { + if (!$namespace) { + $namespaceArrayXML = $dom->createElement('namespace'); + $namespacesXML->appendChild($namespaceArrayXML); + $namespaceArrayXML->setAttribute('id', $space); + } + + foreach ($commands as $name => $command) { + if ($name !== $command->getName()) { + continue; + } + + if (!$namespace) { + $commandXML = $dom->createElement('command'); + $namespaceArrayXML->appendChild($commandXML); + $commandXML->appendChild($dom->createTextNode($name)); + } + + $node = $command->asXml(true)->getElementsByTagName('command')->item(0); + $node = $dom->importNode($node, true); + + $commandsXML->appendChild($node); + } + } + + return $asDom ? $dom : $dom->saveXml(); + } + + /** + * Renders a caught exception. + * + * @param Exception $e An exception instance + * @param OutputInterface $output An OutputInterface instance + */ + public function renderException($e, $output) + { + $strlen = function ($string) { + if (!function_exists('mb_strlen')) { + return strlen($string); + } + + if (false === $encoding = mb_detect_encoding($string)) { + return strlen($string); + } + + return mb_strlen($string, $encoding); + }; + + do { + $title = sprintf(' [%s] ', get_class($e)); + $len = $strlen($title); + $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX; + $lines = array(); + foreach (preg_split("{\r?\n}", $e->getMessage()) as $line) { + foreach (str_split($line, $width - 4) as $line) { + $lines[] = sprintf(' %s ', $line); + $len = max($strlen($line) + 4, $len); + } + } + + $messages = array(str_repeat(' ', $len), $title.str_repeat(' ', max(0, $len - $strlen($title)))); + + foreach ($lines as $line) { + $messages[] = $line.str_repeat(' ', $len - $strlen($line)); + } + + $messages[] = str_repeat(' ', $len); + + $output->writeln(""); + $output->writeln(""); + foreach ($messages as $message) { + $output->writeln(''.$message.''); + } + $output->writeln(""); + $output->writeln(""); + + if (OutputInterface::VERBOSITY_VERBOSE === $output->getVerbosity()) { + $output->writeln('Exception trace:'); + + // exception related properties + $trace = $e->getTrace(); + array_unshift($trace, array( + 'function' => '', + 'file' => $e->getFile() != null ? $e->getFile() : 'n/a', + 'line' => $e->getLine() != null ? $e->getLine() : 'n/a', + 'args' => array(), + )); + + for ($i = 0, $count = count($trace); $i < $count; $i++) { + $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : ''; + $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : ''; + $function = $trace[$i]['function']; + $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a'; + $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a'; + + $output->writeln(sprintf(' %s%s%s() at %s:%s', $class, $type, $function, $file, $line)); + } + + $output->writeln(""); + $output->writeln(""); + } + } while ($e = $e->getPrevious()); + + if (null !== $this->runningCommand) { + $output->writeln(sprintf('%s', sprintf($this->runningCommand->getSynopsis(), $this->getName()))); + $output->writeln(""); + $output->writeln(""); + } + } + + /** + * Tries to figure out the terminal width in which this application runs + * + * @return int|null + */ + protected function getTerminalWidth() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + if ($ansicon = getenv('ANSICON')) { + return preg_replace('{^(\d+)x.*$}', '$1', $ansicon); + } + + exec('mode CON', $execData); + if (preg_match('{columns:\s*(\d+)}i', $execData[4], $matches)) { + return $matches[1]; + } + } + + if (preg_match("{rows.(\d+);.columns.(\d+);}i", $this->getSttyColumns(), $match)) { + return $match[2]; + } + } + + /** + * Tries to figure out the terminal height in which this application runs + * + * @return int|null + */ + protected function getTerminalHeight() + { + if (defined('PHP_WINDOWS_VERSION_BUILD')) { + if ($ansicon = getenv('ANSICON')) { + return preg_replace('{^\d+x\d+ \(\d+x(\d+)\)$}', '$1', trim($ansicon)); + } + + exec('mode CON', $execData); + if (preg_match('{lines:\s*(\d+)}i', $execData[3], $matches)) { + return $matches[1]; + } + } + + if (preg_match("{rows.(\d+);.columns.(\d+);}i", $this->getSttyColumns(), $match)) { + return $match[1]; + } + } + + /** + * Gets the name of the command based on input. + * + * @param InputInterface $input The input interface + * + * @return string The command name + */ + protected function getCommandName(InputInterface $input) + { + return $input->getFirstArgument(); + } + + /** + * Gets the default input definition. + * + * @return InputDefinition An InputDefinition instance + */ + protected function getDefaultInputDefinition() + { + return new InputDefinition(array( + new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), + + new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message.'), + new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message.'), + new InputOption('--verbose', '-v', InputOption::VALUE_NONE, 'Increase verbosity of messages.'), + new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version.'), + new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output.'), + new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output.'), + new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question.'), + )); + } + + /** + * Gets the default commands that should always be available. + * + * @return array An array of default Command instances + */ + protected function getDefaultCommands() + { + return array(new HelpCommand(), new ListCommand()); + } + + /** + * Gets the default helper set with the helpers that should always be available. + * + * @return HelperSet A HelperSet instance + */ + protected function getDefaultHelperSet() + { + return new HelperSet(array( + new FormatterHelper(), + new DialogHelper(), + )); + } + + /** + * Runs and parses stty -a if it's available, suppressing any error output + * + * @return string + */ + private function getSttyColumns() + { + if (!function_exists('proc_open')) { + return; + } + + $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); + $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); + if (is_resource($process)) { + $info = stream_get_contents($pipes[1]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + + return $info; + } + } + + /** + * Sorts commands in alphabetical order. + * + * @param array $commands An associative array of commands to sort + * + * @return array A sorted array of commands + */ + private function sortCommands($commands) + { + $namespacedCommands = array(); + foreach ($commands as $name => $command) { + $key = $this->extractNamespace($name, 1); + if (!$key) { + $key = '_global'; + } + + $namespacedCommands[$key][$name] = $command; + } + ksort($namespacedCommands); + + foreach ($namespacedCommands as &$commands) { + ksort($commands); + } + + return $namespacedCommands; + } + + /** + * Returns abbreviated suggestions in string format. + * + * @param array $abbrevs Abbreviated suggestions to convert + * + * @return string A formatted string of abbreviated suggestions + */ + private function getAbbreviationSuggestions($abbrevs) + { + return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''); + } + + /** + * Returns the namespace part of the command name. + * + * @param string $name The full name of the command + * @param string $limit The maximum number of parts of the namespace + * + * @return string The namespace of the command + */ + private function extractNamespace($name, $limit = null) + { + $parts = explode(':', $name); + array_pop($parts); + + return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit)); + } + + /** + * Finds alternative commands of $name + * + * @param string $name The full name of the command + * @param array $abbrevs The abbreviations + * + * @return array A sorted array of similar commands + */ + private function findAlternativeCommands($name, $abbrevs) + { + $callback = function($item) { + return $item->getName(); + }; + + return $this->findAlternatives($name, $this->commands, $abbrevs, $callback); + } + + /** + * Finds alternative namespace of $name + * + * @param string $name The full name of the namespace + * @param array $abbrevs The abbreviations + * + * @return array A sorted array of similar namespace + */ + private function findAlternativeNamespace($name, $abbrevs) + { + return $this->findAlternatives($name, $this->getNamespaces(), $abbrevs); + } + + /** + * Finds alternative of $name among $collection, + * if nothing is found in $collection, try in $abbrevs + * + * @param string $name The string + * @param array|Traversable $collection The collection + * @param array $abbrevs The abbreviations + * @param Closure|string|array $callback The callable to transform collection item before comparison + * + * @return array A sorted array of similar string + */ + private function findAlternatives($name, $collection, $abbrevs, $callback = null) + { + $alternatives = array(); + + foreach ($collection as $item) { + if (null !== $callback) { + $item = call_user_func($callback, $item); + } + + $lev = levenshtein($name, $item); + if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { + $alternatives[$item] = $lev; + } + } + + if (!$alternatives) { + foreach ($abbrevs as $key => $values) { + $lev = levenshtein($name, $key); + if ($lev <= strlen($name) / 3 || false !== strpos($key, $name)) { + foreach ($values as $value) { + $alternatives[$value] = $lev; + } + } + } + } + + asort($alternatives); + + return array_keys($alternatives); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/CHANGELOG.md b/vendor/symfony/console/Symfony/Component/Console/CHANGELOG.md new file mode 100644 index 0000000..79449d8 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/CHANGELOG.md @@ -0,0 +1,19 @@ +CHANGELOG +========= + +2.1.0 +----- + + * added ConsoleOutputInterface + * added the possibility to disable a command (Command::isEnabled()) + * added suggestions when a command does not exist + * added a --raw option to the list command + * added support for STDERR in the console output class (errors are now sent + to STDERR) + * made the defaults (helper set, commands, input definition) in Application + more easily customizable + * added support for the shell even if readline is not available + * added support for process isolation in Symfony shell via + `--process-isolation` switch + * added support for `--`, which disables options parsing after that point + (tokens will be parsed as arguments) diff --git a/vendor/symfony/console/Symfony/Component/Console/Command/Command.php b/vendor/symfony/console/Symfony/Component/Console/Command/Command.php new file mode 100644 index 0000000..001e364 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Command/Command.php @@ -0,0 +1,614 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Helper\HelperSet; + +/** + * Base class for all commands. + * + * @author Fabien Potencier + * + * @api + */ +class Command +{ + private $application; + private $name; + private $aliases; + private $definition; + private $help; + private $description; + private $ignoreValidationErrors; + private $applicationDefinitionMerged; + private $code; + private $synopsis; + private $helperSet; + + /** + * Constructor. + * + * @param string $name The name of the command + * + * @throws \LogicException When the command name is empty + * + * @api + */ + public function __construct($name = null) + { + $this->definition = new InputDefinition(); + $this->ignoreValidationErrors = false; + $this->applicationDefinitionMerged = false; + $this->aliases = array(); + + if (null !== $name) { + $this->setName($name); + } + + $this->configure(); + + if (!$this->name) { + throw new \LogicException('The command name cannot be empty.'); + } + } + + /** + * Ignores validation errors. + * + * This is mainly useful for the help command. + */ + public function ignoreValidationErrors() + { + $this->ignoreValidationErrors = true; + } + + /** + * Sets the application instance for this command. + * + * @param Application $application An Application instance + * + * @api + */ + public function setApplication(Application $application = null) + { + $this->application = $application; + if ($application) { + $this->setHelperSet($application->getHelperSet()); + } else { + $this->helperSet = null; + } + } + + /** + * Sets the helper set. + * + * @param HelperSet $helperSet A HelperSet instance + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + + /** + * Gets the helper set. + * + * @return HelperSet A HelperSet instance + */ + public function getHelperSet() + { + return $this->helperSet; + } + + /** + * Gets the application instance for this command. + * + * @return Application An Application instance + * + * @api + */ + public function getApplication() + { + return $this->application; + } + + /** + * Checks whether the command is enabled or not in the current environment + * + * Override this to check for x or y and return false if the command can not + * run properly under the current conditions. + * + * @return Boolean + */ + public function isEnabled() + { + return true; + } + + /** + * Configures the current command. + */ + protected function configure() + { + } + + /** + * Executes the current command. + * + * This method is not abstract because you can use this class + * as a concrete class. In this case, instead of defining the + * execute() method, you set the code to execute by passing + * a Closure to the setCode() method. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return integer 0 if everything went fine, or an error code + * + * @throws \LogicException When this abstract method is not implemented + * @see setCode() + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + throw new \LogicException('You must override the execute() method in the concrete command class.'); + } + + /** + * Interacts with the user. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + } + + /** + * Initializes the command just after the input has been validated. + * + * This is mainly useful when a lot of commands extends one main command + * where some things need to be initialized based on the input arguments and options. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + */ + protected function initialize(InputInterface $input, OutputInterface $output) + { + } + + /** + * Runs the command. + * + * The code to execute is either defined directly with the + * setCode() method or by overriding the execute() method + * in a sub-class. + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return integer The command exit code + * + * @see setCode() + * @see execute() + * + * @api + */ + public function run(InputInterface $input, OutputInterface $output) + { + // force the creation of the synopsis before the merge with the app definition + $this->getSynopsis(); + + // add the application arguments and options + $this->mergeApplicationDefinition(); + + // bind the input against the command specific arguments/options + try { + $input->bind($this->definition); + } catch (\Exception $e) { + if (!$this->ignoreValidationErrors) { + throw $e; + } + } + + $this->initialize($input, $output); + + if ($input->isInteractive()) { + $this->interact($input, $output); + } + + $input->validate(); + + if ($this->code) { + return call_user_func($this->code, $input, $output); + } + + return $this->execute($input, $output); + } + + /** + * Sets the code to execute when running this command. + * + * If this method is used, it overrides the code defined + * in the execute() method. + * + * @param \Closure $code A \Closure + * + * @return Command The current instance + * + * @see execute() + * + * @api + */ + public function setCode(\Closure $code) + { + $this->code = $code; + + return $this; + } + + /** + * Merges the application definition with the command definition. + */ + private function mergeApplicationDefinition() + { + if (null === $this->application || true === $this->applicationDefinitionMerged) { + return; + } + + $currentArguments = $this->definition->getArguments(); + $this->definition->setArguments($this->application->getDefinition()->getArguments()); + $this->definition->addArguments($currentArguments); + + $this->definition->addOptions($this->application->getDefinition()->getOptions()); + + $this->applicationDefinitionMerged = true; + } + + /** + * Sets an array of argument and option instances. + * + * @param array|InputDefinition $definition An array of argument and option instances or a definition instance + * + * @return Command The current instance + * + * @api + */ + public function setDefinition($definition) + { + if ($definition instanceof InputDefinition) { + $this->definition = $definition; + } else { + $this->definition->setDefinition($definition); + } + + $this->applicationDefinitionMerged = false; + + return $this; + } + + /** + * Gets the InputDefinition attached to this Command. + * + * @return InputDefinition An InputDefinition instance + * + * @api + */ + public function getDefinition() + { + return $this->definition; + } + + /** + * Gets the InputDefinition to be used to create XML and Text representations of this Command. + * + * Can be overridden to provide the original command representation when it would otherwise + * be changed by merging with the application InputDefinition. + * + * @return InputDefinition An InputDefinition instance + */ + protected function getNativeDefinition() + { + return $this->getDefinition(); + } + + /** + * Adds an argument. + * + * @param string $name The argument name + * @param integer $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL + * @param string $description A description text + * @param mixed $default The default value (for InputArgument::OPTIONAL mode only) + * + * @return Command The current instance + * + * @api + */ + public function addArgument($name, $mode = null, $description = '', $default = null) + { + $this->definition->addArgument(new InputArgument($name, $mode, $description, $default)); + + return $this; + } + + /** + * Adds an option. + * + * @param string $name The option name + * @param string $shortcut The shortcut (can be null) + * @param integer $mode The option mode: One of the InputOption::VALUE_* constants + * @param string $description A description text + * @param mixed $default The default value (must be null for InputOption::VALUE_REQUIRED or InputOption::VALUE_NONE) + * + * @return Command The current instance + * + * @api + */ + public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null) + { + $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default)); + + return $this; + } + + /** + * Sets the name of the command. + * + * This method can set both the namespace and the name if + * you separate them by a colon (:) + * + * $command->setName('foo:bar'); + * + * @param string $name The command name + * + * @return Command The current instance + * + * @throws \InvalidArgumentException When command name given is empty + * + * @api + */ + public function setName($name) + { + $this->validateName($name); + + $this->name = $name; + + return $this; + } + + /** + * Returns the command name. + * + * @return string The command name + * + * @api + */ + public function getName() + { + return $this->name; + } + + /** + * Sets the description for the command. + * + * @param string $description The description for the command + * + * @return Command The current instance + * + * @api + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * Returns the description for the command. + * + * @return string The description for the command + * + * @api + */ + public function getDescription() + { + return $this->description; + } + + /** + * Sets the help for the command. + * + * @param string $help The help for the command + * + * @return Command The current instance + * + * @api + */ + public function setHelp($help) + { + $this->help = $help; + + return $this; + } + + /** + * Returns the help for the command. + * + * @return string The help for the command + * + * @api + */ + public function getHelp() + { + return $this->help; + } + + /** + * Returns the processed help for the command replacing the %command.name% and + * %command.full_name% patterns with the real values dynamically. + * + * @return string The processed help for the command + */ + public function getProcessedHelp() + { + $name = $this->name; + + $placeholders = array( + '%command.name%', + '%command.full_name%' + ); + $replacements = array( + $name, + $_SERVER['PHP_SELF'].' '.$name + ); + + return str_replace($placeholders, $replacements, $this->getHelp()); + } + + /** + * Sets the aliases for the command. + * + * @param array $aliases An array of aliases for the command + * + * @return Command The current instance + * + * @api + */ + public function setAliases($aliases) + { + foreach ($aliases as $alias) { + $this->validateName($alias); + } + + $this->aliases = $aliases; + + return $this; + } + + /** + * Returns the aliases for the command. + * + * @return array An array of aliases for the command + * + * @api + */ + public function getAliases() + { + return $this->aliases; + } + + /** + * Returns the synopsis for the command. + * + * @return string The synopsis + */ + public function getSynopsis() + { + if (null === $this->synopsis) { + $this->synopsis = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis())); + } + + return $this->synopsis; + } + + /** + * Gets a helper instance by name. + * + * @param string $name The helper name + * + * @return mixed The helper value + * + * @throws \InvalidArgumentException if the helper is not defined + * + * @api + */ + public function getHelper($name) + { + return $this->helperSet->get($name); + } + + /** + * Returns a text representation of the command. + * + * @return string A string representing the command + */ + public function asText() + { + $messages = array( + 'Usage:', + ' '.$this->getSynopsis(), + '', + ); + + if ($this->getAliases()) { + $messages[] = 'Aliases: '.implode(', ', $this->getAliases()).''; + } + + $messages[] = $this->getNativeDefinition()->asText(); + + if ($help = $this->getProcessedHelp()) { + $messages[] = 'Help:'; + $messages[] = ' '.str_replace("\n", "\n ", $help)."\n"; + } + + return implode("\n", $messages); + } + + /** + * Returns an XML representation of the command. + * + * @param Boolean $asDom Whether to return a DOM or an XML string + * + * @return string|DOMDocument An XML string representing the command + */ + public function asXml($asDom = false) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = true; + $dom->appendChild($commandXML = $dom->createElement('command')); + $commandXML->setAttribute('id', $this->name); + $commandXML->setAttribute('name', $this->name); + + $commandXML->appendChild($usageXML = $dom->createElement('usage')); + $usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), ''))); + + $commandXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getDescription()))); + + $commandXML->appendChild($helpXML = $dom->createElement('help')); + $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getProcessedHelp()))); + + $commandXML->appendChild($aliasesXML = $dom->createElement('aliases')); + foreach ($this->getAliases() as $alias) { + $aliasesXML->appendChild($aliasXML = $dom->createElement('alias')); + $aliasXML->appendChild($dom->createTextNode($alias)); + } + + $definition = $this->getNativeDefinition()->asXml(true); + $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true)); + $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true)); + + return $asDom ? $dom : $dom->saveXml(); + } + + private function validateName($name) + { + if (!preg_match('/^[^\:]+(\:[^\:]+)*$/', $name)) { + throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); + } + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Command/HelpCommand.php b/vendor/symfony/console/Symfony/Component/Console/Command/HelpCommand.php new file mode 100644 index 0000000..93c8104 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Command/HelpCommand.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Command\Command; + +/** + * HelpCommand displays the help for a given command. + * + * @author Fabien Potencier + */ +class HelpCommand extends Command +{ + private $command; + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->ignoreValidationErrors(); + + $this + ->setName('help') + ->setDefinition(array( + new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'), + new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'), + )) + ->setDescription('Displays help for a command') + ->setHelp(<<%command.name% command displays help for a given command: + + php %command.full_name% list + +You can also output the help as XML by using the --xml option: + + php %command.full_name% --xml list +EOF + ) + ; + } + + /** + * Sets the command + * + * @param Command $command The command to set + */ + public function setCommand(Command $command) + { + $this->command = $command; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if (null === $this->command) { + $this->command = $this->getApplication()->get($input->getArgument('command_name')); + } + + if ($input->getOption('xml')) { + $output->writeln($this->command->asXml(), OutputInterface::OUTPUT_RAW); + } else { + $output->writeln($this->command->asText()); + } + + $this->command = null; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Command/ListCommand.php b/vendor/symfony/console/Symfony/Component/Console/Command/ListCommand.php new file mode 100644 index 0000000..032de16 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Command/ListCommand.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputDefinition; + +/** + * ListCommand displays the list of all available commands for the application. + * + * @author Fabien Potencier + */ +class ListCommand extends Command +{ + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('list') + ->setDefinition($this->createDefinition()) + ->setDescription('Lists commands') + ->setHelp(<<%command.name% command lists all commands: + + php %command.full_name% + +You can also display the commands for a specific namespace: + + php %command.full_name% test + +You can also output the information as XML by using the --xml option: + + php %command.full_name% --xml + +It's also possible to get raw list of commands (useful for embedding command runner): + + php %command.full_name% --raw +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function getNativeDefinition() + { + return $this->createDefinition(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if ($input->getOption('xml')) { + $output->writeln($this->getApplication()->asXml($input->getArgument('namespace')), OutputInterface::OUTPUT_RAW); + } else { + $output->writeln($this->getApplication()->asText($input->getArgument('namespace'), $input->getOption('raw'))); + } + } + + private function createDefinition() + { + return new InputDefinition(array( + new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'), + new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'), + new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), + )); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatter.php b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatter.php new file mode 100644 index 0000000..b16e844 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatter.php @@ -0,0 +1,248 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter class for console output. + * + * @author Konstantin Kudryashov + * + * @api + */ +class OutputFormatter implements OutputFormatterInterface +{ + /** + * The pattern to phrase the format. + */ + const FORMAT_PATTERN = '#(\\\\?)<(/?)([a-z][a-z0-9_=;-]+)?>((?:(?!\\\\?<).)*)#is'; + + private $decorated; + private $styles = array(); + private $styleStack; + + /** + * Escapes "<" special char in given text. + * + * @param string $text Text to escape + * + * @return string Escaped text + */ + public static function escape($text) + { + return preg_replace('/([^\\\\]?) FormatterStyle" instances + * + * @api + */ + public function __construct($decorated = null, array $styles = array()) + { + $this->decorated = (Boolean) $decorated; + + $this->setStyle('error', new OutputFormatterStyle('white', 'red')); + $this->setStyle('info', new OutputFormatterStyle('green')); + $this->setStyle('comment', new OutputFormatterStyle('yellow')); + $this->setStyle('question', new OutputFormatterStyle('black', 'cyan')); + + foreach ($styles as $name => $style) { + $this->setStyle($name, $style); + } + + $this->styleStack = new OutputFormatterStyleStack(); + } + + /** + * Sets the decorated flag. + * + * @param Boolean $decorated Whether to decorate the messages or not + * + * @api + */ + public function setDecorated($decorated) + { + $this->decorated = (Boolean) $decorated; + } + + /** + * Gets the decorated flag. + * + * @return Boolean true if the output will decorate messages, false otherwise + * + * @api + */ + public function isDecorated() + { + return $this->decorated; + } + + /** + * Sets a new style. + * + * @param string $name The style name + * @param OutputFormatterStyleInterface $style The style instance + * + * @api + */ + public function setStyle($name, OutputFormatterStyleInterface $style) + { + $this->styles[strtolower($name)] = $style; + } + + /** + * Checks if output formatter has style with specified name. + * + * @param string $name + * + * @return Boolean + * + * @api + */ + public function hasStyle($name) + { + return isset($this->styles[strtolower($name)]); + } + + /** + * Gets style options from style with specified name. + * + * @param string $name + * + * @return OutputFormatterStyleInterface + * + * @throws \InvalidArgumentException When style isn't defined + * + * @api + */ + public function getStyle($name) + { + if (!$this->hasStyle($name)) { + throw new \InvalidArgumentException('Undefined style: '.$name); + } + + return $this->styles[strtolower($name)]; + } + + /** + * Formats a message according to the given styles. + * + * @param string $message The message to style + * + * @return string The styled message + * + * @api + */ + public function format($message) + { + $message = preg_replace_callback(self::FORMAT_PATTERN, array($this, 'replaceStyle'), $message); + + return str_replace('\\<', '<', $message); + } + + /** + * @return OutputFormatterStyleStack + */ + public function getStyleStack() + { + return $this->styleStack; + } + + /** + * Replaces style of the output. + * + * @param array $match + * + * @return string The replaced style + */ + private function replaceStyle($match) + { + // we got "\<" escaped char + if ('\\' === $match[1]) { + return $this->applyCurrentStyle($match[0]); + } + + if ('' === $match[3]) { + if ('/' === $match[2]) { + // we got "" tag + $this->styleStack->pop(); + + return $this->applyCurrentStyle($match[4]); + } + + // we got "<>" tag + return '<>'.$this->applyCurrentStyle($match[4]); + } + + if (isset($this->styles[strtolower($match[3])])) { + $style = $this->styles[strtolower($match[3])]; + } else { + $style = $this->createStyleFromString($match[3]); + + if (false === $style) { + return $this->applyCurrentStyle($match[0]); + } + } + + if ('/' === $match[2]) { + $this->styleStack->pop($style); + } else { + $this->styleStack->push($style); + } + + return $this->applyCurrentStyle($match[4]); + } + + /** + * Tries to create new style instance from string. + * + * @param string $string + * + * @return OutputFormatterStyle|Boolean false if string is not format string + */ + private function createStyleFromString($string) + { + if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) { + return false; + } + + $style = new OutputFormatterStyle(); + foreach ($matches as $match) { + array_shift($match); + + if ('fg' == $match[0]) { + $style->setForeground($match[1]); + } elseif ('bg' == $match[0]) { + $style->setBackground($match[1]); + } else { + $style->setOption($match[1]); + } + } + + return $style; + } + + /** + * Applies current style from stack to text, if must be applied. + * + * @param string $text Input text + * + * @return string string Styled text + */ + private function applyCurrentStyle($text) + { + return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterInterface.php b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterInterface.php new file mode 100644 index 0000000..0836084 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterInterface.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter interface for console output. + * + * @author Konstantin Kudryashov + * + * @api + */ +interface OutputFormatterInterface +{ + /** + * Sets the decorated flag. + * + * @param Boolean $decorated Whether to decorate the messages or not + * + * @api + */ + public function setDecorated($decorated); + + /** + * Gets the decorated flag. + * + * @return Boolean true if the output will decorate messages, false otherwise + * + * @api + */ + public function isDecorated(); + + /** + * Sets a new style. + * + * @param string $name The style name + * @param OutputFormatterStyleInterface $style The style instance + * + * @api + */ + public function setStyle($name, OutputFormatterStyleInterface $style); + + /** + * Checks if output formatter has style with specified name. + * + * @param string $name + * + * @return Boolean + * + * @api + */ + public function hasStyle($name); + + /** + * Gets style options from style with specified name. + * + * @param string $name + * + * @return OutputFormatterStyleInterface + * + * @api + */ + public function getStyle($name); + + /** + * Formats a message according to the given styles. + * + * @param string $message The message to style + * + * @return string The styled message + * + * @api + */ + public function format($message); +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyle.php b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyle.php new file mode 100644 index 0000000..ec47169 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyle.php @@ -0,0 +1,222 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter style class for defining styles. + * + * @author Konstantin Kudryashov + * + * @api + */ +class OutputFormatterStyle implements OutputFormatterStyleInterface +{ + private static $availableForegroundColors = array( + 'black' => 30, + 'red' => 31, + 'green' => 32, + 'yellow' => 33, + 'blue' => 34, + 'magenta' => 35, + 'cyan' => 36, + 'white' => 37 + ); + private static $availableBackgroundColors = array( + 'black' => 40, + 'red' => 41, + 'green' => 42, + 'yellow' => 43, + 'blue' => 44, + 'magenta' => 45, + 'cyan' => 46, + 'white' => 47 + ); + private static $availableOptions = array( + 'bold' => 1, + 'underscore' => 4, + 'blink' => 5, + 'reverse' => 7, + 'conceal' => 8 + ); + + private $foreground; + private $background; + private $options = array(); + + /** + * Initializes output formatter style. + * + * @param string $foreground The style foreground color name + * @param string $background The style background color name + * @param array $options The style options + * + * @api + */ + public function __construct($foreground = null, $background = null, array $options = array()) + { + if (null !== $foreground) { + $this->setForeground($foreground); + } + if (null !== $background) { + $this->setBackground($background); + } + if (count($options)) { + $this->setOptions($options); + } + } + + /** + * Sets style foreground color. + * + * @param string $color The color name + * + * @throws \InvalidArgumentException When the color name isn't defined + * + * @api + */ + public function setForeground($color = null) + { + if (null === $color) { + $this->foreground = null; + + return; + } + + if (!isset(static::$availableForegroundColors[$color])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid foreground color specified: "%s". Expected one of (%s)', + $color, + implode(', ', array_keys(static::$availableForegroundColors)) + )); + } + + $this->foreground = static::$availableForegroundColors[$color]; + } + + /** + * Sets style background color. + * + * @param string $color The color name + * + * @throws \InvalidArgumentException When the color name isn't defined + * + * @api + */ + public function setBackground($color = null) + { + if (null === $color) { + $this->background = null; + + return; + } + + if (!isset(static::$availableBackgroundColors[$color])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid background color specified: "%s". Expected one of (%s)', + $color, + implode(', ', array_keys(static::$availableBackgroundColors)) + )); + } + + $this->background = static::$availableBackgroundColors[$color]; + } + + /** + * Sets some specific style option. + * + * @param string $option The option name + * + * @throws \InvalidArgumentException When the option name isn't defined + * + * @api + */ + public function setOption($option) + { + if (!isset(static::$availableOptions[$option])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid option specified: "%s". Expected one of (%s)', + $option, + implode(', ', array_keys(static::$availableOptions)) + )); + } + + if (false === array_search(static::$availableOptions[$option], $this->options)) { + $this->options[] = static::$availableOptions[$option]; + } + } + + /** + * Unsets some specific style option. + * + * @param string $option The option name + * + * @throws \InvalidArgumentException When the option name isn't defined + * + */ + public function unsetOption($option) + { + if (!isset(static::$availableOptions[$option])) { + throw new \InvalidArgumentException(sprintf( + 'Invalid option specified: "%s". Expected one of (%s)', + $option, + implode(', ', array_keys(static::$availableOptions)) + )); + } + + $pos = array_search(static::$availableOptions[$option], $this->options); + if (false !== $pos) { + unset($this->options[$pos]); + } + } + + /** + * Sets multiple style options at once. + * + * @param array $options + */ + public function setOptions(array $options) + { + $this->options = array(); + + foreach ($options as $option) { + $this->setOption($option); + } + } + + /** + * Applies the style to a given text. + * + * @param string $text The text to style + * + * @return string + */ + public function apply($text) + { + $codes = array(); + + if (null !== $this->foreground) { + $codes[] = $this->foreground; + } + if (null !== $this->background) { + $codes[] = $this->background; + } + if (count($this->options)) { + $codes = array_merge($codes, $this->options); + } + + if (0 === count($codes)) { + return $text; + } + + return sprintf("\033[%sm%s\033[0m", implode(';', $codes), $text); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php new file mode 100644 index 0000000..e8642b3 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * Formatter style interface for defining styles. + * + * @author Konstantin Kudryashov + * + * @api + */ +interface OutputFormatterStyleInterface +{ + /** + * Sets style foreground color. + * + * @param string $color The color name + * + * @api + */ + public function setForeground($color = null); + + /** + * Sets style background color. + * + * @param string $color The color name + * + * @api + */ + public function setBackground($color = null); + + /** + * Sets some specific style option. + * + * @param string $option The option name + * + * @api + */ + public function setOption($option); + + /** + * Unsets some specific style option. + * + * @param string $option The option name + */ + public function unsetOption($option); + + /** + * Sets multiple style options at once. + * + * @param array $options + */ + public function setOptions(array $options); + + /** + * Applies the style to a given text. + * + * @param string $text The text to style + * + * @return string + */ + public function apply($text); +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php new file mode 100644 index 0000000..5915023 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Formatter; + +/** + * @author Jean-François Simon + */ +class OutputFormatterStyleStack +{ + /** + * @var OutputFormatterStyleInterface[] + */ + private $styles; + + /** + * @var OutputFormatterStyleInterface + */ + private $emptyStyle; + + /** + * Constructor. + * + * @param OutputFormatterStyleInterface $emptyStyle + */ + public function __construct(OutputFormatterStyleInterface $emptyStyle = null) + { + $this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle(); + $this->reset(); + } + + /** + * Resets stack (ie. empty internal arrays). + */ + public function reset() + { + $this->styles = array(); + } + + /** + * Pushes a style in the stack. + * + * @param OutputFormatterStyleInterface $style + */ + public function push(OutputFormatterStyleInterface $style) + { + $this->styles[] = $style; + } + + /** + * Pops a style from the stack. + * + * @param OutputFormatterStyleInterface $style + * + * @return OutputFormatterStyleInterface + * + * @throws \InvalidArgumentException When style tags incorrectly nested + */ + public function pop(OutputFormatterStyleInterface $style = null) + { + if (empty($this->styles)) { + return $this->emptyStyle; + } + + if (null === $style) { + return array_pop($this->styles); + } + + foreach (array_reverse($this->styles, true) as $index => $stackedStyle) { + if ($style->apply('') === $stackedStyle->apply('')) { + $this->styles = array_slice($this->styles, 0, $index); + + return $stackedStyle; + } + } + + throw new \InvalidArgumentException('Incorrectly nested style tag found.'); + } + + /** + * Computes current style with stacks top codes. + * + * @return OutputFormatterStyle + */ + public function getCurrent() + { + if (empty($this->styles)) { + return $this->emptyStyle; + } + + return $this->styles[count($this->styles)-1]; + } + + /** + * @param OutputFormatterStyleInterface $emptyStyle + * + * @return OutputFormatterStyleStack + */ + public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle) + { + $this->emptyStyle = $emptyStyle; + + return $this; + } + + /** + * @return OutputFormatterStyleInterface + */ + public function getEmptyStyle() + { + return $this->emptyStyle; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Helper/DialogHelper.php b/vendor/symfony/console/Symfony/Component/Console/Helper/DialogHelper.php new file mode 100644 index 0000000..03daf8c --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Helper/DialogHelper.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * The Dialog class provides helpers to interact with the user. + * + * @author Fabien Potencier + */ +class DialogHelper extends Helper +{ + private $inputStream; + + /** + * Asks a question to the user. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question to ask + * @param string $default The default answer if none is given by the user + * + * @return string The user answer + * + * @throws \RuntimeException If there is no data to read in the input stream + */ + public function ask(OutputInterface $output, $question, $default = null) + { + $output->write($question); + + $ret = fgets($this->inputStream ?: STDIN, 4096); + if (false === $ret) { + throw new \RuntimeException('Aborted'); + } + $ret = trim($ret); + + return strlen($ret) > 0 ? $ret : $default; + } + + /** + * Asks a confirmation to the user. + * + * The question will be asked until the user answers by nothing, yes, or no. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question to ask + * @param Boolean $default The default answer if the user enters nothing + * + * @return Boolean true if the user has confirmed, false otherwise + */ + public function askConfirmation(OutputInterface $output, $question, $default = true) + { + $answer = 'z'; + while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) { + $answer = $this->ask($output, $question); + } + + if (false === $default) { + return $answer && 'y' == strtolower($answer[0]); + } + + return !$answer || 'y' == strtolower($answer[0]); + } + + /** + * Asks for a value and validates the response. + * + * The validator receives the data to validate. It must return the + * validated data when the data is valid and throw an exception + * otherwise. + * + * @param OutputInterface $output An Output instance + * @param string|array $question The question to ask + * @param callback $validator A PHP callback + * @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite) + * @param string $default The default answer if none is given by the user + * + * @return mixed + * + * @throws \Exception When any of the validators return an error + */ + public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null) + { + $error = null; + while (false === $attempts || $attempts--) { + if (null !== $error) { + $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error')); + } + + $value = $this->ask($output, $question, $default); + + try { + return call_user_func($validator, $value); + } catch (\Exception $error) { + } + } + + throw $error; + } + + /** + * Sets the input stream to read from when interacting with the user. + * + * This is mainly useful for testing purpose. + * + * @param resource $stream The input stream + */ + public function setInputStream($stream) + { + $this->inputStream = $stream; + } + + /** + * Returns the helper's input stream + * + * @return string + */ + public function getInputStream() + { + return $this->inputStream; + } + + /** + * Returns the helper's canonical name. + * + * @return string The helper name + */ + public function getName() + { + return 'dialog'; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Helper/FormatterHelper.php b/vendor/symfony/console/Symfony/Component/Console/Helper/FormatterHelper.php new file mode 100644 index 0000000..34ae394 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Helper/FormatterHelper.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Formatter\OutputFormatter; + +/** + * The Formatter class provides helpers to format messages. + * + * @author Fabien Potencier + */ +class FormatterHelper extends Helper +{ + /** + * Formats a message within a section. + * + * @param string $section The section name + * @param string $message The message + * @param string $style The style to apply to the section + * + * @return string The format section + */ + public function formatSection($section, $message, $style = 'info') + { + return sprintf('<%s>[%s] %s', $style, $section, $style, $message); + } + + /** + * Formats a message as a block of text. + * + * @param string|array $messages The message to write in the block + * @param string $style The style to apply to the whole block + * @param Boolean $large Whether to return a large block + * + * @return string The formatter message + */ + public function formatBlock($messages, $style, $large = false) + { + $messages = (array) $messages; + + $len = 0; + $lines = array(); + foreach ($messages as $message) { + $message = OutputFormatter::escape($message); + $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); + $len = max($this->strlen($message) + ($large ? 4 : 2), $len); + } + + $messages = $large ? array(str_repeat(' ', $len)) : array(); + foreach ($lines as $line) { + $messages[] = $line.str_repeat(' ', $len - $this->strlen($line)); + } + if ($large) { + $messages[] = str_repeat(' ', $len); + } + + foreach ($messages as &$message) { + $message = sprintf('<%s>%s', $style, $message, $style); + } + + return implode("\n", $messages); + } + + /** + * Returns the length of a string, using mb_strlen if it is available. + * + * @param string $string The string to check its length + * + * @return integer The length of the string + */ + private function strlen($string) + { + if (!function_exists('mb_strlen')) { + return strlen($string); + } + + if (false === $encoding = mb_detect_encoding($string)) { + return strlen($string); + } + + return mb_strlen($string, $encoding); + } + + /** + * Returns the helper's canonical name. + * + * @return string The canonical name of the helper + */ + public function getName() + { + return 'formatter'; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Helper/Helper.php b/vendor/symfony/console/Symfony/Component/Console/Helper/Helper.php new file mode 100644 index 0000000..28488ca --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Helper/Helper.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * Helper is the base class for all helper classes. + * + * @author Fabien Potencier + */ +abstract class Helper implements HelperInterface +{ + protected $helperSet = null; + + /** + * Sets the helper set associated with this helper. + * + * @param HelperSet $helperSet A HelperSet instance + */ + public function setHelperSet(HelperSet $helperSet = null) + { + $this->helperSet = $helperSet; + } + + /** + * Gets the helper set associated with this helper. + * + * @return HelperSet A HelperSet instance + */ + public function getHelperSet() + { + return $this->helperSet; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Helper/HelperInterface.php b/vendor/symfony/console/Symfony/Component/Console/Helper/HelperInterface.php new file mode 100644 index 0000000..6d39449 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Helper/HelperInterface.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * HelperInterface is the interface all helpers must implement. + * + * @author Fabien Potencier + * + * @api + */ +interface HelperInterface +{ + /** + * Sets the helper set associated with this helper. + * + * @param HelperSet $helperSet A HelperSet instance + * + * @api + */ + public function setHelperSet(HelperSet $helperSet = null); + + /** + * Gets the helper set associated with this helper. + * + * @return HelperSet A HelperSet instance + * + * @api + */ + public function getHelperSet(); + + /** + * Returns the canonical name of this helper. + * + * @return string The canonical name + * + * @api + */ + public function getName(); +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Helper/HelperSet.php b/vendor/symfony/console/Symfony/Component/Console/Helper/HelperSet.php new file mode 100644 index 0000000..d95c9a3 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Helper/HelperSet.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Command\Command; + +/** + * HelperSet represents a set of helpers to be used with a command. + * + * @author Fabien Potencier + */ +class HelperSet +{ + private $helpers; + private $command; + + /** + * Constructor. + * + * @param Helper[] $helpers An array of helper. + */ + public function __construct(array $helpers = array()) + { + $this->helpers = array(); + foreach ($helpers as $alias => $helper) { + $this->set($helper, is_int($alias) ? null : $alias); + } + } + + /** + * Sets a helper. + * + * @param HelperInterface $helper The helper instance + * @param string $alias An alias + */ + public function set(HelperInterface $helper, $alias = null) + { + $this->helpers[$helper->getName()] = $helper; + if (null !== $alias) { + $this->helpers[$alias] = $helper; + } + + $helper->setHelperSet($this); + } + + /** + * Returns true if the helper if defined. + * + * @param string $name The helper name + * + * @return Boolean true if the helper is defined, false otherwise + */ + public function has($name) + { + return isset($this->helpers[$name]); + } + + /** + * Gets a helper value. + * + * @param string $name The helper name + * + * @return HelperInterface The helper instance + * + * @throws \InvalidArgumentException if the helper is not defined + */ + public function get($name) + { + if (!$this->has($name)) { + throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name)); + } + + return $this->helpers[$name]; + } + + /** + * Sets the command associated with this helper set. + * + * @param Command $command A Command instance + */ + public function setCommand(Command $command = null) + { + $this->command = $command; + } + + /** + * Gets the command associated with this helper set. + * + * @return Command A Command instance + */ + public function getCommand() + { + return $this->command; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Input/ArgvInput.php b/vendor/symfony/console/Symfony/Component/Console/Input/ArgvInput.php new file mode 100644 index 0000000..3ca9b05 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Input/ArgvInput.php @@ -0,0 +1,313 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * ArgvInput represents an input coming from the CLI arguments. + * + * Usage: + * + * $input = new ArgvInput(); + * + * By default, the `$_SERVER['argv']` array is used for the input values. + * + * This can be overridden by explicitly passing the input values in the constructor: + * + * $input = new ArgvInput($_SERVER['argv']); + * + * If you pass it yourself, don't forget that the first element of the array + * is the name of the running application. + * + * When passing an argument to the constructor, be sure that it respects + * the same rules as the argv one. It's almost always better to use the + * `StringInput` when you want to provide your own input. + * + * @author Fabien Potencier + * + * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02 + * + * @api + */ +class ArgvInput extends Input +{ + private $tokens; + private $parsed; + + /** + * Constructor. + * + * @param array $argv An array of parameters from the CLI (in the argv format) + * @param InputDefinition $definition A InputDefinition instance + * + * @api + */ + public function __construct(array $argv = null, InputDefinition $definition = null) + { + if (null === $argv) { + $argv = $_SERVER['argv']; + } + + // strip the application name + array_shift($argv); + + $this->tokens = $argv; + + parent::__construct($definition); + } + + protected function setTokens(array $tokens) + { + $this->tokens = $tokens; + } + + /** + * Processes command line arguments. + */ + protected function parse() + { + $parseOptions = true; + $this->parsed = $this->tokens; + while (null !== $token = array_shift($this->parsed)) { + if ($parseOptions && '' == $token) { + $this->parseArgument($token); + } elseif ($parseOptions && '--' == $token) { + $parseOptions = false; + } elseif ($parseOptions && 0 === strpos($token, '--')) { + $this->parseLongOption($token); + } elseif ($parseOptions && '-' === $token[0]) { + $this->parseShortOption($token); + } else { + $this->parseArgument($token); + } + } + } + + /** + * Parses a short option. + * + * @param string $token The current token. + */ + private function parseShortOption($token) + { + $name = substr($token, 1); + + if (strlen($name) > 1) { + if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) { + // an option with a value (with no space) + $this->addShortOption($name[0], substr($name, 1)); + } else { + $this->parseShortOptionSet($name); + } + } else { + $this->addShortOption($name, null); + } + } + + /** + * Parses a short option set. + * + * @param string $name The current token + * + * @throws \RuntimeException When option given doesn't exist + */ + private function parseShortOptionSet($name) + { + $len = strlen($name); + for ($i = 0; $i < $len; $i++) { + if (!$this->definition->hasShortcut($name[$i])) { + throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i])); + } + + $option = $this->definition->getOptionForShortcut($name[$i]); + if ($option->acceptValue()) { + $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1)); + + break; + } else { + $this->addLongOption($option->getName(), true); + } + } + } + + /** + * Parses a long option. + * + * @param string $token The current token + */ + private function parseLongOption($token) + { + $name = substr($token, 2); + + if (false !== $pos = strpos($name, '=')) { + $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1)); + } else { + $this->addLongOption($name, null); + } + } + + /** + * Parses an argument. + * + * @param string $token The current token + * + * @throws \RuntimeException When too many arguments are given + */ + private function parseArgument($token) + { + $c = count($this->arguments); + + // if input is expecting another argument, add it + if ($this->definition->hasArgument($c)) { + $arg = $this->definition->getArgument($c); + $this->arguments[$arg->getName()] = $arg->isArray()? array($token) : $token; + + // if last argument isArray(), append token to last argument + } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) { + $arg = $this->definition->getArgument($c - 1); + $this->arguments[$arg->getName()][] = $token; + + // unexpected argument + } else { + throw new \RuntimeException('Too many arguments.'); + } + } + + /** + * Adds a short option value. + * + * @param string $shortcut The short option key + * @param mixed $value The value for the option + * + * @throws \RuntimeException When option given doesn't exist + */ + private function addShortOption($shortcut, $value) + { + if (!$this->definition->hasShortcut($shortcut)) { + throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); + } + + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + + /** + * Adds a long option value. + * + * @param string $name The long option key + * @param mixed $value The value for the option + * + * @throws \RuntimeException When option given doesn't exist + */ + private function addLongOption($name, $value) + { + if (!$this->definition->hasOption($name)) { + throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name)); + } + + $option = $this->definition->getOption($name); + + if (null === $value && $option->acceptValue()) { + // if option accepts an optional or mandatory argument + // let's see if there is one provided + $next = array_shift($this->parsed); + if ('-' !== $next[0]) { + $value = $next; + } else { + array_unshift($this->parsed, $next); + } + } + + if (null === $value) { + if ($option->isValueRequired()) { + throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name)); + } + + $value = $option->isValueOptional() ? $option->getDefault() : true; + } + + if ($option->isArray()) { + $this->options[$name][] = $value; + } else { + $this->options[$name] = $value; + } + } + + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string The value of the first argument or null otherwise + */ + public function getFirstArgument() + { + foreach ($this->tokens as $token) { + if ($token && '-' === $token[0]) { + continue; + } + + return $token; + } + } + + /** + * Returns true if the raw parameters (not parsed) contain a value. + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * + * @return Boolean true if the value is contained in the raw parameters + */ + public function hasParameterOption($values) + { + $values = (array) $values; + + foreach ($this->tokens as $v) { + if (in_array($v, $values)) { + return true; + } + } + + return false; + } + + /** + * Returns the value of a raw option (not parsed). + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param mixed $default The default value to return if no result is found + * + * @return mixed The option value + */ + public function getParameterOption($values, $default = false) + { + $values = (array) $values; + + $tokens = $this->tokens; + while ($token = array_shift($tokens)) { + foreach ($values as $value) { + if (0 === strpos($token, $value)) { + if (false !== $pos = strpos($token, '=')) { + return substr($token, $pos + 1); + } + + return array_shift($tokens); + } + } + } + + return $default; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Input/ArrayInput.php b/vendor/symfony/console/Symfony/Component/Console/Input/ArrayInput.php new file mode 100644 index 0000000..9921fff --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Input/ArrayInput.php @@ -0,0 +1,190 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * ArrayInput represents an input provided as an array. + * + * Usage: + * + * $input = new ArrayInput(array('name' => 'foo', '--bar' => 'foobar')); + * + * @author Fabien Potencier + * + * @api + */ +class ArrayInput extends Input +{ + private $parameters; + + /** + * Constructor. + * + * @param array $parameters An array of parameters + * @param InputDefinition $definition A InputDefinition instance + * + * @api + */ + public function __construct(array $parameters, InputDefinition $definition = null) + { + $this->parameters = $parameters; + + parent::__construct($definition); + } + + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string The value of the first argument or null otherwise + */ + public function getFirstArgument() + { + foreach ($this->parameters as $key => $value) { + if ($key && '-' === $key[0]) { + continue; + } + + return $value; + } + } + + /** + * Returns true if the raw parameters (not parsed) contain a value. + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The values to look for in the raw parameters (can be an array) + * + * @return Boolean true if the value is contained in the raw parameters + */ + public function hasParameterOption($values) + { + $values = (array) $values; + + foreach ($this->parameters as $k => $v) { + if (!is_int($k)) { + $v = $k; + } + + if (in_array($v, $values)) { + return true; + } + } + + return false; + } + + /** + * Returns the value of a raw option (not parsed). + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param mixed $default The default value to return if no result is found + * + * @return mixed The option value + */ + public function getParameterOption($values, $default = false) + { + $values = (array) $values; + + foreach ($this->parameters as $k => $v) { + if (is_int($k) && in_array($v, $values)) { + return true; + } elseif (in_array($k, $values)) { + return $v; + } + } + + return $default; + } + + /** + * Processes command line arguments. + */ + protected function parse() + { + foreach ($this->parameters as $key => $value) { + if (0 === strpos($key, '--')) { + $this->addLongOption(substr($key, 2), $value); + } elseif ('-' === $key[0]) { + $this->addShortOption(substr($key, 1), $value); + } else { + $this->addArgument($key, $value); + } + } + } + + /** + * Adds a short option value. + * + * @param string $shortcut The short option key + * @param mixed $value The value for the option + * + * @throws \InvalidArgumentException When option given doesn't exist + */ + private function addShortOption($shortcut, $value) + { + if (!$this->definition->hasShortcut($shortcut)) { + throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); + } + + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + + /** + * Adds a long option value. + * + * @param string $name The long option key + * @param mixed $value The value for the option + * + * @throws \InvalidArgumentException When option given doesn't exist + * @throws \InvalidArgumentException When a required value is missing + */ + private function addLongOption($name, $value) + { + if (!$this->definition->hasOption($name)) { + throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); + } + + $option = $this->definition->getOption($name); + + if (null === $value) { + if ($option->isValueRequired()) { + throw new \InvalidArgumentException(sprintf('The "--%s" option requires a value.', $name)); + } + + $value = $option->isValueOptional() ? $option->getDefault() : true; + } + + $this->options[$name] = $value; + } + + /** + * Adds an argument value. + * + * @param string $name The argument name + * @param mixed $value The value for the argument + * + * @throws \InvalidArgumentException When argument given doesn't exist + */ + private function addArgument($name, $value) + { + if (!$this->definition->hasArgument($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + $this->arguments[$name] = $value; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Input/Input.php b/vendor/symfony/console/Symfony/Component/Console/Input/Input.php new file mode 100644 index 0000000..70291be --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Input/Input.php @@ -0,0 +1,211 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * Input is the base class for all concrete Input classes. + * + * Three concrete classes are provided by default: + * + * * `ArgvInput`: The input comes from the CLI arguments (argv) + * * `StringInput`: The input is provided as a string + * * `ArrayInput`: The input is provided as an array + * + * @author Fabien Potencier + */ +abstract class Input implements InputInterface +{ + protected $definition; + protected $options; + protected $arguments; + protected $interactive = true; + + /** + * Constructor. + * + * @param InputDefinition $definition A InputDefinition instance + */ + public function __construct(InputDefinition $definition = null) + { + if (null === $definition) { + $this->definition = new InputDefinition(); + } else { + $this->bind($definition); + $this->validate(); + } + } + + /** + * Binds the current Input instance with the given arguments and options. + * + * @param InputDefinition $definition A InputDefinition instance + */ + public function bind(InputDefinition $definition) + { + $this->arguments = array(); + $this->options = array(); + $this->definition = $definition; + + $this->parse(); + } + + /** + * Processes command line arguments. + */ + abstract protected function parse(); + + /** + * Validates the input. + * + * @throws \RuntimeException When not enough arguments are given + */ + public function validate() + { + if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) { + throw new \RuntimeException('Not enough arguments.'); + } + } + + /** + * Checks if the input is interactive. + * + * @return Boolean Returns true if the input is interactive + */ + public function isInteractive() + { + return $this->interactive; + } + + /** + * Sets the input interactivity. + * + * @param Boolean $interactive If the input should be interactive + */ + public function setInteractive($interactive) + { + $this->interactive = (Boolean) $interactive; + } + + /** + * Returns the argument values. + * + * @return array An array of argument values + */ + public function getArguments() + { + return array_merge($this->definition->getArgumentDefaults(), $this->arguments); + } + + /** + * Returns the argument value for a given argument name. + * + * @param string $name The argument name + * + * @return mixed The argument value + * + * @throws \InvalidArgumentException When argument given doesn't exist + */ + public function getArgument($name) + { + if (!$this->definition->hasArgument($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault(); + } + + /** + * Sets an argument value by name. + * + * @param string $name The argument name + * @param string $value The argument value + * + * @throws \InvalidArgumentException When argument given doesn't exist + */ + public function setArgument($name, $value) + { + if (!$this->definition->hasArgument($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + $this->arguments[$name] = $value; + } + + /** + * Returns true if an InputArgument object exists by name or position. + * + * @param string|integer $name The InputArgument name or position + * + * @return Boolean true if the InputArgument object exists, false otherwise + */ + public function hasArgument($name) + { + return $this->definition->hasArgument($name); + } + + /** + * Returns the options values. + * + * @return array An array of option values + */ + public function getOptions() + { + return array_merge($this->definition->getOptionDefaults(), $this->options); + } + + /** + * Returns the option value for a given option name. + * + * @param string $name The option name + * + * @return mixed The option value + * + * @throws \InvalidArgumentException When option given doesn't exist + */ + public function getOption($name) + { + if (!$this->definition->hasOption($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + } + + return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); + } + + /** + * Sets an option value by name. + * + * @param string $name The option name + * @param string $value The option value + * + * @throws \InvalidArgumentException When option given doesn't exist + */ + public function setOption($name, $value) + { + if (!$this->definition->hasOption($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + } + + $this->options[$name] = $value; + } + + /** + * Returns true if an InputOption object exists by name. + * + * @param string $name The InputOption name + * + * @return Boolean true if the InputOption object exists, false otherwise + */ + public function hasOption($name) + { + return $this->definition->hasOption($name); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Input/InputArgument.php b/vendor/symfony/console/Symfony/Component/Console/Input/InputArgument.php new file mode 100644 index 0000000..e7cc935 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Input/InputArgument.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * Represents a command line argument. + * + * @author Fabien Potencier + * + * @api + */ +class InputArgument +{ + const REQUIRED = 1; + const OPTIONAL = 2; + const IS_ARRAY = 4; + + private $name; + private $mode; + private $default; + private $description; + + /** + * Constructor. + * + * @param string $name The argument name + * @param integer $mode The argument mode: self::REQUIRED or self::OPTIONAL + * @param string $description A description text + * @param mixed $default The default value (for self::OPTIONAL mode only) + * + * @throws \InvalidArgumentException When argument mode is not valid + * + * @api + */ + public function __construct($name, $mode = null, $description = '', $default = null) + { + if (null === $mode) { + $mode = self::OPTIONAL; + } elseif (!is_int($mode) || $mode > 7 || $mode < 1) { + throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); + } + + $this->name = $name; + $this->mode = $mode; + $this->description = $description; + + $this->setDefault($default); + } + + /** + * Returns the argument name. + * + * @return string The argument name + */ + public function getName() + { + return $this->name; + } + + /** + * Returns true if the argument is required. + * + * @return Boolean true if parameter mode is self::REQUIRED, false otherwise + */ + public function isRequired() + { + return self::REQUIRED === (self::REQUIRED & $this->mode); + } + + /** + * Returns true if the argument can take multiple values. + * + * @return Boolean true if mode is self::IS_ARRAY, false otherwise + */ + public function isArray() + { + return self::IS_ARRAY === (self::IS_ARRAY & $this->mode); + } + + /** + * Sets the default value. + * + * @param mixed $default The default value + * + * @throws \LogicException When incorrect default value is given + */ + public function setDefault($default = null) + { + if (self::REQUIRED === $this->mode && null !== $default) { + throw new \LogicException('Cannot set a default value except for Parameter::OPTIONAL mode.'); + } + + if ($this->isArray()) { + if (null === $default) { + $default = array(); + } elseif (!is_array($default)) { + throw new \LogicException('A default value for an array argument must be an array.'); + } + } + + $this->default = $default; + } + + /** + * Returns the default value. + * + * @return mixed The default value + */ + public function getDefault() + { + return $this->default; + } + + /** + * Returns the description text. + * + * @return string The description text + */ + public function getDescription() + { + return $this->description; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Input/InputDefinition.php b/vendor/symfony/console/Symfony/Component/Console/Input/InputDefinition.php new file mode 100644 index 0000000..2db9222 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Input/InputDefinition.php @@ -0,0 +1,531 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * A InputDefinition represents a set of valid command line arguments and options. + * + * Usage: + * + * $definition = new InputDefinition(array( + * new InputArgument('name', InputArgument::REQUIRED), + * new InputOption('foo', 'f', InputOption::VALUE_REQUIRED), + * )); + * + * @author Fabien Potencier + * + * @api + */ +class InputDefinition +{ + private $arguments; + private $requiredCount; + private $hasAnArrayArgument = false; + private $hasOptional; + private $options; + private $shortcuts; + + /** + * Constructor. + * + * @param array $definition An array of InputArgument and InputOption instance + * + * @api + */ + public function __construct(array $definition = array()) + { + $this->setDefinition($definition); + } + + /** + * Sets the definition of the input. + * + * @param array $definition The definition array + * + * @api + */ + public function setDefinition(array $definition) + { + $arguments = array(); + $options = array(); + foreach ($definition as $item) { + if ($item instanceof InputOption) { + $options[] = $item; + } else { + $arguments[] = $item; + } + } + + $this->setArguments($arguments); + $this->setOptions($options); + } + + /** + * Sets the InputArgument objects. + * + * @param array $arguments An array of InputArgument objects + * + * @api + */ + public function setArguments($arguments = array()) + { + $this->arguments = array(); + $this->requiredCount = 0; + $this->hasOptional = false; + $this->hasAnArrayArgument = false; + $this->addArguments($arguments); + } + + /** + * Adds an array of InputArgument objects. + * + * @param InputArgument[] $arguments An array of InputArgument objects + * + * @api + */ + public function addArguments($arguments = array()) + { + if (null !== $arguments) { + foreach ($arguments as $argument) { + $this->addArgument($argument); + } + } + } + + /** + * Adds an InputArgument object. + * + * @param InputArgument $argument An InputArgument object + * + * @throws \LogicException When incorrect argument is given + * + * @api + */ + public function addArgument(InputArgument $argument) + { + if (isset($this->arguments[$argument->getName()])) { + throw new \LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName())); + } + + if ($this->hasAnArrayArgument) { + throw new \LogicException('Cannot add an argument after an array argument.'); + } + + if ($argument->isRequired() && $this->hasOptional) { + throw new \LogicException('Cannot add a required argument after an optional one.'); + } + + if ($argument->isArray()) { + $this->hasAnArrayArgument = true; + } + + if ($argument->isRequired()) { + ++$this->requiredCount; + } else { + $this->hasOptional = true; + } + + $this->arguments[$argument->getName()] = $argument; + } + + /** + * Returns an InputArgument by name or by position. + * + * @param string|integer $name The InputArgument name or position + * + * @return InputArgument An InputArgument object + * + * @throws \InvalidArgumentException When argument given doesn't exist + * + * @api + */ + public function getArgument($name) + { + $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments; + + if (!$this->hasArgument($name)) { + throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + } + + return $arguments[$name]; + } + + /** + * Returns true if an InputArgument object exists by name or position. + * + * @param string|integer $name The InputArgument name or position + * + * @return Boolean true if the InputArgument object exists, false otherwise + * + * @api + */ + public function hasArgument($name) + { + $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments; + + return isset($arguments[$name]); + } + + /** + * Gets the array of InputArgument objects. + * + * @return array An array of InputArgument objects + * + * @api + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * Returns the number of InputArguments. + * + * @return integer The number of InputArguments + */ + public function getArgumentCount() + { + return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments); + } + + /** + * Returns the number of required InputArguments. + * + * @return integer The number of required InputArguments + */ + public function getArgumentRequiredCount() + { + return $this->requiredCount; + } + + /** + * Gets the default values. + * + * @return array An array of default values + */ + public function getArgumentDefaults() + { + $values = array(); + foreach ($this->arguments as $argument) { + $values[$argument->getName()] = $argument->getDefault(); + } + + return $values; + } + + /** + * Sets the InputOption objects. + * + * @param array $options An array of InputOption objects + * + * @api + */ + public function setOptions($options = array()) + { + $this->options = array(); + $this->shortcuts = array(); + $this->addOptions($options); + } + + /** + * Adds an array of InputOption objects. + * + * @param InputOption[] $options An array of InputOption objects + * + * @api + */ + public function addOptions($options = array()) + { + foreach ($options as $option) { + $this->addOption($option); + } + } + + /** + * Adds an InputOption object. + * + * @param InputOption $option An InputOption object + * + * @throws \LogicException When option given already exist + * + * @api + */ + public function addOption(InputOption $option) + { + if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { + throw new \LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + } elseif (isset($this->shortcuts[$option->getShortcut()]) && !$option->equals($this->options[$this->shortcuts[$option->getShortcut()]])) { + throw new \LogicException(sprintf('An option with shortcut "%s" already exists.', $option->getShortcut())); + } + + $this->options[$option->getName()] = $option; + if ($option->getShortcut()) { + $this->shortcuts[$option->getShortcut()] = $option->getName(); + } + } + + /** + * Returns an InputOption by name. + * + * @param string $name The InputOption name + * + * @return InputOption A InputOption object + * + * @throws \InvalidArgumentException When option given doesn't exist + * + * @api + */ + public function getOption($name) + { + if (!$this->hasOption($name)) { + throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); + } + + return $this->options[$name]; + } + + /** + * Returns true if an InputOption object exists by name. + * + * @param string $name The InputOption name + * + * @return Boolean true if the InputOption object exists, false otherwise + * + * @api + */ + public function hasOption($name) + { + return isset($this->options[$name]); + } + + /** + * Gets the array of InputOption objects. + * + * @return array An array of InputOption objects + * + * @api + */ + public function getOptions() + { + return $this->options; + } + + /** + * Returns true if an InputOption object exists by shortcut. + * + * @param string $name The InputOption shortcut + * + * @return Boolean true if the InputOption object exists, false otherwise + */ + public function hasShortcut($name) + { + return isset($this->shortcuts[$name]); + } + + /** + * Gets an InputOption by shortcut. + * + * @param string $shortcut the Shortcut name + * + * @return InputOption An InputOption object + */ + public function getOptionForShortcut($shortcut) + { + return $this->getOption($this->shortcutToName($shortcut)); + } + + /** + * Gets an array of default values. + * + * @return array An array of all default values + */ + public function getOptionDefaults() + { + $values = array(); + foreach ($this->options as $option) { + $values[$option->getName()] = $option->getDefault(); + } + + return $values; + } + + /** + * Returns the InputOption name given a shortcut. + * + * @param string $shortcut The shortcut + * + * @return string The InputOption name + * + * @throws \InvalidArgumentException When option given does not exist + */ + private function shortcutToName($shortcut) + { + if (!isset($this->shortcuts[$shortcut])) { + throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); + } + + return $this->shortcuts[$shortcut]; + } + + /** + * Gets the synopsis. + * + * @return string The synopsis + */ + public function getSynopsis() + { + $elements = array(); + foreach ($this->getOptions() as $option) { + $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; + $elements[] = sprintf('['.($option->isValueRequired() ? '%s--%s="..."' : ($option->isValueOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName()); + } + + foreach ($this->getArguments() as $argument) { + $elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : '')); + + if ($argument->isArray()) { + $elements[] = sprintf('... [%sN]', $argument->getName()); + } + } + + return implode(' ', $elements); + } + + /** + * Returns a textual representation of the InputDefinition. + * + * @return string A string representing the InputDefinition + */ + public function asText() + { + // find the largest option or argument name + $max = 0; + foreach ($this->getOptions() as $option) { + $nameLength = strlen($option->getName()) + 2; + if ($option->getShortcut()) { + $nameLength += strlen($option->getShortcut()) + 3; + } + + $max = max($max, $nameLength); + } + foreach ($this->getArguments() as $argument) { + $max = max($max, strlen($argument->getName())); + } + ++$max; + + $text = array(); + + if ($this->getArguments()) { + $text[] = 'Arguments:'; + foreach ($this->getArguments() as $argument) { + if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) { + $default = sprintf(' (default: %s)', $this->formatDefaultValue($argument->getDefault())); + } else { + $default = ''; + } + + $description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $argument->getDescription()); + + $text[] = sprintf(" %-${max}s %s%s", $argument->getName(), $description, $default); + } + + $text[] = ''; + } + + if ($this->getOptions()) { + $text[] = 'Options:'; + + foreach ($this->getOptions() as $option) { + if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) { + $default = sprintf(' (default: %s)', $this->formatDefaultValue($option->getDefault())); + } else { + $default = ''; + } + + $multiple = $option->isArray() ? ' (multiple values allowed)' : ''; + $description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $option->getDescription()); + + $optionMax = $max - strlen($option->getName()) - 2; + $text[] = sprintf(" %s %-${optionMax}s%s%s%s", + '--'.$option->getName(), + $option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '', + $description, + $default, + $multiple + ); + } + + $text[] = ''; + } + + return implode("\n", $text); + } + + /** + * Returns an XML representation of the InputDefinition. + * + * @param Boolean $asDom Whether to return a DOM or an XML string + * + * @return string|DOMDocument An XML string representing the InputDefinition + */ + public function asXml($asDom = false) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = true; + $dom->appendChild($definitionXML = $dom->createElement('definition')); + + $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); + foreach ($this->getArguments() as $argument) { + $argumentsXML->appendChild($argumentXML = $dom->createElement('argument')); + $argumentXML->setAttribute('name', $argument->getName()); + $argumentXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); + $argumentXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); + $argumentXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); + + $argumentXML->appendChild($defaultsXML = $dom->createElement('defaults')); + $defaults = is_array($argument->getDefault()) ? $argument->getDefault() : (is_bool($argument->getDefault()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array())); + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + } + + $definitionXML->appendChild($optionsXML = $dom->createElement('options')); + foreach ($this->getOptions() as $option) { + $optionsXML->appendChild($optionXML = $dom->createElement('option')); + $optionXML->setAttribute('name', '--'.$option->getName()); + $optionXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : ''); + $optionXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); + $optionXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); + $optionXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); + $optionXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); + + if ($option->acceptValue()) { + $optionXML->appendChild($defaultsXML = $dom->createElement('defaults')); + $defaults = is_array($option->getDefault()) ? $option->getDefault() : (is_bool($option->getDefault()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array())); + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + } + } + + return $asDom ? $dom : $dom->saveXml(); + } + + private function formatDefaultValue($default) + { + return json_encode($default); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Input/InputInterface.php b/vendor/symfony/console/Symfony/Component/Console/Input/InputInterface.php new file mode 100644 index 0000000..c39429d --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Input/InputInterface.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * InputInterface is the interface implemented by all input classes. + * + * @author Fabien Potencier + */ +interface InputInterface +{ + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string The value of the first argument or null otherwise + */ + public function getFirstArgument(); + + /** + * Returns true if the raw parameters (not parsed) contain a value. + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The values to look for in the raw parameters (can be an array) + * + * @return Boolean true if the value is contained in the raw parameters + */ + public function hasParameterOption($values); + + /** + * Returns the value of a raw option (not parsed). + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param mixed $default The default value to return if no result is found + * + * @return mixed The option value + */ + public function getParameterOption($values, $default = false); + + /** + * Binds the current Input instance with the given arguments and options. + * + * @param InputDefinition $definition A InputDefinition instance + */ + public function bind(InputDefinition $definition); + + /** + * Validates if arguments given are correct. + * + * Throws an exception when not enough arguments are given. + * + * @throws \RuntimeException + */ + public function validate(); + + /** + * Returns all the given arguments merged with the default values. + * + * @return array + */ + public function getArguments(); + + /** + * Gets argument by name. + * + * @param string $name The name of the argument + * + * @return mixed + */ + public function getArgument($name); + + /** + * Sets an argument value by name. + * + * @param string $name The argument name + * @param string $value The argument value + * + * @throws \InvalidArgumentException When argument given doesn't exist + */ + public function setArgument($name, $value); + + /** + * Returns true if an InputArgument object exists by name or position. + * + * @param string|integer $name The InputArgument name or position + * + * @return Boolean true if the InputArgument object exists, false otherwise + */ + public function hasArgument($name); + + /** + * Returns all the given options merged with the default values. + * + * @return array + */ + public function getOptions(); + + /** + * Gets an option by name. + * + * @param string $name The name of the option + * + * @return mixed + */ + public function getOption($name); + + /** + * Sets an option value by name. + * + * @param string $name The option name + * @param string $value The option value + * + * @throws \InvalidArgumentException When option given doesn't exist + */ + public function setOption($name, $value); + + /** + * Returns true if an InputOption object exists by name. + * + * @param string $name The InputOption name + * + * @return Boolean true if the InputOption object exists, false otherwise + */ + public function hasOption($name); + + /** + * Is this input means interactive? + * + * @return Boolean + */ + public function isInteractive(); + + /** + * Sets the input interactivity. + * + * @param Boolean $interactive If the input should be interactive + */ + public function setInteractive($interactive); +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Input/InputOption.php b/vendor/symfony/console/Symfony/Component/Console/Input/InputOption.php new file mode 100644 index 0000000..e194b32 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Input/InputOption.php @@ -0,0 +1,209 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * Represents a command line option. + * + * @author Fabien Potencier + * + * @api + */ +class InputOption +{ + const VALUE_NONE = 1; + const VALUE_REQUIRED = 2; + const VALUE_OPTIONAL = 4; + const VALUE_IS_ARRAY = 8; + + private $name; + private $shortcut; + private $mode; + private $default; + private $description; + + /** + * Constructor. + * + * @param string $name The option name + * @param string $shortcut The shortcut (can be null) + * @param integer $mode The option mode: One of the VALUE_* constants + * @param string $description A description text + * @param mixed $default The default value (must be null for self::VALUE_REQUIRED or self::VALUE_NONE) + * + * @throws \InvalidArgumentException If option mode is invalid or incompatible + * + * @api + */ + public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null) + { + if (0 === strpos($name, '--')) { + $name = substr($name, 2); + } + + if (empty($name)) { + throw new \InvalidArgumentException('An option name cannot be empty.'); + } + + if (empty($shortcut)) { + $shortcut = null; + } + + if (null !== $shortcut) { + if ('-' === $shortcut[0]) { + $shortcut = substr($shortcut, 1); + } + + if (empty($shortcut)) { + throw new \InvalidArgumentException('An option shortcut cannot be empty.'); + } + } + + if (null === $mode) { + $mode = self::VALUE_NONE; + } elseif (!is_int($mode) || $mode > 15 || $mode < 1) { + throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); + } + + $this->name = $name; + $this->shortcut = $shortcut; + $this->mode = $mode; + $this->description = $description; + + if ($this->isArray() && !$this->acceptValue()) { + throw new \InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.'); + } + + $this->setDefault($default); + } + + /** + * Returns the option shortcut. + * + * @return string The shortcut + */ + public function getShortcut() + { + return $this->shortcut; + } + + /** + * Returns the option name. + * + * @return string The name + */ + public function getName() + { + return $this->name; + } + + /** + * Returns true if the option accepts a value. + * + * @return Boolean true if value mode is not self::VALUE_NONE, false otherwise + */ + public function acceptValue() + { + return $this->isValueRequired() || $this->isValueOptional(); + } + + /** + * Returns true if the option requires a value. + * + * @return Boolean true if value mode is self::VALUE_REQUIRED, false otherwise + */ + public function isValueRequired() + { + return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode); + } + + /** + * Returns true if the option takes an optional value. + * + * @return Boolean true if value mode is self::VALUE_OPTIONAL, false otherwise + */ + public function isValueOptional() + { + return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode); + } + + /** + * Returns true if the option can take multiple values. + * + * @return Boolean true if mode is self::VALUE_IS_ARRAY, false otherwise + */ + public function isArray() + { + return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode); + } + + /** + * Sets the default value. + * + * @param mixed $default The default value + * + * @throws \LogicException When incorrect default value is given + */ + public function setDefault($default = null) + { + if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { + throw new \LogicException('Cannot set a default value when using Option::VALUE_NONE mode.'); + } + + if ($this->isArray()) { + if (null === $default) { + $default = array(); + } elseif (!is_array($default)) { + throw new \LogicException('A default value for an array option must be an array.'); + } + } + + $this->default = $this->acceptValue() ? $default : false; + } + + /** + * Returns the default value. + * + * @return mixed The default value + */ + public function getDefault() + { + return $this->default; + } + + /** + * Returns the description text. + * + * @return string The description text + */ + public function getDescription() + { + return $this->description; + } + + /** + * Checks whether the given option equals this one + * + * @param InputOption $option option to compare + * @return Boolean + */ + public function equals(InputOption $option) + { + return $option->getName() === $this->getName() + && $option->getShortcut() === $this->getShortcut() + && $option->getDefault() === $this->getDefault() + && $option->isArray() === $this->isArray() + && $option->isValueRequired() === $this->isValueRequired() + && $option->isValueOptional() === $this->isValueOptional() + ; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Input/StringInput.php b/vendor/symfony/console/Symfony/Component/Console/Input/StringInput.php new file mode 100644 index 0000000..93b1b83 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Input/StringInput.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Input; + +/** + * StringInput represents an input provided as a string. + * + * Usage: + * + * $input = new StringInput('foo --bar="foobar"'); + * + * @author Fabien Potencier + * + * @api + */ +class StringInput extends ArgvInput +{ + const REGEX_STRING = '([^ ]+?)(?: |(?setTokens($this->tokenize($input)); + } + + /** + * Tokenizes a string. + * + * @param string $input The input to tokenize + * + * @return array An array of tokens + * + * @throws \InvalidArgumentException When unable to parse input (should never happen) + */ + private function tokenize($input) + { + $input = preg_replace('/(\r\n|\r|\n|\t)/', ' ', $input); + + $tokens = array(); + $length = strlen($input); + $cursor = 0; + while ($cursor < $length) { + if (preg_match('/\s+/A', $input, $match, null, $cursor)) { + } elseif (preg_match('/([^="\' ]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) { + $tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2))); + } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) { + $tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2)); + } elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) { + $tokens[] = stripcslashes($match[1]); + } else { + // should never happen + // @codeCoverageIgnoreStart + throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10))); + // @codeCoverageIgnoreEnd + } + + $cursor += strlen($match[0]); + } + + return $tokens; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/LICENSE b/vendor/symfony/console/Symfony/Component/Console/LICENSE new file mode 100644 index 0000000..cdffe7a --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2012 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutput.php b/vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutput.php new file mode 100644 index 0000000..0b7e083 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutput.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; + +/** + * ConsoleOutput is the default class for all CLI output. It uses STDOUT. + * + * This class is a convenient wrapper around `StreamOutput`. + * + * $output = new ConsoleOutput(); + * + * This is equivalent to: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * + * @author Fabien Potencier + * + * @api + */ +class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface +{ + private $stderr; + + /** + * Constructor. + * + * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, + * self::VERBOSITY_VERBOSE) + * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing) + * @param OutputFormatter $formatter Output formatter instance + * + * @api + */ + public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null) + { + $outputStream = 'php://stdout'; + if (!$this->hasStdoutSupport()) { + $outputStream = 'php://output'; + } + + parent::__construct(fopen($outputStream, 'w'), $verbosity, $decorated, $formatter); + + $this->stderr = new StreamOutput(fopen('php://stderr', 'w'), $verbosity, $decorated, $formatter); + } + + public function setDecorated($decorated) + { + parent::setDecorated($decorated); + $this->stderr->setDecorated($decorated); + } + + public function setFormatter(OutputFormatterInterface $formatter) + { + parent::setFormatter($formatter); + $this->stderr->setFormatter($formatter); + } + + public function setVerbosity($level) + { + parent::setVerbosity($level); + $this->stderr->setVerbosity($level); + } + + /** + * @return OutputInterface + */ + public function getErrorOutput() + { + return $this->stderr; + } + + public function setErrorOutput(OutputInterface $error) + { + $this->stderr = $error; + } + + /** + * Returns true if current environment supports writing console output to + * STDOUT. + * + * IBM iSeries (OS400) exhibits character-encoding issues when writing to + * STDOUT and doesn't properly convert ASCII to EBCDIC, resulting in garbage + * output. + * + * @return boolean + */ + protected function hasStdoutSupport() + { + return ('OS400' != php_uname('s')); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutputInterface.php b/vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutputInterface.php new file mode 100644 index 0000000..5006b80 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutputInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * ConsoleOutputInterface is the interface implemented by ConsoleOutput class. + * This adds information about stderr output stream. + * + * @author Dariusz Górecki + */ +interface ConsoleOutputInterface extends OutputInterface +{ + /** + * @return OutputInterface + */ + public function getErrorOutput(); + + public function setErrorOutput(OutputInterface $error); +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Output/NullOutput.php b/vendor/symfony/console/Symfony/Component/Console/Output/NullOutput.php new file mode 100644 index 0000000..783d42b --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Output/NullOutput.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +/** + * NullOutput suppresses all output. + * + * $output = new NullOutput(); + * + * @author Fabien Potencier + * + * @api + */ +class NullOutput extends Output +{ + /** + * Writes a message to the output. + * + * @param string $message A message to write to the output + * @param Boolean $newline Whether to add a newline or not + */ + protected function doWrite($message, $newline) + { + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Output/Output.php b/vendor/symfony/console/Symfony/Component/Console/Output/Output.php new file mode 100644 index 0000000..3866dbc --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Output/Output.php @@ -0,0 +1,180 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\Console\Formatter\OutputFormatter; + +/** + * Base class for output classes. + * + * There are three levels of verbosity: + * + * * normal: no option passed (normal output - information) + * * verbose: -v (more output - debug) + * * quiet: -q (no output) + * + * @author Fabien Potencier + * + * @api + */ +abstract class Output implements OutputInterface +{ + private $verbosity; + private $formatter; + + /** + * Constructor. + * + * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, self::VERBOSITY_VERBOSE) + * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing) + * @param OutputFormatterInterface $formatter Output formatter instance + * + * @api + */ + public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null) + { + $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity; + $this->formatter = null === $formatter ? new OutputFormatter() : $formatter; + $this->formatter->setDecorated((Boolean) $decorated); + } + + /** + * Sets output formatter. + * + * @param OutputFormatterInterface $formatter + * + * @api + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + $this->formatter = $formatter; + } + + /** + * Returns current output formatter instance. + * + * @return OutputFormatterInterface + * + * @api + */ + public function getFormatter() + { + return $this->formatter; + } + + /** + * Sets the decorated flag. + * + * @param Boolean $decorated Whether to decorate the messages or not + * + * @api + */ + public function setDecorated($decorated) + { + $this->formatter->setDecorated((Boolean) $decorated); + } + + /** + * Gets the decorated flag. + * + * @return Boolean true if the output will decorate messages, false otherwise + * + * @api + */ + public function isDecorated() + { + return $this->formatter->isDecorated(); + } + + /** + * Sets the verbosity of the output. + * + * @param integer $level The level of verbosity + * + * @api + */ + public function setVerbosity($level) + { + $this->verbosity = (int) $level; + } + + /** + * Gets the current verbosity of the output. + * + * @return integer The current level of verbosity + * + * @api + */ + public function getVerbosity() + { + return $this->verbosity; + } + + /** + * Writes a message to the output and adds a newline at the end. + * + * @param string|array $messages The message as an array of lines of a single string + * @param integer $type The type of output + * + * @api + */ + public function writeln($messages, $type = 0) + { + $this->write($messages, true, $type); + } + + /** + * Writes a message to the output. + * + * @param string|array $messages The message as an array of lines of a single string + * @param Boolean $newline Whether to add a newline or not + * @param integer $type The type of output + * + * @throws \InvalidArgumentException When unknown output type is given + * + * @api + */ + public function write($messages, $newline = false, $type = 0) + { + if (self::VERBOSITY_QUIET === $this->verbosity) { + return; + } + + $messages = (array) $messages; + + foreach ($messages as $message) { + switch ($type) { + case OutputInterface::OUTPUT_NORMAL: + $message = $this->formatter->format($message); + break; + case OutputInterface::OUTPUT_RAW: + break; + case OutputInterface::OUTPUT_PLAIN: + $message = strip_tags($this->formatter->format($message)); + break; + default: + throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type)); + } + + $this->doWrite($message, $newline); + } + } + + /** + * Writes a message to the output. + * + * @param string $message A message to write to the output + * @param Boolean $newline Whether to add a newline or not + */ + abstract protected function doWrite($message, $newline); +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Output/OutputInterface.php b/vendor/symfony/console/Symfony/Component/Console/Output/OutputInterface.php new file mode 100644 index 0000000..f36ae03 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Output/OutputInterface.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * OutputInterface is the interface implemented by all Output classes. + * + * @author Fabien Potencier + * + * @api + */ +interface OutputInterface +{ + const VERBOSITY_QUIET = 0; + const VERBOSITY_NORMAL = 1; + const VERBOSITY_VERBOSE = 2; + + const OUTPUT_NORMAL = 0; + const OUTPUT_RAW = 1; + const OUTPUT_PLAIN = 2; + + /** + * Writes a message to the output. + * + * @param string|array $messages The message as an array of lines of a single string + * @param Boolean $newline Whether to add a newline or not + * @param integer $type The type of output (0: normal, 1: raw, 2: plain) + * + * @throws \InvalidArgumentException When unknown output type is given + * + * @api + */ + public function write($messages, $newline = false, $type = 0); + + /** + * Writes a message to the output and adds a newline at the end. + * + * @param string|array $messages The message as an array of lines of a single string + * @param integer $type The type of output (0: normal, 1: raw, 2: plain) + * + * @api + */ + public function writeln($messages, $type = 0); + + /** + * Sets the verbosity of the output. + * + * @param integer $level The level of verbosity + * + * @api + */ + public function setVerbosity($level); + + /** + * Gets the current verbosity of the output. + * + * @return integer The current level of verbosity + * + * @api + */ + public function getVerbosity(); + + /** + * Sets the decorated flag. + * + * @param Boolean $decorated Whether to decorate the messages or not + * + * @api + */ + public function setDecorated($decorated); + + /** + * Gets the decorated flag. + * + * @return Boolean true if the output will decorate messages, false otherwise + * + * @api + */ + public function isDecorated(); + + /** + * Sets output formatter. + * + * @param OutputFormatterInterface $formatter + * + * @api + */ + public function setFormatter(OutputFormatterInterface $formatter); + + /** + * Returns current output formatter instance. + * + * @return OutputFormatterInterface + * + * @api + */ + public function getFormatter(); +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Output/StreamOutput.php b/vendor/symfony/console/Symfony/Component/Console/Output/StreamOutput.php new file mode 100644 index 0000000..e00d065 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Output/StreamOutput.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Output; + +use Symfony\Component\Console\Formatter\OutputFormatterInterface; + +/** + * StreamOutput writes the output to a given stream. + * + * Usage: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * + * As `StreamOutput` can use any stream, you can also use a file: + * + * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false)); + * + * @author Fabien Potencier + * + * @api + */ +class StreamOutput extends Output +{ + private $stream; + + /** + * Constructor. + * + * @param mixed $stream A stream resource + * @param integer $verbosity The verbosity level (self::VERBOSITY_QUIET, self::VERBOSITY_NORMAL, + * self::VERBOSITY_VERBOSE) + * @param Boolean $decorated Whether to decorate messages or not (null for auto-guessing) + * @param OutputFormatter $formatter Output formatter instance + * + * @throws \InvalidArgumentException When first argument is not a real stream + * + * @api + */ + public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null) + { + if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) { + throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); + } + + $this->stream = $stream; + + if (null === $decorated) { + $decorated = $this->hasColorSupport($decorated); + } + + parent::__construct($verbosity, $decorated, $formatter); + } + + /** + * Gets the stream attached to this StreamOutput instance. + * + * @return resource A stream resource + */ + public function getStream() + { + return $this->stream; + } + + /** + * Writes a message to the output. + * + * @param string $message A message to write to the output + * @param Boolean $newline Whether to add a newline or not + * + * @throws \RuntimeException When unable to write output (should never happen) + */ + protected function doWrite($message, $newline) + { + if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) { + // @codeCoverageIgnoreStart + // should never happen + throw new \RuntimeException('Unable to write output.'); + // @codeCoverageIgnoreEnd + } + + fflush($this->stream); + } + + /** + * Returns true if the stream supports colorization. + * + * Colorization is disabled if not supported by the stream: + * + * - windows without ansicon + * - non tty consoles + * + * @return Boolean true if the stream supports colorization, false otherwise + */ + protected function hasColorSupport() + { + // @codeCoverageIgnoreStart + if (DIRECTORY_SEPARATOR == '\\') { + return false !== getenv('ANSICON'); + } + + return function_exists('posix_isatty') && @posix_isatty($this->stream); + // @codeCoverageIgnoreEnd + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/README.md b/vendor/symfony/console/Symfony/Component/Console/README.md new file mode 100644 index 0000000..d817952 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/README.md @@ -0,0 +1,55 @@ +Console Component +================= + +Console eases the creation of beautiful and testable command line interfaces. + +The Application object manages the CLI application: + + use Symfony\Component\Console\Application; + + $console = new Application(); + $console->run(); + +The ``run()`` method parses the arguments and options passed on the command +line and executes the right command. + +Registering a new command can easily be done via the ``register()`` method, +which returns a ``Command`` instance: + + use Symfony\Component\Console\Input\InputInterface; + use Symfony\Component\Console\Input\InputArgument; + use Symfony\Component\Console\Input\InputOption; + use Symfony\Component\Console\Output\OutputInterface; + + $console + ->register('ls') + ->setDefinition(array( + new InputArgument('dir', InputArgument::REQUIRED, 'Directory name'), + )) + ->setDescription('Displays the files in the given directory') + ->setCode(function (InputInterface $input, OutputInterface $output) { + $dir = $input->getArgument('dir'); + + $output->writeln(sprintf('Dir listing for %s', $dir)); + }) + ; + +You can also register new commands via classes. + +The component provides a lot of features like output coloring, input and +output abstractions (so that you can easily unit-test your commands), +validation, automatic help messages, ... + +Tests +--------- + +You can run the unit tests with the following command: + + phpunit + +Resources +--------- + +[The Console Component](http://symfony.com/doc/current/components/console.html) + +[How to create a Console Command](http://symfony.com/doc/current/cookbook/console/console_command.html) diff --git a/vendor/symfony/console/Symfony/Component/Console/Shell.php b/vendor/symfony/console/Symfony/Component/Console/Shell.php new file mode 100644 index 0000000..2dc51b6 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Shell.php @@ -0,0 +1,207 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Process\ProcessBuilder; +use Symfony\Component\Process\PhpExecutableFinder; + +/** + * A Shell wraps an Application to add shell capabilities to it. + * + * Support for history and completion only works with a PHP compiled + * with readline support (either --with-readline or --with-libedit) + * + * @author Fabien Potencier + * @author Martin Hasoň + */ +class Shell +{ + private $application; + private $history; + private $output; + private $hasReadline; + private $prompt; + private $processIsolation; + + /** + * Constructor. + * + * If there is no readline support for the current PHP executable + * a \RuntimeException exception is thrown. + * + * @param Application $application An application instance + */ + public function __construct(Application $application) + { + $this->hasReadline = function_exists('readline'); + $this->application = $application; + $this->history = getenv('HOME').'/.history_'.$application->getName(); + $this->output = new ConsoleOutput(); + $this->prompt = $application->getName().' > '; + $this->processIsolation = false; + } + + /** + * Runs the shell. + */ + public function run() + { + $this->application->setAutoExit(false); + $this->application->setCatchExceptions(true); + + if ($this->hasReadline) { + readline_read_history($this->history); + readline_completion_function(array($this, 'autocompleter')); + } + + $this->output->writeln($this->getHeader()); + $php = null; + if ($this->processIsolation) { + $finder = new PhpExecutableFinder(); + $php = $finder->find(); + $this->output->writeln(<<Running with process isolation, you should consider this: + * each command is executed as separate process, + * commands don't support interactivity, all params must be passed explicitly, + * commands output is not colorized. + +EOF + ); + } + + while (true) { + $command = $this->readline(); + + if (false === $command) { + $this->output->writeln("\n"); + + break; + } + + if ($this->hasReadline) { + readline_add_history($command); + readline_write_history($this->history); + } + + if ($this->processIsolation) { + $pb = new ProcessBuilder(); + + $process = $pb + ->add($php) + ->add($_SERVER['argv'][0]) + ->add($command) + ->inheritEnvironmentVariables(true) + ->getProcess() + ; + + $output = $this->output; + $process->run(function($type, $data) use ($output) { + $output->writeln($data); + }); + + $ret = $process->getExitCode(); + } else { + $ret = $this->application->run(new StringInput($command), $this->output); + } + + if (0 !== $ret) { + $this->output->writeln(sprintf('The command terminated with an error status (%s)', $ret)); + } + } + } + + /** + * Returns the shell header. + * + * @return string The header string + */ + protected function getHeader() + { + return <<{$this->application->getName()} shell ({$this->application->getVersion()}). + +At the prompt, type help for some help, +or list to get a list of available commands. + +To exit the shell, type ^D. + +EOF; + } + + /** + * Tries to return autocompletion for the current entered text. + * + * @param string $text The last segment of the entered text + * + * @return Boolean|array A list of guessed strings or true + */ + private function autocompleter($text) + { + $info = readline_info(); + $text = substr($info['line_buffer'], 0, $info['end']); + + if ($info['point'] !== $info['end']) { + return true; + } + + // task name? + if (false === strpos($text, ' ') || !$text) { + return array_keys($this->application->all()); + } + + // options and arguments? + try { + $command = $this->application->find(substr($text, 0, strpos($text, ' '))); + } catch (\Exception $e) { + return true; + } + + $list = array('--help'); + foreach ($command->getDefinition()->getOptions() as $option) { + $list[] = '--'.$option->getName(); + } + + return $list; + } + + /** + * Reads a single line from standard input. + * + * @return string The single line from standard input + */ + private function readline() + { + if ($this->hasReadline) { + $line = readline($this->prompt); + } else { + $this->output->write($this->prompt); + $line = fgets(STDIN, 1024); + $line = (!$line && strlen($line) == 0) ? false : rtrim($line); + } + + return $line; + } + + public function getProcessIsolation() + { + return $this->processIsolation; + } + + public function setProcessIsolation($processIsolation) + { + $this->processIsolation = (Boolean) $processIsolation; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tester/ApplicationTester.php b/vendor/symfony/console/Symfony/Component/Console/Tester/ApplicationTester.php new file mode 100644 index 0000000..2c576aa --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tester/ApplicationTester.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tester; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\StreamOutput; + +/** + * Eases the testing of console applications. + * + * @author Fabien Potencier + */ +class ApplicationTester +{ + private $application; + private $input; + private $output; + + /** + * Constructor. + * + * @param Application $application An Application instance to test. + */ + public function __construct(Application $application) + { + $this->application = $application; + } + + /** + * Executes the application. + * + * Available options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * + * @param array $input An array of arguments and options + * @param array $options An array of options + * + * @return integer The command exit code + */ + public function run(array $input, $options = array()) + { + $this->input = new ArrayInput($input); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + + $this->output = new StreamOutput(fopen('php://memory', 'w', false)); + if (isset($options['decorated'])) { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) { + $this->output->setVerbosity($options['verbosity']); + } + + return $this->application->run($this->input, $this->output); + } + + /** + * Gets the display returned by the last execution of the application. + * + * @return string The display + */ + public function getDisplay() + { + rewind($this->output->getStream()); + + return stream_get_contents($this->output->getStream()); + } + + /** + * Gets the input instance used by the last execution of the application. + * + * @return InputInterface The current input instance + */ + public function getInput() + { + return $this->input; + } + + /** + * Gets the output instance used by the last execution of the application. + * + * @return OutputInterface The current output instance + */ + public function getOutput() + { + return $this->output; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tester/CommandTester.php b/vendor/symfony/console/Symfony/Component/Console/Tester/CommandTester.php new file mode 100644 index 0000000..c840574 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tester/CommandTester.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tester; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Output\StreamOutput; + +/** + * Eases the testing of console commands. + * + * @author Fabien Potencier + */ +class CommandTester +{ + private $command; + private $input; + private $output; + + /** + * Constructor. + * + * @param Command $command A Command instance to test. + */ + public function __construct(Command $command) + { + $this->command = $command; + } + + /** + * Executes the command. + * + * Available options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * + * @param array $input An array of arguments and options + * @param array $options An array of options + * + * @return integer The command exit code + */ + public function execute(array $input, array $options = array()) + { + $this->input = new ArrayInput($input); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + + $this->output = new StreamOutput(fopen('php://memory', 'w', false)); + if (isset($options['decorated'])) { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) { + $this->output->setVerbosity($options['verbosity']); + } + + return $this->command->run($this->input, $this->output); + } + + /** + * Gets the display returned by the last execution of the command. + * + * @return string The display + */ + public function getDisplay() + { + rewind($this->output->getStream()); + + return stream_get_contents($this->output->getStream()); + } + + /** + * Gets the input instance used by the last execution of the command. + * + * @return InputInterface The current input instance + */ + public function getInput() + { + return $this->input; + } + + /** + * Gets the output instance used by the last execution of the command. + * + * @return OutputInterface The current output instance + */ + public function getOutput() + { + return $this->output; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/ApplicationTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/ApplicationTest.php new file mode 100644 index 0000000..3652d9e --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/ApplicationTest.php @@ -0,0 +1,516 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Tester\ApplicationTester; + +class ApplicationTest extends \PHPUnit_Framework_TestCase +{ + protected static $fixturesPath; + + public static function setUpBeforeClass() + { + self::$fixturesPath = realpath(__DIR__.'/Fixtures/'); + require_once self::$fixturesPath.'/FooCommand.php'; + require_once self::$fixturesPath.'/Foo1Command.php'; + require_once self::$fixturesPath.'/Foo2Command.php'; + require_once self::$fixturesPath.'/Foo3Command.php'; + } + + protected function normalizeLineBreaks($text) + { + return str_replace(PHP_EOL, "\n", $text); + } + + /** + * Replaces the dynamic placeholders of the command help text with a static version. + * The placeholder %command.full_name% includes the script path that is not predictable + * and can not be tested against. + */ + protected function ensureStaticCommandHelp(Application $application) + { + foreach ($application->all() as $command) { + $command->setHelp(str_replace('%command.full_name%', 'app/console %command.name%', $command->getHelp())); + } + } + + public function testConstructor() + { + $application = new Application('foo', 'bar'); + $this->assertEquals('foo', $application->getName(), '__construct() takes the application name as its first argument'); + $this->assertEquals('bar', $application->getVersion(), '__construct() takes the application version as its first argument'); + $this->assertEquals(array('help', 'list'), array_keys($application->all()), '__construct() registered the help and list commands by default'); + } + + public function testSetGetName() + { + $application = new Application(); + $application->setName('foo'); + $this->assertEquals('foo', $application->getName(), '->setName() sets the name of the application'); + } + + public function testSetGetVersion() + { + $application = new Application(); + $application->setVersion('bar'); + $this->assertEquals('bar', $application->getVersion(), '->setVersion() sets the version of the application'); + } + + public function testGetLongVersion() + { + $application = new Application('foo', 'bar'); + $this->assertEquals('foo version bar', $application->getLongVersion(), '->getLongVersion() returns the long version of the application'); + } + + public function testHelp() + { + $application = new Application(); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_gethelp.txt', $this->normalizeLineBreaks($application->getHelp()), '->setHelp() returns a help message'); + } + + public function testAll() + { + $application = new Application(); + $commands = $application->all(); + $this->assertEquals('Symfony\\Component\\Console\\Command\\HelpCommand', get_class($commands['help']), '->all() returns the registered commands'); + + $application->add(new \FooCommand()); + $commands = $application->all('foo'); + $this->assertEquals(1, count($commands), '->all() takes a namespace as its first argument'); + } + + public function testRegister() + { + $application = new Application(); + $command = $application->register('foo'); + $this->assertEquals('foo', $command->getName(), '->register() registers a new command'); + } + + public function testAdd() + { + $application = new Application(); + $application->add($foo = new \FooCommand()); + $commands = $application->all(); + $this->assertEquals($foo, $commands['foo:bar'], '->add() registers a command'); + + $application = new Application(); + $application->addCommands(array($foo = new \FooCommand(), $foo1 = new \Foo1Command())); + $commands = $application->all(); + $this->assertEquals(array($foo, $foo1), array($commands['foo:bar'], $commands['foo:bar1']), '->addCommands() registers an array of commands'); + } + + public function testHasGet() + { + $application = new Application(); + $this->assertTrue($application->has('list'), '->has() returns true if a named command is registered'); + $this->assertFalse($application->has('afoobar'), '->has() returns false if a named command is not registered'); + + $application->add($foo = new \FooCommand()); + $this->assertTrue($application->has('afoobar'), '->has() returns true if an alias is registered'); + $this->assertEquals($foo, $application->get('foo:bar'), '->get() returns a command by name'); + $this->assertEquals($foo, $application->get('afoobar'), '->get() returns a command by alias'); + + try { + $application->get('foofoo'); + $this->fail('->get() throws an \InvalidArgumentException if the command does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->get() throws an \InvalidArgumentException if the command does not exist'); + $this->assertEquals('The command "foofoo" does not exist.', $e->getMessage(), '->get() throws an \InvalidArgumentException if the command does not exist'); + } + + $application = new Application(); + $application->add($foo = new \FooCommand()); + // simulate --help + $r = new \ReflectionObject($application); + $p = $r->getProperty('wantHelps'); + $p->setAccessible(true); + $p->setValue($application, true); + $command = $application->get('foo:bar'); + $this->assertEquals('Symfony\Component\Console\Command\HelpCommand', get_class($command), '->get() returns the help command if --help is provided as the input'); + } + + public function testGetNamespaces() + { + $application = new Application(); + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $this->assertEquals(array('foo'), $application->getNamespaces(), '->getNamespaces() returns an array of unique used namespaces'); + } + + public function testFindNamespace() + { + $application = new Application(); + $application->add(new \FooCommand()); + $this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns the given namespace if it exists'); + $this->assertEquals('foo', $application->findNamespace('f'), '->findNamespace() finds a namespace given an abbreviation'); + $application->add(new \Foo2Command()); + $this->assertEquals('foo', $application->findNamespace('foo'), '->findNamespace() returns the given namespace if it exists'); + try { + $application->findNamespace('f'); + $this->fail('->findNamespace() throws an \InvalidArgumentException if the abbreviation is ambiguous'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->findNamespace() throws an \InvalidArgumentException if the abbreviation is ambiguous'); + $this->assertEquals('The namespace "f" is ambiguous (foo, foo1).', $e->getMessage(), '->findNamespace() throws an \InvalidArgumentException if the abbreviation is ambiguous'); + } + + try { + $application->findNamespace('bar'); + $this->fail('->findNamespace() throws an \InvalidArgumentException if no command is in the given namespace'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->findNamespace() throws an \InvalidArgumentException if no command is in the given namespace'); + $this->assertEquals('There are no commands defined in the "bar" namespace.', $e->getMessage(), '->findNamespace() throws an \InvalidArgumentException if no command is in the given namespace'); + } + } + + public function testFind() + { + $application = new Application(); + $application->add(new \FooCommand()); + $this->assertEquals('FooCommand', get_class($application->find('foo:bar')), '->find() returns a command if its name exists'); + $this->assertEquals('Symfony\Component\Console\Command\HelpCommand', get_class($application->find('h')), '->find() returns a command if its name exists'); + $this->assertEquals('FooCommand', get_class($application->find('f:bar')), '->find() returns a command if the abbreviation for the namespace exists'); + $this->assertEquals('FooCommand', get_class($application->find('f:b')), '->find() returns a command if the abbreviation for the namespace and the command name exist'); + $this->assertEquals('FooCommand', get_class($application->find('a')), '->find() returns a command if the abbreviation exists for an alias'); + + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + + try { + $application->find('f'); + $this->fail('->find() throws an \InvalidArgumentException if the abbreviation is ambiguous for a namespace'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if the abbreviation is ambiguous for a namespace'); + $this->assertRegExp('/Command "f" is not defined./', $e->getMessage(), '->find() throws an \InvalidArgumentException if the abbreviation is ambiguous for a namespace'); + } + + try { + $application->find('a'); + $this->fail('->find() throws an \InvalidArgumentException if the abbreviation is ambiguous for an alias'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if the abbreviation is ambiguous for an alias'); + $this->assertEquals('Command "a" is ambiguous (afoobar, afoobar1 and 1 more).', $e->getMessage(), '->find() throws an \InvalidArgumentException if the abbreviation is ambiguous for an alias'); + } + + try { + $application->find('foo:b'); + $this->fail('->find() throws an \InvalidArgumentException if the abbreviation is ambiguous for a command'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if the abbreviation is ambiguous for a command'); + $this->assertEquals('Command "foo:b" is ambiguous (foo:bar, foo:bar1).', $e->getMessage(), '->find() throws an \InvalidArgumentException if the abbreviation is ambiguous for a command'); + } + } + + public function testFindAlternativeExceptionMessage() + { + $application = new Application(); + $application->add(new \FooCommand()); + + // Command + singular + try { + $application->find('foo:baR'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist, with one alternative'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist, with one alternative'); + $this->assertRegExp('/Did you mean this/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with one alternative'); + } + + // Namespace + singular + try { + $application->find('foO:bar'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist, with one alternative'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist, with one alternative'); + $this->assertRegExp('/Did you mean this/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with one alternative'); + } + + + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + + // Command + plural + try { + $application->find('foo:baR'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + $this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + } + + // Namespace + plural + try { + $application->find('foo2:bar'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + $this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + } + } + + public function testFindAlternativeCommands() + { + $application = new Application(); + + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + + try { + $application->find($commandName = 'Unknown command'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist'); + $this->assertEquals(sprintf('Command "%s" is not defined.', $commandName), $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, without alternatives'); + } + + try { + $application->find($commandName = 'foo'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist'); + $this->assertRegExp(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + $this->assertRegExp('/foo:bar/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternative : "foo:bar"'); + $this->assertRegExp('/foo1:bar/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternative : "foo1:bar"'); + $this->assertRegExp('/foo:bar1/', $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternative : "foo:bar1"'); + } + + // Test if "foo1" command throw an "\InvalidArgumentException" and does not contain + // "foo:bar" as alternative because "foo1" is too far from "foo:bar" + try { + $application->find($commandName = 'foo1'); + $this->fail('->find() throws an \InvalidArgumentException if command does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if command does not exist'); + $this->assertRegExp(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws an \InvalidArgumentException if command does not exist, with alternatives'); + $this->assertFalse(strpos($e->getMessage(), 'foo:bar'), '->find() throws an \InvalidArgumentException if command does not exist, without "foo:bar" alternative'); + } + } + + public function testFindAlternativeNamespace() + { + $application = new Application(); + + $application->add(new \FooCommand()); + $application->add(new \Foo1Command()); + $application->add(new \Foo2Command()); + $application->add(new \foo3Command()); + + try { + $application->find('Unknown-namespace:Unknown-command'); + $this->fail('->find() throws an \InvalidArgumentException if namespace does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if namespace does not exist'); + $this->assertEquals('There are no commands defined in the "Unknown-namespace" namespace.', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, without alternatives'); + } + + try { + $application->find('foo2:command'); + $this->fail('->find() throws an \InvalidArgumentException if namespace does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->find() throws an \InvalidArgumentException if namespace does not exist'); + $this->assertRegExp('/There are no commands defined in the "foo2" namespace./', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative'); + $this->assertRegExp('/foo/', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative : "foo"'); + $this->assertRegExp('/foo1/', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative : "foo1"'); + $this->assertRegExp('/foo3/', $e->getMessage(), '->find() throws an \InvalidArgumentException if namespace does not exist, with alternative : "foo3"'); + } + } + + public function testSetCatchExceptions() + { + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(120)); + $tester = new ApplicationTester($application); + + $application->setCatchExceptions(true); + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->setCatchExceptions() sets the catch exception flag'); + + $application->setCatchExceptions(false); + try { + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->fail('->setCatchExceptions() sets the catch exception flag'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->setCatchExceptions() sets the catch exception flag'); + $this->assertEquals('Command "foo" is not defined.', $e->getMessage(), '->setCatchExceptions() sets the catch exception flag'); + } + } + + public function testAsText() + { + $application = new Application(); + $application->add(new \FooCommand); + $this->ensureStaticCommandHelp($application); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_astext1.txt', $this->normalizeLineBreaks($application->asText()), '->asText() returns a text representation of the application'); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_astext2.txt', $this->normalizeLineBreaks($application->asText('foo')), '->asText() returns a text representation of the application'); + } + + public function testAsXml() + { + $application = new Application(); + $application->add(new \FooCommand); + $this->ensureStaticCommandHelp($application); + $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/application_asxml1.txt', $application->asXml(), '->asXml() returns an XML representation of the application'); + $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/application_asxml2.txt', $application->asXml('foo'), '->asXml() returns an XML representation of the application'); + } + + public function testRenderException() + { + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(120)); + $tester = new ApplicationTester($application); + + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->renderException() renders a pretty exception'); + + $tester->run(array('command' => 'foo'), array('decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE)); + $this->assertContains('Exception trace', $tester->getDisplay(), '->renderException() renders a pretty exception with a stack trace when verbosity is verbose'); + + $tester->run(array('command' => 'list', '--foo' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception2.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->renderException() renders the command synopsis when an exception occurs in the context of a command'); + + $application->add(new \Foo3Command); + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo3:bar'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->renderException() renders a pretty exceptions with previous exceptions'); + + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(32)); + $tester = new ApplicationTester($application); + + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(32)); + $tester = new ApplicationTester($application); + + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception4.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->renderException() wraps messages when they are bigger than the terminal'); + } + + public function testRun() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + $application->add($command = new \Foo1Command()); + $_SERVER['argv'] = array('cli.php', 'foo:bar1'); + + ob_start(); + $application->run(); + ob_end_clean(); + + $this->assertSame('Symfony\Component\Console\Input\ArgvInput', get_class($command->input), '->run() creates an ArgvInput by default if none is given'); + $this->assertSame('Symfony\Component\Console\Output\ConsoleOutput', get_class($command->output), '->run() creates a ConsoleOutput by default if none is given'); + + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $this->ensureStaticCommandHelp($application); + $tester = new ApplicationTester($application); + + $tester->run(array(), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run1.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->run() runs the list command if no argument is passed'); + + $tester->run(array('--help' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run2.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->run() runs the help command if --help is passed'); + + $tester->run(array('-h' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run2.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->run() runs the help command if -h is passed'); + + $tester->run(array('command' => 'list', '--help' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run3.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->run() displays the help if --help is passed'); + + $tester->run(array('command' => 'list', '-h' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run3.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->run() displays the help if -h is passed'); + + $tester->run(array('--ansi' => true)); + $this->assertTrue($tester->getOutput()->isDecorated(), '->run() forces color output if --ansi is passed'); + + $tester->run(array('--no-ansi' => true)); + $this->assertFalse($tester->getOutput()->isDecorated(), '->run() forces color output to be disabled if --no-ansi is passed'); + + $tester->run(array('--version' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run4.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->run() displays the program version if --version is passed'); + + $tester->run(array('-V' => true), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_run4.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->run() displays the program version if -v is passed'); + + $tester->run(array('command' => 'list', '--quiet' => true)); + $this->assertSame('', $tester->getDisplay(), '->run() removes all output if --quiet is passed'); + + $tester->run(array('command' => 'list', '-q' => true)); + $this->assertSame('', $tester->getDisplay(), '->run() removes all output if -q is passed'); + + $tester->run(array('command' => 'list', '--verbose' => true)); + $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if --verbose is passed'); + + $tester->run(array('command' => 'list', '-v' => true)); + $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if -v is passed'); + + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + $application->add(new \FooCommand()); + $tester = new ApplicationTester($application); + + $tester->run(array('command' => 'foo:bar', '--no-interaction' => true), array('decorated' => false)); + $this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if --no-interaction is passed'); + + $tester->run(array('command' => 'foo:bar', '-n' => true), array('decorated' => false)); + $this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if -n is passed'); + } + + /** + * @expectedException \LogicException + * @dataProvider getAddingAlreadySetDefinitionElementData + */ + public function testAddingAlreadySetDefinitionElementData($def) + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + $application + ->register('foo') + ->setDefinition(array($def)) + ->setCode(function (InputInterface $input, OutputInterface $output) {}) + ; + + $input = new ArrayInput(array('command' => 'foo')); + $output = new NullOutput(); + $application->run($input, $output); + } + + public function getAddingAlreadySetDefinitionElementData() + { + return array( + array(new InputArgument('command', InputArgument::REQUIRED)), + array(new InputOption('quiet', '', InputOption::VALUE_NONE)), + array(new InputOption('query', 'q', InputOption::VALUE_NONE)), + ); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Command/CommandTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Command/CommandTest.php new file mode 100644 index 0000000..e248cff --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Command/CommandTest.php @@ -0,0 +1,253 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Command; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\FormatterHelper; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Output\NullOutput; +use Symfony\Component\Console\Tester\CommandTester; + +class CommandTest extends \PHPUnit_Framework_TestCase +{ + protected static $fixturesPath; + + public static function setUpBeforeClass() + { + self::$fixturesPath = __DIR__.'/../Fixtures/'; + require_once self::$fixturesPath.'/TestCommand.php'; + } + + public function testConstructor() + { + try { + $command = new Command(); + $this->fail('__construct() throws a \LogicException if the name is null'); + } catch (\Exception $e) { + $this->assertInstanceOf('\LogicException', $e, '__construct() throws a \LogicException if the name is null'); + $this->assertEquals('The command name cannot be empty.', $e->getMessage(), '__construct() throws a \LogicException if the name is null'); + } + $command = new Command('foo:bar'); + $this->assertEquals('foo:bar', $command->getName(), '__construct() takes the command name as its first argument'); + } + + public function testSetApplication() + { + $application = new Application(); + $command = new \TestCommand(); + $command->setApplication($application); + $this->assertEquals($application, $command->getApplication(), '->setApplication() sets the current application'); + } + + public function testSetGetDefinition() + { + $command = new \TestCommand(); + $ret = $command->setDefinition($definition = new InputDefinition()); + $this->assertEquals($command, $ret, '->setDefinition() implements a fluent interface'); + $this->assertEquals($definition, $command->getDefinition(), '->setDefinition() sets the current InputDefinition instance'); + $command->setDefinition(array(new InputArgument('foo'), new InputOption('bar'))); + $this->assertTrue($command->getDefinition()->hasArgument('foo'), '->setDefinition() also takes an array of InputArguments and InputOptions as an argument'); + $this->assertTrue($command->getDefinition()->hasOption('bar'), '->setDefinition() also takes an array of InputArguments and InputOptions as an argument'); + $command->setDefinition(new InputDefinition()); + } + + public function testAddArgument() + { + $command = new \TestCommand(); + $ret = $command->addArgument('foo'); + $this->assertEquals($command, $ret, '->addArgument() implements a fluent interface'); + $this->assertTrue($command->getDefinition()->hasArgument('foo'), '->addArgument() adds an argument to the command'); + } + + public function testAddOption() + { + $command = new \TestCommand(); + $ret = $command->addOption('foo'); + $this->assertEquals($command, $ret, '->addOption() implements a fluent interface'); + $this->assertTrue($command->getDefinition()->hasOption('foo'), '->addOption() adds an option to the command'); + } + + public function testGetNamespaceGetNameSetName() + { + $command = new \TestCommand(); + $this->assertEquals('namespace:name', $command->getName(), '->getName() returns the command name'); + $command->setName('foo'); + $this->assertEquals('foo', $command->getName(), '->setName() sets the command name'); + + $ret = $command->setName('foobar:bar'); + $this->assertEquals($command, $ret, '->setName() implements a fluent interface'); + $this->assertEquals('foobar:bar', $command->getName(), '->setName() sets the command name'); + + try { + $command->setName(''); + $this->fail('->setName() throws an \InvalidArgumentException if the name is empty'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->setName() throws an \InvalidArgumentException if the name is empty'); + $this->assertEquals('Command name "" is invalid.', $e->getMessage(), '->setName() throws an \InvalidArgumentException if the name is empty'); + } + + try { + $command->setName('foo:'); + $this->fail('->setName() throws an \InvalidArgumentException if the name is empty'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->setName() throws an \InvalidArgumentException if the name is empty'); + $this->assertEquals('Command name "foo:" is invalid.', $e->getMessage(), '->setName() throws an \InvalidArgumentException if the name is empty'); + } + } + + public function testGetSetDescription() + { + $command = new \TestCommand(); + $this->assertEquals('description', $command->getDescription(), '->getDescription() returns the description'); + $ret = $command->setDescription('description1'); + $this->assertEquals($command, $ret, '->setDescription() implements a fluent interface'); + $this->assertEquals('description1', $command->getDescription(), '->setDescription() sets the description'); + } + + public function testGetSetHelp() + { + $command = new \TestCommand(); + $this->assertEquals('help', $command->getHelp(), '->getHelp() returns the help'); + $ret = $command->setHelp('help1'); + $this->assertEquals($command, $ret, '->setHelp() implements a fluent interface'); + $this->assertEquals('help1', $command->getHelp(), '->setHelp() sets the help'); + } + + public function testGetProcessedHelp() + { + $command = new \TestCommand(); + $command->setHelp('The %command.name% command does... Example: php %command.full_name%.'); + $this->assertContains('The namespace:name command does...', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.name% correctly'); + $this->assertNotContains('%command.full_name%', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.full_name%'); + } + + public function testGetSetAliases() + { + $command = new \TestCommand(); + $this->assertEquals(array('name'), $command->getAliases(), '->getAliases() returns the aliases'); + $ret = $command->setAliases(array('name1')); + $this->assertEquals($command, $ret, '->setAliases() implements a fluent interface'); + $this->assertEquals(array('name1'), $command->getAliases(), '->setAliases() sets the aliases'); + } + + public function testGetSynopsis() + { + $command = new \TestCommand(); + $command->addOption('foo'); + $command->addArgument('foo'); + $this->assertEquals('namespace:name [--foo] [foo]', $command->getSynopsis(), '->getSynopsis() returns the synopsis'); + } + + public function testGetHelper() + { + $application = new Application(); + $command = new \TestCommand(); + $command->setApplication($application); + $formatterHelper = new FormatterHelper(); + $this->assertEquals($formatterHelper->getName(), $command->getHelper('formatter')->getName(), '->getHelper() returns the correct helper'); + } + + public function testGet() + { + $application = new Application(); + $command = new \TestCommand(); + $command->setApplication($application); + $formatterHelper = new FormatterHelper(); + $this->assertEquals($formatterHelper->getName(), $command->getHelper('formatter')->getName(), '->__get() returns the correct helper'); + } + + public function testMergeApplicationDefinition() + { + $application1 = new Application(); + $application1->getDefinition()->addArguments(array(new InputArgument('foo'))); + $application1->getDefinition()->addOptions(array(new InputOption('bar'))); + $command = new \TestCommand(); + $command->setApplication($application1); + $command->setDefinition($definition = new InputDefinition(array(new InputArgument('bar'), new InputOption('foo')))); + + $r = new \ReflectionObject($command); + $m = $r->getMethod('mergeApplicationDefinition'); + $m->setAccessible(true); + $m->invoke($command); + $this->assertTrue($command->getDefinition()->hasArgument('foo'), '->mergeApplicationDefinition() merges the application arguments and the command arguments'); + $this->assertTrue($command->getDefinition()->hasArgument('bar'), '->mergeApplicationDefinition() merges the application arguments and the command arguments'); + $this->assertTrue($command->getDefinition()->hasOption('foo'), '->mergeApplicationDefinition() merges the application options and the command options'); + $this->assertTrue($command->getDefinition()->hasOption('bar'), '->mergeApplicationDefinition() merges the application options and the command options'); + + $m->invoke($command); + $this->assertEquals(3, $command->getDefinition()->getArgumentCount(), '->mergeApplicationDefinition() does not try to merge twice the application arguments and options'); + } + + public function testRun() + { + $command = new \TestCommand(); + $tester = new CommandTester($command); + try { + $tester->execute(array('--bar' => true)); + $this->fail('->run() throws a \InvalidArgumentException when the input does not validate the current InputDefinition'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->run() throws a \InvalidArgumentException when the input does not validate the current InputDefinition'); + $this->assertEquals('The "--bar" option does not exist.', $e->getMessage(), '->run() throws a \InvalidArgumentException when the input does not validate the current InputDefinition'); + } + + $tester->execute(array(), array('interactive' => true)); + $this->assertEquals('interact called'.PHP_EOL.'execute called'.PHP_EOL, $tester->getDisplay(), '->run() calls the interact() method if the input is interactive'); + + $tester->execute(array(), array('interactive' => false)); + $this->assertEquals('execute called'.PHP_EOL, $tester->getDisplay(), '->run() does not call the interact() method if the input is not interactive'); + + $command = new Command('foo'); + try { + $command->run(new StringInput(''), new NullOutput()); + $this->fail('->run() throws a \LogicException if the execute() method has not been overridden and no code has been provided'); + } catch (\Exception $e) { + $this->assertInstanceOf('\LogicException', $e, '->run() throws a \LogicException if the execute() method has not been overridden and no code has been provided'); + $this->assertEquals('You must override the execute() method in the concrete command class.', $e->getMessage(), '->run() throws a \LogicException if the execute() method has not been overridden and no code has been provided'); + } + } + + public function testSetCode() + { + $command = new \TestCommand(); + $ret = $command->setCode(function (InputInterface $input, OutputInterface $output) { + $output->writeln('from the code...'); + }); + $this->assertEquals($command, $ret, '->setCode() implements a fluent interface'); + $tester = new CommandTester($command); + $tester->execute(array()); + $this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay()); + } + + public function testAsText() + { + $command = new \TestCommand(); + $command->setApplication(new Application()); + $tester = new CommandTester($command); + $tester->execute(array('command' => $command->getName())); + $this->assertStringEqualsFile(self::$fixturesPath.'/command_astext.txt', $command->asText(), '->asText() returns a text representation of the command'); + } + + public function testAsXml() + { + $command = new \TestCommand(); + $command->setApplication(new Application()); + $tester = new CommandTester($command); + $tester->execute(array('command' => $command->getName())); + $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/command_asxml.txt', $command->asXml(), '->asXml() returns an XML representation of the command'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Command/HelpCommandTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Command/HelpCommandTest.php new file mode 100644 index 0000000..417eea1 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Command/HelpCommandTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Command; + +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Console\Command\HelpCommand; +use Symfony\Component\Console\Command\ListCommand; +use Symfony\Component\Console\Application; + +class HelpCommandTest extends \PHPUnit_Framework_TestCase +{ + public function testExecute() + { + $command = new HelpCommand(); + + $commandTester = new CommandTester($command); + $command->setCommand(new ListCommand()); + $commandTester->execute(array()); + $this->assertRegExp('/list \[--xml\] \[--raw\] \[namespace\]/', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + + $command->setCommand(new ListCommand()); + $commandTester->execute(array('--xml' => true)); + $this->assertRegExp('/getDisplay(), '->execute() returns an XML help text if --xml is passed'); + + $application = new Application(); + $commandTester = new CommandTester($application->get('help')); + $commandTester->execute(array('command_name' => 'list')); + $this->assertRegExp('/list \[--xml\] \[--raw\] \[namespace\]/', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); + + $commandTester->execute(array('command_name' => 'list', '--xml' => true)); + $this->assertRegExp('/getDisplay(), '->execute() returns an XML help text if --xml is passed'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Command/ListCommandTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Command/ListCommandTest.php new file mode 100644 index 0000000..fb0eacc --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Command/ListCommandTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Command; + +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Console\Application; + +class ListCommandTest extends \PHPUnit_Framework_TestCase +{ + public function testExecute() + { + $application = new Application(); + + $commandTester = new CommandTester($command = $application->get('list')); + $commandTester->execute(array('command' => $command->getName()), array('decorated' => false)); + $this->assertRegExp('/help Displays help for a command/', $commandTester->getDisplay(), '->execute() returns a list of available commands'); + + $commandTester->execute(array('command' => $command->getName(), '--xml' => true)); + $this->assertRegExp('//', $commandTester->getDisplay(), '->execute() returns a list of available commands in XML if --xml is passed'); + + $commandTester->execute(array('command' => $command->getName(), '--raw' => true)); + $output = <<assertEquals(str_replace("\n", PHP_EOL, $output), $commandTester->getDisplay(), 'boo'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo1Command.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo1Command.php new file mode 100644 index 0000000..254162f --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo1Command.php @@ -0,0 +1,26 @@ +setName('foo:bar1') + ->setDescription('The foo:bar1 command') + ->setAliases(array('afoobar1')) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->output = $output; + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo2Command.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo2Command.php new file mode 100644 index 0000000..8071dc8 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo2Command.php @@ -0,0 +1,21 @@ +setName('foo1:bar') + ->setDescription('The foo1:bar command') + ->setAliases(array('afoobar2')) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo3Command.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo3Command.php new file mode 100644 index 0000000..7349bc3 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/Foo3Command.php @@ -0,0 +1,25 @@ +setName('foo3:bar') + ->setDescription('The foo3:bar command') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + try { + throw new \Exception("First exception"); + } catch (\Exception $e) { + throw new \Exception("Second exception", 0, $e); + } + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/FooCommand.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/FooCommand.php new file mode 100644 index 0000000..355e0ad --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/FooCommand.php @@ -0,0 +1,33 @@ +setName('foo:bar') + ->setDescription('The foo:bar command') + ->setAliases(array('afoobar')) + ; + } + + protected function interact(InputInterface $input, OutputInterface $output) + { + $output->writeln('interact called'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->output = $output; + + $output->writeln('called'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/TestCommand.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/TestCommand.php new file mode 100644 index 0000000..dcd3273 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/TestCommand.php @@ -0,0 +1,28 @@ +setName('namespace:name') + ->setAliases(array('name')) + ->setDescription('description') + ->setHelp('help') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $output->writeln('execute called'); + } + + protected function interact(InputInterface $input, OutputInterface $output) + { + $output->writeln('interact called'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_astext1.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_astext1.txt new file mode 100644 index 0000000..2f692c0 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_astext1.txt @@ -0,0 +1,20 @@ +Console Tool + +Usage: + [options] command [arguments] + +Options: + --help -h Display this help message. + --quiet -q Do not output any message. + --verbose -v Increase verbosity of messages. + --version -V Display this application version. + --ansi Force ANSI output. + --no-ansi Disable ANSI output. + --no-interaction -n Do not ask any interactive question. + +Available commands: + afoobar The foo:bar command + help Displays help for a command + list Lists commands +foo + foo:bar The foo:bar command \ No newline at end of file diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_astext2.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_astext2.txt new file mode 100644 index 0000000..1457bf7 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_astext2.txt @@ -0,0 +1,16 @@ +Console Tool + +Usage: + [options] command [arguments] + +Options: + --help -h Display this help message. + --quiet -q Do not output any message. + --verbose -v Increase verbosity of messages. + --version -V Display this application version. + --ansi Force ANSI output. + --no-ansi Disable ANSI output. + --no-interaction -n Do not ask any interactive question. + +Available commands for the "foo" namespace: + foo:bar The foo:bar command \ No newline at end of file diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_asxml1.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_asxml1.txt new file mode 100644 index 0000000..ce21a32 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_asxml1.txt @@ -0,0 +1,83 @@ + + + + + help [--xml] [command_name] + Displays help for a command + The <info>help</info> command displays help for a given command: + + <info>php app/console help list</info> + + You can also output the help as XML by using the <comment>--xml</comment> option: + + <info>php app/console help --xml list</info> + + + + The command name + + help + + + + + + + + + list [--xml] [--raw] [namespace] + Lists commands + The <info>list</info> command lists all commands: + + <info>php app/console list</info> + + You can also display the commands for a specific namespace: + + <info>php app/console list test</info> + + You can also output the information as XML by using the <comment>--xml</comment> option: + + <info>php app/console list --xml</info> + + It's also possible to get raw list of commands (useful for embedding command runner): + + <info>php app/console list --raw</info> + + + + The namespace name + + + + + + + + + + foo:bar + The foo:bar command + + + afoobar + + + + + + + + help + list + + + foo:bar + + + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_asxml2.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_asxml2.txt new file mode 100644 index 0000000..9e1f4a1 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_asxml2.txt @@ -0,0 +1,15 @@ + + + + + foo:bar + The foo:bar command + + + afoobar + + + + + + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_gethelp.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_gethelp.txt new file mode 100644 index 0000000..5ad5420 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_gethelp.txt @@ -0,0 +1,13 @@ +Console Tool + +Usage: + [options] command [arguments] + +Options: + --help -h Display this help message. + --quiet -q Do not output any message. + --verbose -v Increase verbosity of messages. + --version -V Display this application version. + --ansi Force ANSI output. + --no-ansi Disable ANSI output. + --no-interaction -n Do not ask any interactive question. \ No newline at end of file diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception1.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception1.txt new file mode 100644 index 0000000..4629345 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception1.txt @@ -0,0 +1,8 @@ + + + + [InvalidArgumentException] + Command "foo" is not defined. + + + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception2.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception2.txt new file mode 100644 index 0000000..56dd52e --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception2.txt @@ -0,0 +1,11 @@ + + + + [InvalidArgumentException] + The "--foo" option does not exist. + + + +list [--xml] [--raw] [namespace] + + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt new file mode 100644 index 0000000..c639924 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt @@ -0,0 +1,19 @@ + + + + [Exception] + Second exception + + + + + + + [Exception] + First exception + + + +foo3:bar + + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception4.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception4.txt new file mode 100644 index 0000000..19f893b --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_renderexception4.txt @@ -0,0 +1,9 @@ + + + + [InvalidArgumentException] + Command "foo" is not define + d. + + + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run1.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run1.txt new file mode 100644 index 0000000..176dc88 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run1.txt @@ -0,0 +1,17 @@ +Console Tool + +Usage: + [options] command [arguments] + +Options: + --help -h Display this help message. + --quiet -q Do not output any message. + --verbose -v Increase verbosity of messages. + --version -V Display this application version. + --ansi Force ANSI output. + --no-ansi Disable ANSI output. + --no-interaction -n Do not ask any interactive question. + +Available commands: + help Displays help for a command + list Lists commands diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run2.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run2.txt new file mode 100644 index 0000000..cad7dd5 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run2.txt @@ -0,0 +1,26 @@ +Usage: + help [--xml] [command_name] + +Arguments: + command The command to execute + command_name The command name (default: "help") + +Options: + --xml To output help as XML + --help (-h) Display this help message. + --quiet (-q) Do not output any message. + --verbose (-v) Increase verbosity of messages. + --version (-V) Display this application version. + --ansi Force ANSI output. + --no-ansi Disable ANSI output. + --no-interaction (-n) Do not ask any interactive question. + +Help: + The help command displays help for a given command: + + php app/console help list + + You can also output the help as XML by using the --xml option: + + php app/console help --xml list + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run3.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run3.txt new file mode 100644 index 0000000..441db54 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run3.txt @@ -0,0 +1,27 @@ +Usage: + list [--xml] [--raw] [namespace] + +Arguments: + namespace The namespace name + +Options: + --xml To output help as XML + --raw To output raw command list + +Help: + The list command lists all commands: + + php app/console list + + You can also display the commands for a specific namespace: + + php app/console list test + + You can also output the information as XML by using the --xml option: + + php app/console list --xml + + It's also possible to get raw list of commands (useful for embedding command runner): + + php app/console list --raw + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run4.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run4.txt new file mode 100644 index 0000000..47187fc --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/application_run4.txt @@ -0,0 +1 @@ +Console Tool diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/command_astext.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/command_astext.txt new file mode 100644 index 0000000..e599903 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/command_astext.txt @@ -0,0 +1,18 @@ +Usage: + namespace:name + +Aliases: name +Arguments: + command The command to execute + +Options: + --help (-h) Display this help message. + --quiet (-q) Do not output any message. + --verbose (-v) Increase verbosity of messages. + --version (-V) Display this application version. + --ansi Force ANSI output. + --no-ansi Disable ANSI output. + --no-interaction (-n) Do not ask any interactive question. + +Help: + help diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/command_asxml.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/command_asxml.txt new file mode 100644 index 0000000..806c5a5 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/command_asxml.txt @@ -0,0 +1,38 @@ + + + namespace:name + description + help + + name + + + + The command to execute + + + + + + + + + + + + + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/definition_astext.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/definition_astext.txt new file mode 100644 index 0000000..9dd5390 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/definition_astext.txt @@ -0,0 +1,11 @@ +Arguments: + foo The foo argument + baz The baz argument (default: true) + bar The bar argument (default: ["bar"]) + +Options: + --foo (-f) The foo option + --baz The baz option (default: false) + --bar (-b) The bar option (default: "bar") + --qux The qux option (default: ["foo","bar"]) (multiple values allowed) + --qux2 The qux2 option (default: {"foo":"bar"}) (multiple values allowed) diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/definition_asxml.txt b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/definition_asxml.txt new file mode 100644 index 0000000..eec8c07 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Fixtures/definition_asxml.txt @@ -0,0 +1,39 @@ + + + + + The foo argument + + + + The baz argument + + true + + + + The bar argument + + bar + + + + + + + + + diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleStackTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleStackTest.php new file mode 100644 index 0000000..e99ebc5 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleStackTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Formatter; + +use Symfony\Component\Console\Formatter\OutputFormatterStyleStack; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; + +class OutputFormatterStyleStackTest extends \PHPUnit_Framework_TestCase +{ + public function testPush() + { + $stack = new OutputFormatterStyleStack(); + $stack->push($s1 = new OutputFormatterStyle('white', 'black')); + $stack->push($s2 = new OutputFormatterStyle('yellow', 'blue')); + + $this->assertEquals($s2, $stack->getCurrent()); + + $stack->push($s3 = new OutputFormatterStyle('green', 'red')); + + $this->assertEquals($s3, $stack->getCurrent()); + } + + public function testPop() + { + $stack = new OutputFormatterStyleStack(); + $stack->push($s1 = new OutputFormatterStyle('white', 'black')); + $stack->push($s2 = new OutputFormatterStyle('yellow', 'blue')); + + $this->assertEquals($s2, $stack->pop()); + $this->assertEquals($s1, $stack->pop()); + } + + public function testPopEmpty() + { + $stack = new OutputFormatterStyleStack(); + $style = new OutputFormatterStyle(); + + $this->assertEquals($style, $stack->pop()); + } + + public function testPopNotLast() + { + $stack = new OutputFormatterStyleStack(); + $stack->push($s1 = new OutputFormatterStyle('white', 'black')); + $stack->push($s2 = new OutputFormatterStyle('yellow', 'blue')); + $stack->push($s3 = new OutputFormatterStyle('green', 'red')); + + $this->assertEquals($s2, $stack->pop($s2)); + $this->assertEquals($s1, $stack->pop()); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testInvalidPop() + { + $stack = new OutputFormatterStyleStack(); + $stack->push(new OutputFormatterStyle('white', 'black')); + $stack->pop(new OutputFormatterStyle('yellow', 'blue')); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php new file mode 100644 index 0000000..b2875e9 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Formatter; + +use Symfony\Component\Console\Formatter\OutputFormatterStyle; + +class OutputFormatterStyleTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $style = new OutputFormatterStyle('green', 'black', array('bold', 'underscore')); + $this->assertEquals("\033[32;40;1;4mfoo\033[0m", $style->apply('foo')); + + $style = new OutputFormatterStyle('red', null, array('blink')); + $this->assertEquals("\033[31;5mfoo\033[0m", $style->apply('foo')); + + $style = new OutputFormatterStyle(null, 'white'); + $this->assertEquals("\033[47mfoo\033[0m", $style->apply('foo')); + } + + public function testForeground() + { + $style = new OutputFormatterStyle(); + + $style->setForeground('black'); + $this->assertEquals("\033[30mfoo\033[0m", $style->apply('foo')); + + $style->setForeground('blue'); + $this->assertEquals("\033[34mfoo\033[0m", $style->apply('foo')); + + $this->setExpectedException('InvalidArgumentException'); + $style->setForeground('undefined-color'); + } + + public function testBackground() + { + $style = new OutputFormatterStyle(); + + $style->setBackground('black'); + $this->assertEquals("\033[40mfoo\033[0m", $style->apply('foo')); + + $style->setBackground('yellow'); + $this->assertEquals("\033[43mfoo\033[0m", $style->apply('foo')); + + $this->setExpectedException('InvalidArgumentException'); + $style->setBackground('undefined-color'); + } + + public function testOptions() + { + $style = new OutputFormatterStyle(); + + $style->setOptions(array('reverse', 'conceal')); + $this->assertEquals("\033[7;8mfoo\033[0m", $style->apply('foo')); + + $style->setOption('bold'); + $this->assertEquals("\033[7;8;1mfoo\033[0m", $style->apply('foo')); + + $style->unsetOption('reverse'); + $this->assertEquals("\033[8;1mfoo\033[0m", $style->apply('foo')); + + $style->setOption('bold'); + $this->assertEquals("\033[8;1mfoo\033[0m", $style->apply('foo')); + + $style->setOptions(array('bold')); + $this->assertEquals("\033[1mfoo\033[0m", $style->apply('foo')); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php new file mode 100644 index 0000000..5f3b809 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -0,0 +1,212 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + + +namespace Symfony\Component\Console\Tests\Formatter; + +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; + +class FormatterStyleTest extends \PHPUnit_Framework_TestCase +{ + public function testEmptyTag() + { + $formatter = new OutputFormatter(true); + $this->assertEquals("foo<>bar", $formatter->format('foo<>bar')); + } + + public function testLGCharEscaping() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals("fooformat('foo\\assertEquals("some info", $formatter->format('\\some info\\')); + $this->assertEquals("\\some info\\", OutputFormatter::escape('some info')); + + $this->assertEquals( + "\033[33mSymfony\\Component\\Console does work very well!\033[0m", + $formatter->format('Symfony\Component\Console does work very well!') + ); + } + + public function testBundledStyles() + { + $formatter = new OutputFormatter(true); + + $this->assertTrue($formatter->hasStyle('error')); + $this->assertTrue($formatter->hasStyle('info')); + $this->assertTrue($formatter->hasStyle('comment')); + $this->assertTrue($formatter->hasStyle('question')); + + $this->assertEquals( + "\033[37;41msome error\033[0m", + $formatter->format('some error') + ); + $this->assertEquals( + "\033[32msome info\033[0m", + $formatter->format('some info') + ); + $this->assertEquals( + "\033[33msome comment\033[0m", + $formatter->format('some comment') + ); + $this->assertEquals( + "\033[30;46msome question\033[0m", + $formatter->format('some question') + ); + } + + public function testNestedStyles() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals( + "\033[37;41msome \033[0m\033[32msome info\033[0m\033[37;41m error\033[0m", + $formatter->format('some some info error') + ); + } + + public function testDeepNestedStyles() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals( + "\033[37;41merror\033[0m\033[32minfo\033[0m\033[33mcomment\033[0m\033[37;41merror\033[0m", + $formatter->format('errorinfocommenterror') + ); + } + + public function testNewStyle() + { + $formatter = new OutputFormatter(true); + + $style = new OutputFormatterStyle('blue', 'white'); + $formatter->setStyle('test', $style); + + $this->assertEquals($style, $formatter->getStyle('test')); + $this->assertNotEquals($style, $formatter->getStyle('info')); + + $this->assertEquals("\033[34;47msome custom msg\033[0m", $formatter->format('some custom msg')); + } + + public function testRedefineStyle() + { + $formatter = new OutputFormatter(true); + + $style = new OutputFormatterStyle('blue', 'white'); + $formatter->setStyle('info', $style); + + $this->assertEquals("\033[34;47msome custom msg\033[0m", $formatter->format('some custom msg')); + } + + public function testInlineStyle() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals("\033[34;41msome text\033[0m", $formatter->format('some text')); + $this->assertEquals("\033[34;41msome text\033[0m", $formatter->format('some text')); + } + + public function testNonStyleTag() + { + $formatter = new OutputFormatter(true); + $this->assertEquals("\033[32msome \033[0m\033[32m styled\033[0m", $formatter->format('some styled')); + } + + public function testNotDecoratedFormatter() + { + $formatter = new OutputFormatter(false); + + $this->assertTrue($formatter->hasStyle('error')); + $this->assertTrue($formatter->hasStyle('info')); + $this->assertTrue($formatter->hasStyle('comment')); + $this->assertTrue($formatter->hasStyle('question')); + + $this->assertEquals( + "some error", $formatter->format('some error') + ); + $this->assertEquals( + "some info", $formatter->format('some info') + ); + $this->assertEquals( + "some comment", $formatter->format('some comment') + ); + $this->assertEquals( + "some question", $formatter->format('some question') + ); + + $formatter->setDecorated(true); + + $this->assertEquals( + "\033[37;41msome error\033[0m", $formatter->format('some error') + ); + $this->assertEquals( + "\033[32msome info\033[0m", $formatter->format('some info') + ); + $this->assertEquals( + "\033[33msome comment\033[0m", $formatter->format('some comment') + ); + $this->assertEquals( + "\033[30;46msome question\033[0m", $formatter->format('some question') + ); + } + + public function testContentWithLineBreaks() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals(<<format(<< +some text +EOF + )); + + $this->assertEquals(<<format(<<some text + +EOF + )); + + $this->assertEquals(<<format(<< +some text + +EOF + )); + + $this->assertEquals(<<format(<< +some text +more text + +EOF + )); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Helper/DialogHelperTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Helper/DialogHelperTest.php new file mode 100644 index 0000000..a486f62 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Helper/DialogHelperTest.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\DialogHelper; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Helper\FormatterHelper; +use Symfony\Component\Console\Output\StreamOutput; + +class DialogHelperTest extends \PHPUnit_Framework_TestCase +{ + public function testAsk() + { + $dialog = new DialogHelper(); + + $dialog->setInputStream($this->getInputStream("\n8AM\n")); + + $this->assertEquals('2PM', $dialog->ask($this->getOutputStream(), 'What time is it?', '2PM')); + $this->assertEquals('8AM', $dialog->ask($output = $this->getOutputStream(), 'What time is it?', '2PM')); + + rewind($output->getStream()); + $this->assertEquals('What time is it?', stream_get_contents($output->getStream())); + } + + public function testAskConfirmation() + { + $dialog = new DialogHelper(); + + $dialog->setInputStream($this->getInputStream("\n\n")); + $this->assertTrue($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?')); + $this->assertFalse($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', false)); + + $dialog->setInputStream($this->getInputStream("y\nyes\n")); + $this->assertTrue($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', false)); + $this->assertTrue($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', false)); + + $dialog->setInputStream($this->getInputStream("n\nno\n")); + $this->assertFalse($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', true)); + $this->assertFalse($dialog->askConfirmation($this->getOutputStream(), 'Do you like French fries?', true)); + } + + public function testAskAndValidate() + { + $dialog = new DialogHelper(); + $helperSet = new HelperSet(array(new FormatterHelper())); + $dialog->setHelperSet($helperSet); + + $question ='What color was the white horse of Henry IV?'; + $error = 'This is not a color!'; + $validator = function ($color) use ($error) { + if (!in_array($color, array('white', 'black'))) { + throw new \InvalidArgumentException($error); + } + + return $color; + }; + + $dialog->setInputStream($this->getInputStream("\nblack\n")); + $this->assertEquals('white', $dialog->askAndValidate($this->getOutputStream(), $question, $validator, 2, 'white')); + $this->assertEquals('black', $dialog->askAndValidate($this->getOutputStream(), $question, $validator, 2, 'white')); + + $dialog->setInputStream($this->getInputStream("green\nyellow\norange\n")); + try { + $this->assertEquals('white', $dialog->askAndValidate($this->getOutputStream(), $question, $validator, 2, 'white')); + $this->fail(); + } catch (\InvalidArgumentException $e) { + $this->assertEquals($error, $e->getMessage()); + } + } + + protected function getInputStream($input) + { + $stream = fopen('php://memory', 'r+', false); + fputs($stream, $input); + rewind($stream); + + return $stream; + } + + protected function getOutputStream() + { + return new StreamOutput(fopen('php://memory', 'r+', false)); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Helper/FormatterHelperTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Helper/FormatterHelperTest.php new file mode 100644 index 0000000..5ab62a3 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Helper/FormatterHelperTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\FormatterHelper; + +class FormatterHelperTest extends \PHPUnit_Framework_TestCase +{ + public function testFormatSection() + { + $formatter = new FormatterHelper(); + + $this->assertEquals( + '[cli] Some text to display', + $formatter->formatSection('cli', 'Some text to display'), + '::formatSection() formats a message in a section' + ); + } + + public function testFormatBlock() + { + $formatter = new FormatterHelper(); + + $this->assertEquals( + ' Some text to display ', + $formatter->formatBlock('Some text to display', 'error'), + '::formatBlock() formats a message in a block' + ); + + $this->assertEquals( + ' Some text to display ' . "\n" . + ' foo bar ', + $formatter->formatBlock(array('Some text to display', 'foo bar'), 'error'), + '::formatBlock() formats a message in a block' + ); + + $this->assertEquals( + ' ' . "\n" . + ' Some text to display ' . "\n" . + ' ', + $formatter->formatBlock('Some text to display', 'error', true), + '::formatBlock() formats a message in a block' + ); + } + + public function testFormatBlockWithDiacriticLetters() + { + if (!extension_loaded('mbstring')) { + $this->markTestSkipped('This test requires mbstring to work.'); + } + + $formatter = new FormatterHelper(); + + $this->assertEquals( + ' ' . "\n" . + ' Du texte à afficher ' . "\n" . + ' ', + $formatter->formatBlock('Du texte à afficher', 'error', true), + '::formatBlock() formats a message in a block' + ); + } + + public function testFormatBlockLGEscaping() + { + $formatter = new FormatterHelper(); + + $this->assertEquals( + ' ' . "\n" . + ' \some info\ ' . "\n" . + ' ', + $formatter->formatBlock('some info', 'error', true), + '::formatBlock() escapes \'<\' chars' + ); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/ArgvInputTest.php new file mode 100644 index 0000000..cf63177 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/ArgvInputTest.php @@ -0,0 +1,217 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + +class ArgvInputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $_SERVER['argv'] = array('cli.php', 'foo'); + $input = new ArgvInput(); + $r = new \ReflectionObject($input); + $p = $r->getProperty('tokens'); + $p->setAccessible(true); + + $this->assertEquals(array('foo'), $p->getValue($input), '__construct() automatically get its input from the argv server variable'); + } + + public function testParser() + { + $input = new ArgvInput(array('cli.php', 'foo')); + $input->bind(new InputDefinition(array(new InputArgument('name')))); + $this->assertEquals(array('name' => 'foo'), $input->getArguments(), '->parse() parses required arguments'); + + $input->bind(new InputDefinition(array(new InputArgument('name')))); + $this->assertEquals(array('name' => 'foo'), $input->getArguments(), '->parse() is stateless'); + + $input = new ArgvInput(array('cli.php', '--foo')); + $input->bind(new InputDefinition(array(new InputOption('foo')))); + $this->assertEquals(array('foo' => true), $input->getOptions(), '->parse() parses long options without a value'); + + $input = new ArgvInput(array('cli.php', '--foo=bar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)))); + $this->assertEquals(array('foo' => 'bar'), $input->getOptions(), '->parse() parses long options with a required value (with a = separator)'); + + $input = new ArgvInput(array('cli.php', '--foo', 'bar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)))); + $this->assertEquals(array('foo' => 'bar'), $input->getOptions(), '->parse() parses long options with a required value (with a space separator)'); + + try { + $input = new ArgvInput(array('cli.php', '--foo')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)))); + $this->fail('->parse() throws a \RuntimeException if no value is passed to an option when it is required'); + } catch (\Exception $e) { + $this->assertInstanceOf('\RuntimeException', $e, '->parse() throws a \RuntimeException if no value is passed to an option when it is required'); + $this->assertEquals('The "--foo" option requires a value.', $e->getMessage(), '->parse() throws a \RuntimeException if no value is passed to an option when it is required'); + } + + $input = new ArgvInput(array('cli.php', '-f')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f')))); + $this->assertEquals(array('foo' => true), $input->getOptions(), '->parse() parses short options without a value'); + + $input = new ArgvInput(array('cli.php', '-fbar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)))); + $this->assertEquals(array('foo' => 'bar'), $input->getOptions(), '->parse() parses short options with a required value (with no separator)'); + + $input = new ArgvInput(array('cli.php', '-f', 'bar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)))); + $this->assertEquals(array('foo' => 'bar'), $input->getOptions(), '->parse() parses short options with a required value (with a space separator)'); + + $input = new ArgvInput(array('cli.php', '-f', '-b', 'foo')); + $input->bind(new InputDefinition(array(new InputArgument('name'), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputOption('bar', 'b')))); + $this->assertEquals(array('foo' => null, 'bar' => true), $input->getOptions(), '->parse() parses short options with an optional value which is not present'); + + try { + $input = new ArgvInput(array('cli.php', '-f')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)))); + $this->fail('->parse() throws a \RuntimeException if no value is passed to an option when it is required'); + } catch (\Exception $e) { + $this->assertInstanceOf('\RuntimeException', $e, '->parse() throws a \RuntimeException if no value is passed to an option when it is required'); + $this->assertEquals('The "--foo" option requires a value.', $e->getMessage(), '->parse() throws a \RuntimeException if no value is passed to an option when it is required'); + } + + try { + $input = new ArgvInput(array('cli.php', '-ffoo')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_NONE)))); + $this->fail('->parse() throws a \RuntimeException if a value is passed to an option which does not take one'); + } catch (\Exception $e) { + $this->assertInstanceOf('\RuntimeException', $e, '->parse() throws a \RuntimeException if a value is passed to an option which does not take one'); + $this->assertEquals('The "-o" option does not exist.', $e->getMessage(), '->parse() throws a \RuntimeException if a value is passed to an option which does not take one'); + } + + try { + $input = new ArgvInput(array('cli.php', 'foo', 'bar')); + $input->bind(new InputDefinition()); + $this->fail('->parse() throws a \RuntimeException if too many arguments are passed'); + } catch (\Exception $e) { + $this->assertInstanceOf('\RuntimeException', $e, '->parse() throws a \RuntimeException if too many arguments are passed'); + $this->assertEquals('Too many arguments.', $e->getMessage(), '->parse() throws a \RuntimeException if too many arguments are passed'); + } + + try { + $input = new ArgvInput(array('cli.php', '--foo')); + $input->bind(new InputDefinition()); + $this->fail('->parse() throws a \RuntimeException if an unknown long option is passed'); + } catch (\Exception $e) { + $this->assertInstanceOf('\RuntimeException', $e, '->parse() throws a \RuntimeException if an unknown long option is passed'); + $this->assertEquals('The "--foo" option does not exist.', $e->getMessage(), '->parse() throws a \RuntimeException if an unknown long option is passed'); + } + + try { + $input = new ArgvInput(array('cli.php', '-f')); + $input->bind(new InputDefinition()); + $this->fail('->parse() throws a \RuntimeException if an unknown short option is passed'); + } catch (\Exception $e) { + $this->assertInstanceOf('\RuntimeException', $e, '->parse() throws a \RuntimeException if an unknown short option is passed'); + $this->assertEquals('The "-f" option does not exist.', $e->getMessage(), '->parse() throws a \RuntimeException if an unknown short option is passed'); + } + + $input = new ArgvInput(array('cli.php', '-fb')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f'), new InputOption('bar', 'b')))); + $this->assertEquals(array('foo' => true, 'bar' => true), $input->getOptions(), '->parse() parses short options when they are aggregated as a single one'); + + $input = new ArgvInput(array('cli.php', '-fb', 'bar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f'), new InputOption('bar', 'b', InputOption::VALUE_REQUIRED)))); + $this->assertEquals(array('foo' => true, 'bar' => 'bar'), $input->getOptions(), '->parse() parses short options when they are aggregated as a single one and the last one has a required value'); + + $input = new ArgvInput(array('cli.php', '-fb', 'bar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f'), new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL)))); + $this->assertEquals(array('foo' => true, 'bar' => 'bar'), $input->getOptions(), '->parse() parses short options when they are aggregated as a single one and the last one has an optional value'); + + $input = new ArgvInput(array('cli.php', '-fbbar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f'), new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL)))); + $this->assertEquals(array('foo' => true, 'bar' => 'bar'), $input->getOptions(), '->parse() parses short options when they are aggregated as a single one and the last one has an optional value with no separator'); + + $input = new ArgvInput(array('cli.php', '-fbbar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL)))); + $this->assertEquals(array('foo' => 'bbar', 'bar' => null), $input->getOptions(), '->parse() parses short options when they are aggregated as a single one and one of them takes a value'); + + try { + $input = new ArgvInput(array('cli.php', 'foo', 'bar', 'baz', 'bat')); + $input->bind(new InputDefinition(array(new InputArgument('name', InputArgument::IS_ARRAY)))); + $this->assertEquals(array('name' => array('foo', 'bar', 'baz', 'bat')), $input->getArguments(), '->parse() parses array arguments'); + } catch (\RuntimeException $e) { + $this->assertNotEquals('Too many arguments.', $e->getMessage(), '->parse() parses array arguments'); + } + + $input = new ArgvInput(array('cli.php', '--name=foo', '--name=bar', '--name=baz')); + $input->bind(new InputDefinition(array(new InputOption('name', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY)))); + $this->assertEquals(array('name' => array('foo', 'bar', 'baz')), $input->getOptions()); + + try { + $input = new ArgvInput(array('cli.php', '-1')); + $input->bind(new InputDefinition(array(new InputArgument('number')))); + $this->fail('->parse() throws a \RuntimeException if an unknown option is passed'); + } catch (\Exception $e) { + $this->assertInstanceOf('\RuntimeException', $e, '->parse() parses arguments with leading dashes as options without having encountered a double-dash sequence'); + $this->assertEquals('The "-1" option does not exist.', $e->getMessage(), '->parse() parses arguments with leading dashes as options without having encountered a double-dash sequence'); + } + + $input = new ArgvInput(array('cli.php', '--', '-1')); + $input->bind(new InputDefinition(array(new InputArgument('number')))); + $this->assertEquals(array('number' => '-1'), $input->getArguments(), '->parse() parses arguments with leading dashes as arguments after having encountered a double-dash sequence'); + + $input = new ArgvInput(array('cli.php', '-f', 'bar', '--', '-1')); + $input->bind(new InputDefinition(array(new InputArgument('number'), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)))); + $this->assertEquals(array('foo' => 'bar'), $input->getOptions(), '->parse() parses arguments with leading dashes as options before having encountered a double-dash sequence'); + $this->assertEquals(array('number' => '-1'), $input->getArguments(), '->parse() parses arguments with leading dashes as arguments after having encountered a double-dash sequence'); + + $input = new ArgvInput(array('cli.php', '-f', 'bar', '')); + $input->bind(new InputDefinition(array(new InputArgument('empty'), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)))); + $this->assertEquals(array('empty' => ''), $input->getArguments(), '->parse() parses empty string arguments'); + } + + public function testGetFirstArgument() + { + $input = new ArgvInput(array('cli.php', '-fbbar')); + $this->assertEquals('', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input'); + + $input = new ArgvInput(array('cli.php', '-fbbar', 'foo')); + $this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input'); + } + + public function testHasParameterOption() + { + $input = new ArgvInput(array('cli.php', '-f', 'foo')); + $this->assertTrue($input->hasParameterOption('-f'), '->hasParameterOption() returns true if the given short option is in the raw input'); + + $input = new ArgvInput(array('cli.php', '--foo', 'foo')); + $this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if the given short option is in the raw input'); + + $input = new ArgvInput(array('cli.php', 'foo')); + $this->assertFalse($input->hasParameterOption('--foo'), '->hasParameterOption() returns false if the given short option is not in the raw input'); + } + + /** + * @dataProvider provideGetParameterOptionValues + */ + public function testGetParameterOptionEqualSign($argv, $key, $expected) + { + $input = new ArgvInput($argv); + $this->assertEquals($expected, $input->getParameterOption($key), '->getParameterOption() returns the expected value'); + } + + public function provideGetParameterOptionValues() + { + return array( + array(array('app/console', 'foo:bar', '-e', 'dev'), '-e', 'dev'), + array(array('app/console', 'foo:bar', '--env=dev'), '--env', 'dev'), + array(array('app/console', 'foo:bar', '-e', 'dev'), array('-e', '--env'), 'dev'), + array(array('app/console', 'foo:bar', '--env=dev'), array('-e', '--env'), 'dev'), + ); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Input/ArrayInputTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/ArrayInputTest.php new file mode 100644 index 0000000..82f477e --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/ArrayInputTest.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + +class ArrayInputTest extends \PHPUnit_Framework_TestCase +{ + public function testGetFirstArgument() + { + $input = new ArrayInput(array()); + $this->assertNull($input->getFirstArgument(), '->getFirstArgument() returns null if no argument were passed'); + $input = new ArrayInput(array('name' => 'Fabien')); + $this->assertEquals('Fabien', $input->getFirstArgument(), '->getFirstArgument() returns the first passed argument'); + $input = new ArrayInput(array('--foo' => 'bar', 'name' => 'Fabien')); + $this->assertEquals('Fabien', $input->getFirstArgument(), '->getFirstArgument() returns the first passed argument'); + } + + public function testHasParameterOption() + { + $input = new ArrayInput(array('name' => 'Fabien', '--foo' => 'bar')); + $this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if an option is present in the passed parameters'); + $this->assertFalse($input->hasParameterOption('--bar'), '->hasParameterOption() returns false if an option is not present in the passed parameters'); + + $input = new ArrayInput(array('--foo')); + $this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if an option is present in the passed parameters'); + } + + public function testParse() + { + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name')))); + $this->assertEquals(array('name' => 'foo'), $input->getArguments(), '->parse() parses required arguments'); + + try { + $input = new ArrayInput(array('foo' => 'foo'), new InputDefinition(array(new InputArgument('name')))); + $this->fail('->parse() throws an \InvalidArgumentException exception if an invalid argument is passed'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws an \InvalidArgumentException exception if an invalid argument is passed'); + $this->assertEquals('The "foo" argument does not exist.', $e->getMessage(), '->parse() throws an \InvalidArgumentException exception if an invalid argument is passed'); + } + + $input = new ArrayInput(array('--foo' => 'bar'), new InputDefinition(array(new InputOption('foo')))); + $this->assertEquals(array('foo' => 'bar'), $input->getOptions(), '->parse() parses long options'); + + $input = new ArrayInput(array('--foo' => 'bar'), new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, '', 'default')))); + $this->assertEquals(array('foo' => 'bar'), $input->getOptions(), '->parse() parses long options with a default value'); + + $input = new ArrayInput(array('--foo' => null), new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, '', 'default')))); + $this->assertEquals(array('foo' => 'default'), $input->getOptions(), '->parse() parses long options with a default value'); + + try { + $input = new ArrayInput(array('--foo' => null), new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED)))); + $this->fail('->parse() throws an \InvalidArgumentException exception if a required option is passed without a value'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws an \InvalidArgumentException exception if a required option is passed without a value'); + $this->assertEquals('The "--foo" option requires a value.', $e->getMessage(), '->parse() throws an \InvalidArgumentException exception if a required option is passed without a value'); + } + + try { + $input = new ArrayInput(array('--foo' => 'foo'), new InputDefinition()); + $this->fail('->parse() throws an \InvalidArgumentException exception if an invalid option is passed'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws an \InvalidArgumentException exception if an invalid option is passed'); + $this->assertEquals('The "--foo" option does not exist.', $e->getMessage(), '->parse() throws an \InvalidArgumentException exception if an invalid option is passed'); + } + + $input = new ArrayInput(array('-f' => 'bar'), new InputDefinition(array(new InputOption('foo', 'f')))); + $this->assertEquals(array('foo' => 'bar'), $input->getOptions(), '->parse() parses short options'); + + try { + $input = new ArrayInput(array('-o' => 'foo'), new InputDefinition()); + $this->fail('->parse() throws an \InvalidArgumentException exception if an invalid option is passed'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws an \InvalidArgumentException exception if an invalid option is passed'); + $this->assertEquals('The "-o" option does not exist.', $e->getMessage(), '->parse() throws an \InvalidArgumentException exception if an invalid option is passed'); + } + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputArgumentTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputArgumentTest.php new file mode 100644 index 0000000..1b680a9 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputArgumentTest.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\InputArgument; + +class InputArgumentTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $argument = new InputArgument('foo'); + $this->assertEquals('foo', $argument->getName(), '__construct() takes a name as its first argument'); + + // mode argument + $argument = new InputArgument('foo'); + $this->assertFalse($argument->isRequired(), '__construct() gives a "InputArgument::OPTIONAL" mode by default'); + + $argument = new InputArgument('foo', null); + $this->assertFalse($argument->isRequired(), '__construct() can take "InputArgument::OPTIONAL" as its mode'); + + $argument = new InputArgument('foo', InputArgument::OPTIONAL); + $this->assertFalse($argument->isRequired(), '__construct() can take "InputArgument::OPTIONAL" as its mode'); + + $argument = new InputArgument('foo', InputArgument::REQUIRED); + $this->assertTrue($argument->isRequired(), '__construct() can take "InputArgument::REQUIRED" as its mode'); + + try { + $argument = new InputArgument('foo', 'ANOTHER_ONE'); + $this->fail('__construct() throws an Exception if the mode is not valid'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '__construct() throws an Exception if the mode is not valid'); + $this->assertEquals('Argument mode "ANOTHER_ONE" is not valid.', $e->getMessage()); + } + try { + $argument = new InputArgument('foo', -1); + $this->fail('__construct() throws an Exception if the mode is not valid'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '__construct() throws an Exception if the mode is not valid'); + $this->assertEquals('Argument mode "-1" is not valid.', $e->getMessage()); + } + } + + public function testIsArray() + { + $argument = new InputArgument('foo', InputArgument::IS_ARRAY); + $this->assertTrue($argument->isArray(), '->isArray() returns true if the argument can be an array'); + $argument = new InputArgument('foo', InputArgument::OPTIONAL | InputArgument::IS_ARRAY); + $this->assertTrue($argument->isArray(), '->isArray() returns true if the argument can be an array'); + $argument = new InputArgument('foo', InputArgument::OPTIONAL); + $this->assertFalse($argument->isArray(), '->isArray() returns false if the argument can not be an array'); + } + + public function testGetDescription() + { + $argument = new InputArgument('foo', null, 'Some description'); + $this->assertEquals('Some description', $argument->getDescription(), '->getDescription() return the message description'); + } + + public function testGetDefault() + { + $argument = new InputArgument('foo', InputArgument::OPTIONAL, '', 'default'); + $this->assertEquals('default', $argument->getDefault(), '->getDefault() return the default value'); + } + + public function testSetDefault() + { + $argument = new InputArgument('foo', InputArgument::OPTIONAL, '', 'default'); + $argument->setDefault(null); + $this->assertNull($argument->getDefault(), '->setDefault() can reset the default value by passing null'); + $argument->setDefault('another'); + $this->assertEquals('another', $argument->getDefault(), '->setDefault() changes the default value'); + + $argument = new InputArgument('foo', InputArgument::OPTIONAL | InputArgument::IS_ARRAY); + $argument->setDefault(array(1, 2)); + $this->assertEquals(array(1, 2), $argument->getDefault(), '->setDefault() changes the default value'); + + try { + $argument = new InputArgument('foo', InputArgument::REQUIRED); + $argument->setDefault('default'); + $this->fail('->setDefault() throws an Exception if you give a default value for a required argument'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->parse() throws an \InvalidArgumentException exception if an invalid option is passed'); + $this->assertEquals('Cannot set a default value except for Parameter::OPTIONAL mode.', $e->getMessage()); + } + + try { + $argument = new InputArgument('foo', InputArgument::IS_ARRAY); + $argument->setDefault('default'); + $this->fail('->setDefault() throws an Exception if you give a default value which is not an array for a IS_ARRAY option'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->setDefault() throws an Exception if you give a default value which is not an array for a IS_ARRAY option'); + $this->assertEquals('A default value for an array argument must be an array.', $e->getMessage()); + } + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputDefinitionTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputDefinitionTest.php new file mode 100644 index 0000000..20554ec --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputDefinitionTest.php @@ -0,0 +1,363 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + +class InputDefinitionTest extends \PHPUnit_Framework_TestCase +{ + protected static $fixtures; + + protected $foo, $bar, $foo1, $foo2; + + public static function setUpBeforeClass() + { + self::$fixtures = __DIR__.'/../Fixtures/'; + } + + public function testConstructor() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $this->assertEquals(array(), $definition->getArguments(), '__construct() creates a new InputDefinition object'); + + $definition = new InputDefinition(array($this->foo, $this->bar)); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getArguments(), '__construct() takes an array of InputArgument objects as its first argument'); + + $this->initializeOptions(); + + $definition = new InputDefinition(); + $this->assertEquals(array(), $definition->getOptions(), '__construct() creates a new InputDefinition object'); + + $definition = new InputDefinition(array($this->foo, $this->bar)); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getOptions(), '__construct() takes an array of InputOption objects as its first argument'); + } + + public function testSetArguments() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->setArguments(array($this->foo)); + $this->assertEquals(array('foo' => $this->foo), $definition->getArguments(), '->setArguments() sets the array of InputArgument objects'); + $definition->setArguments(array($this->bar)); + + $this->assertEquals(array('bar' => $this->bar), $definition->getArguments(), '->setArguments() clears all InputArgument objects'); + } + + public function testAddArguments() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArguments(array($this->foo)); + $this->assertEquals(array('foo' => $this->foo), $definition->getArguments(), '->addArguments() adds an array of InputArgument objects'); + $definition->addArguments(array($this->bar)); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getArguments(), '->addArguments() does not clear existing InputArgument objects'); + } + + public function testAddArgument() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArgument($this->foo); + $this->assertEquals(array('foo' => $this->foo), $definition->getArguments(), '->addArgument() adds a InputArgument object'); + $definition->addArgument($this->bar); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getArguments(), '->addArgument() adds a InputArgument object'); + + // arguments must have different names + try { + $definition->addArgument($this->foo1); + $this->fail('->addArgument() throws a Exception if another argument is already registered with the same name'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->addArgument() throws a Exception if another argument is already registered with the same name'); + $this->assertEquals('An argument with name "foo" already exists.', $e->getMessage()); + } + + // cannot add a parameter after an array parameter + $definition->addArgument(new InputArgument('fooarray', InputArgument::IS_ARRAY)); + try { + $definition->addArgument(new InputArgument('anotherbar')); + $this->fail('->addArgument() throws a Exception if there is an array parameter already registered'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->addArgument() throws a Exception if there is an array parameter already registered'); + $this->assertEquals('Cannot add an argument after an array argument.', $e->getMessage()); + } + + // cannot add a required argument after an optional one + $definition = new InputDefinition(); + $definition->addArgument($this->foo); + try { + $definition->addArgument($this->foo2); + $this->fail('->addArgument() throws an exception if you try to add a required argument after an optional one'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->addArgument() throws an exception if you try to add a required argument after an optional one'); + $this->assertEquals('Cannot add a required argument after an optional one.', $e->getMessage()); + } + } + + public function testGetArgument() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArguments(array($this->foo)); + $this->assertEquals($this->foo, $definition->getArgument('foo'), '->getArgument() returns a InputArgument by its name'); + try { + $definition->getArgument('bar'); + $this->fail('->getArgument() throws an exception if the InputArgument name does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->getArgument() throws an exception if the InputArgument name does not exist'); + $this->assertEquals('The "bar" argument does not exist.', $e->getMessage()); + } + } + + public function testHasArgument() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArguments(array($this->foo)); + $this->assertTrue($definition->hasArgument('foo'), '->hasArgument() returns true if a InputArgument exists for the given name'); + $this->assertFalse($definition->hasArgument('bar'), '->hasArgument() returns false if a InputArgument exists for the given name'); + } + + public function testGetArgumentRequiredCount() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArgument($this->foo2); + $this->assertEquals(1, $definition->getArgumentRequiredCount(), '->getArgumentRequiredCount() returns the number of required arguments'); + $definition->addArgument($this->foo); + $this->assertEquals(1, $definition->getArgumentRequiredCount(), '->getArgumentRequiredCount() returns the number of required arguments'); + } + + public function testGetArgumentCount() + { + $this->initializeArguments(); + + $definition = new InputDefinition(); + $definition->addArgument($this->foo2); + $this->assertEquals(1, $definition->getArgumentCount(), '->getArgumentCount() returns the number of arguments'); + $definition->addArgument($this->foo); + $this->assertEquals(2, $definition->getArgumentCount(), '->getArgumentCount() returns the number of arguments'); + } + + public function testGetArgumentDefaults() + { + $definition = new InputDefinition(array( + new InputArgument('foo1', InputArgument::OPTIONAL), + new InputArgument('foo2', InputArgument::OPTIONAL, '', 'default'), + new InputArgument('foo3', InputArgument::OPTIONAL | InputArgument::IS_ARRAY), + // new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', array(1, 2)), + )); + $this->assertEquals(array('foo1' => null, 'foo2' => 'default', 'foo3' => array()), $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); + + $definition = new InputDefinition(array( + new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', array(1, 2)), + )); + $this->assertEquals(array('foo4' => array(1, 2)), $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); + } + + public function testSetOptions() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertEquals(array('foo' => $this->foo), $definition->getOptions(), '->setOptions() sets the array of InputOption objects'); + $definition->setOptions(array($this->bar)); + $this->assertEquals(array('bar' => $this->bar), $definition->getOptions(), '->setOptions() clears all InputOption objects'); + try { + $definition->getOptionForShortcut('f'); + $this->fail('->setOptions() clears all InputOption objects'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->setOptions() clears all InputOption objects'); + $this->assertEquals('The "-f" option does not exist.', $e->getMessage()); + } + } + + public function testAddOptions() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertEquals(array('foo' => $this->foo), $definition->getOptions(), '->addOptions() adds an array of InputOption objects'); + $definition->addOptions(array($this->bar)); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getOptions(), '->addOptions() does not clear existing InputOption objects'); + } + + public function testAddOption() + { + $this->initializeOptions(); + + $definition = new InputDefinition(); + $definition->addOption($this->foo); + $this->assertEquals(array('foo' => $this->foo), $definition->getOptions(), '->addOption() adds a InputOption object'); + $definition->addOption($this->bar); + $this->assertEquals(array('foo' => $this->foo, 'bar' => $this->bar), $definition->getOptions(), '->addOption() adds a InputOption object'); + try { + $definition->addOption($this->foo2); + $this->fail('->addOption() throws a Exception if the another option is already registered with the same name'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->addOption() throws a Exception if the another option is already registered with the same name'); + $this->assertEquals('An option named "foo" already exists.', $e->getMessage()); + } + try { + $definition->addOption($this->foo1); + $this->fail('->addOption() throws a Exception if the another option is already registered with the same shortcut'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->addOption() throws a Exception if the another option is already registered with the same shortcut'); + $this->assertEquals('An option with shortcut "f" already exists.', $e->getMessage()); + } + } + + public function testGetOption() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertEquals($this->foo, $definition->getOption('foo'), '->getOption() returns a InputOption by its name'); + try { + $definition->getOption('bar'); + $this->fail('->getOption() throws an exception if the option name does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->getOption() throws an exception if the option name does not exist'); + $this->assertEquals('The "--bar" option does not exist.', $e->getMessage()); + } + } + + public function testHasOption() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertTrue($definition->hasOption('foo'), '->hasOption() returns true if a InputOption exists for the given name'); + $this->assertFalse($definition->hasOption('bar'), '->hasOption() returns false if a InputOption exists for the given name'); + } + + public function testHasShortcut() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertTrue($definition->hasShortcut('f'), '->hasShortcut() returns true if a InputOption exists for the given shortcut'); + $this->assertFalse($definition->hasShortcut('b'), '->hasShortcut() returns false if a InputOption exists for the given shortcut'); + } + + public function testGetOptionForShortcut() + { + $this->initializeOptions(); + + $definition = new InputDefinition(array($this->foo)); + $this->assertEquals($this->foo, $definition->getOptionForShortcut('f'), '->getOptionForShortcut() returns a InputOption by its shortcut'); + try { + $definition->getOptionForShortcut('l'); + $this->fail('->getOption() throws an exception if the shortcut does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->getOption() throws an exception if the shortcut does not exist'); + $this->assertEquals('The "-l" option does not exist.', $e->getMessage()); + } + } + + public function testGetOptionDefaults() + { + $definition = new InputDefinition(array( + new InputOption('foo1', null, InputOption::VALUE_NONE), + new InputOption('foo2', null, InputOption::VALUE_REQUIRED), + new InputOption('foo3', null, InputOption::VALUE_REQUIRED, '', 'default'), + new InputOption('foo4', null, InputOption::VALUE_OPTIONAL), + new InputOption('foo5', null, InputOption::VALUE_OPTIONAL, '', 'default'), + new InputOption('foo6', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY), + new InputOption('foo7', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, '', array(1, 2)), + )); + $defaults = array( + 'foo1' => null, + 'foo2' => null, + 'foo3' => 'default', + 'foo4' => null, + 'foo5' => 'default', + 'foo6' => array(), + 'foo7' => array(1, 2), + ); + $this->assertEquals($defaults, $definition->getOptionDefaults(), '->getOptionDefaults() returns the default values for all options'); + } + + public function testGetSynopsis() + { + $definition = new InputDefinition(array(new InputOption('foo'))); + $this->assertEquals('[--foo]', $definition->getSynopsis(), '->getSynopsis() returns a synopsis of arguments and options'); + $definition = new InputDefinition(array(new InputOption('foo', 'f'))); + $this->assertEquals('[-f|--foo]', $definition->getSynopsis(), '->getSynopsis() returns a synopsis of arguments and options'); + $definition = new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_REQUIRED))); + $this->assertEquals('[-f|--foo="..."]', $definition->getSynopsis(), '->getSynopsis() returns a synopsis of arguments and options'); + $definition = new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL))); + $this->assertEquals('[-f|--foo[="..."]]', $definition->getSynopsis(), '->getSynopsis() returns a synopsis of arguments and options'); + + $definition = new InputDefinition(array(new InputArgument('foo'))); + $this->assertEquals('[foo]', $definition->getSynopsis(), '->getSynopsis() returns a synopsis of arguments and options'); + $definition = new InputDefinition(array(new InputArgument('foo', InputArgument::REQUIRED))); + $this->assertEquals('foo', $definition->getSynopsis(), '->getSynopsis() returns a synopsis of arguments and options'); + $definition = new InputDefinition(array(new InputArgument('foo', InputArgument::IS_ARRAY))); + $this->assertEquals('[foo1] ... [fooN]', $definition->getSynopsis(), '->getSynopsis() returns a synopsis of arguments and options'); + $definition = new InputDefinition(array(new InputArgument('foo', InputArgument::REQUIRED | InputArgument::IS_ARRAY))); + $this->assertEquals('foo1 ... [fooN]', $definition->getSynopsis(), '->getSynopsis() returns a synopsis of arguments and options'); + } + + public function testAsText() + { + $definition = new InputDefinition(array( + new InputArgument('foo', InputArgument::OPTIONAL, 'The foo argument'), + new InputArgument('baz', InputArgument::OPTIONAL, 'The baz argument', true), + new InputArgument('bar', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'The bar argument', array('bar')), + new InputOption('foo', 'f', InputOption::VALUE_REQUIRED, 'The foo option'), + new InputOption('baz', null, InputOption::VALUE_OPTIONAL, 'The baz option', false), + new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL, 'The bar option', 'bar'), + new InputOption('qux', '', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The qux option', array('foo', 'bar')), + new InputOption('qux2', '', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The qux2 option', array('foo' => 'bar')), + )); + $this->assertStringEqualsFile(self::$fixtures.'/definition_astext.txt', $definition->asText(), '->asText() returns a textual representation of the InputDefinition'); + } + + public function testAsXml() + { + $definition = new InputDefinition(array( + new InputArgument('foo', InputArgument::OPTIONAL, 'The foo argument'), + new InputArgument('baz', InputArgument::OPTIONAL, 'The baz argument', true), + new InputArgument('bar', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'The bar argument', array('bar')), + new InputOption('foo', 'f', InputOption::VALUE_REQUIRED, 'The foo option'), + new InputOption('baz', null, InputOption::VALUE_OPTIONAL, 'The baz option', false), + new InputOption('bar', 'b', InputOption::VALUE_OPTIONAL, 'The bar option', 'bar'), + )); + $this->assertXmlStringEqualsXmlFile(self::$fixtures.'/definition_asxml.txt', $definition->asXml(), '->asText() returns a textual representation of the InputDefinition'); + } + + protected function initializeArguments() + { + $this->foo = new InputArgument('foo'); + $this->bar = new InputArgument('bar'); + $this->foo1 = new InputArgument('foo'); + $this->foo2 = new InputArgument('foo2', InputArgument::REQUIRED); + } + + protected function initializeOptions() + { + $this->foo = new InputOption('foo', 'f'); + $this->bar = new InputOption('bar', 'b'); + $this->foo1 = new InputOption('fooBis', 'f'); + $this->foo2 = new InputOption('foo', 'p'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputOptionTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputOptionTest.php new file mode 100644 index 0000000..b5d8b43 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputOptionTest.php @@ -0,0 +1,192 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\InputOption; + +class InputOptionTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $option = new InputOption('foo'); + $this->assertEquals('foo', $option->getName(), '__construct() takes a name as its first argument'); + $option = new InputOption('--foo'); + $this->assertEquals('foo', $option->getName(), '__construct() removes the leading -- of the option name'); + + try { + $option = new InputOption('foo', 'f', InputOption::VALUE_IS_ARRAY); + $this->fail('->setDefault() throws an Exception if VALUE_IS_ARRAY option is used when an option does not accept a value'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->setDefault() throws an Exception if VALUE_IS_ARRAY option is used when an option does not accept a value'); + $this->assertEquals('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.', $e->getMessage()); + } + + // shortcut argument + $option = new InputOption('foo', 'f'); + $this->assertEquals('f', $option->getShortcut(), '__construct() can take a shortcut as its second argument'); + $option = new InputOption('foo', '-f'); + $this->assertEquals('f', $option->getShortcut(), '__construct() removes the leading - of the shortcut'); + $option = new InputOption('foo'); + $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null by default'); + + // mode argument + $option = new InputOption('foo', 'f'); + $this->assertFalse($option->acceptValue(), '__construct() gives a "InputOption::VALUE_NONE" mode by default'); + $this->assertFalse($option->isValueRequired(), '__construct() gives a "InputOption::VALUE_NONE" mode by default'); + $this->assertFalse($option->isValueOptional(), '__construct() gives a "InputOption::VALUE_NONE" mode by default'); + + $option = new InputOption('foo', 'f', null); + $this->assertFalse($option->acceptValue(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isValueOptional(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + + $option = new InputOption('foo', 'f', InputOption::VALUE_NONE); + $this->assertFalse($option->acceptValue(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isValueOptional(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + + $option = new InputOption('foo', 'f', InputOption::VALUE_REQUIRED); + $this->assertTrue($option->acceptValue(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); + $this->assertTrue($option->isValueRequired(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); + $this->assertFalse($option->isValueOptional(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); + + $option = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL); + $this->assertTrue($option->acceptValue(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); + $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); + $this->assertTrue($option->isValueOptional(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); + + try { + $option = new InputOption('foo', 'f', 'ANOTHER_ONE'); + $this->fail('__construct() throws an Exception if the mode is not valid'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '__construct() throws an Exception if the mode is not valid'); + $this->assertEquals('Option mode "ANOTHER_ONE" is not valid.', $e->getMessage()); + } + try { + $option = new InputOption('foo', 'f', -1); + $this->fail('__construct() throws an Exception if the mode is not valid'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '__construct() throws an Exception if the mode is not valid'); + $this->assertEquals('Option mode "-1" is not valid.', $e->getMessage()); + } + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testEmptyNameIsInvalid() + { + new InputOption(''); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testDoubleDashNameIsInvalid() + { + new InputOption('--'); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testSingleDashOptionIsInvalid() + { + new InputOption('foo', '-'); + } + + public function testIsArray() + { + $option = new InputOption('foo', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY); + $this->assertTrue($option->isArray(), '->isArray() returns true if the option can be an array'); + $option = new InputOption('foo', null, InputOption::VALUE_NONE); + $this->assertFalse($option->isArray(), '->isArray() returns false if the option can not be an array'); + } + + public function testGetDescription() + { + $option = new InputOption('foo', 'f', null, 'Some description'); + $this->assertEquals('Some description', $option->getDescription(), '->getDescription() returns the description message'); + } + + public function testGetDefault() + { + $option = new InputOption('foo', null, InputOption::VALUE_OPTIONAL, '', 'default'); + $this->assertEquals('default', $option->getDefault(), '->getDefault() returns the default value'); + + $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED, '', 'default'); + $this->assertEquals('default', $option->getDefault(), '->getDefault() returns the default value'); + + $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED); + $this->assertNull($option->getDefault(), '->getDefault() returns null if no default value is configured'); + + $option = new InputOption('foo', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY); + $this->assertEquals(array(), $option->getDefault(), '->getDefault() returns an empty array if option is an array'); + + $option = new InputOption('foo', null, InputOption::VALUE_NONE); + $this->assertFalse($option->getDefault(), '->getDefault() returns false if the option does not take a value'); + } + + public function testSetDefault() + { + $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED, '', 'default'); + $option->setDefault(null); + $this->assertNull($option->getDefault(), '->setDefault() can reset the default value by passing null'); + $option->setDefault('another'); + $this->assertEquals('another', $option->getDefault(), '->setDefault() changes the default value'); + + $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY); + $option->setDefault(array(1, 2)); + $this->assertEquals(array(1, 2), $option->getDefault(), '->setDefault() changes the default value'); + + $option = new InputOption('foo', 'f', InputOption::VALUE_NONE); + try { + $option->setDefault('default'); + $this->fail('->setDefault() throws an Exception if you give a default value for a VALUE_NONE option'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->setDefault() throws an Exception if you give a default value for a VALUE_NONE option'); + $this->assertEquals('Cannot set a default value when using Option::VALUE_NONE mode.', $e->getMessage()); + } + + $option = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY); + try { + $option->setDefault('default'); + $this->fail('->setDefault() throws an Exception if you give a default value which is not an array for a VALUE_IS_ARRAY option'); + } catch (\Exception $e) { + $this->assertInstanceOf('\Exception', $e, '->setDefault() throws an Exception if you give a default value which is not an array for a VALUE_IS_ARRAY option'); + $this->assertEquals('A default value for an array option must be an array.', $e->getMessage()); + } + } + + public function testEquals() + { + $option = new InputOption('foo', 'f', null, 'Some description'); + $option2 = new InputOption('foo', 'f', null, 'Alternative description'); + $this->assertTrue($option->equals($option2)); + + $option = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, 'Some description'); + $option2 = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, 'Some description', true); + $this->assertFalse($option->equals($option2)); + + $option = new InputOption('foo', 'f', null, 'Some description'); + $option2 = new InputOption('bar', 'f', null, 'Some description'); + $this->assertFalse($option->equals($option2)); + + $option = new InputOption('foo', 'f', null, 'Some description'); + $option2 = new InputOption('foo', '', null, 'Some description'); + $this->assertFalse($option->equals($option2)); + + $option = new InputOption('foo', 'f', null, 'Some description'); + $option2 = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL, 'Some description'); + $this->assertFalse($option->equals($option2)); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputTest.php new file mode 100644 index 0000000..779d45d --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/InputTest.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + +class InputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name')))); + $this->assertEquals('foo', $input->getArgument('name'), '->__construct() takes a InputDefinition as an argument'); + } + + public function testOptions() + { + $input = new ArrayInput(array('--name' => 'foo'), new InputDefinition(array(new InputOption('name')))); + $this->assertEquals('foo', $input->getOption('name'), '->getOption() returns the value for the given option'); + + $input->setOption('name', 'bar'); + $this->assertEquals('bar', $input->getOption('name'), '->setOption() sets the value for a given option'); + $this->assertEquals(array('name' => 'bar'), $input->getOptions(), '->getOptions() returns all option values'); + + $input = new ArrayInput(array('--name' => 'foo'), new InputDefinition(array(new InputOption('name'), new InputOption('bar', '', InputOption::VALUE_OPTIONAL, '', 'default')))); + $this->assertEquals('default', $input->getOption('bar'), '->getOption() returns the default value for optional options'); + $this->assertEquals(array('name' => 'foo', 'bar' => 'default'), $input->getOptions(), '->getOptions() returns all option values, even optional ones'); + + try { + $input->setOption('foo', 'bar'); + $this->fail('->setOption() throws a \InvalidArgumentException if the option does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->setOption() throws a \InvalidArgumentException if the option does not exist'); + $this->assertEquals('The "foo" option does not exist.', $e->getMessage()); + } + + try { + $input->getOption('foo'); + $this->fail('->getOption() throws a \InvalidArgumentException if the option does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->setOption() throws a \InvalidArgumentException if the option does not exist'); + $this->assertEquals('The "foo" option does not exist.', $e->getMessage()); + } + } + + public function testArguments() + { + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name')))); + $this->assertEquals('foo', $input->getArgument('name'), '->getArgument() returns the value for the given argument'); + + $input->setArgument('name', 'bar'); + $this->assertEquals('bar', $input->getArgument('name'), '->setArgument() sets the value for a given argument'); + $this->assertEquals(array('name' => 'bar'), $input->getArguments(), '->getArguments() returns all argument values'); + + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name'), new InputArgument('bar', InputArgument::OPTIONAL, '', 'default')))); + $this->assertEquals('default', $input->getArgument('bar'), '->getArgument() returns the default value for optional arguments'); + $this->assertEquals(array('name' => 'foo', 'bar' => 'default'), $input->getArguments(), '->getArguments() returns all argument values, even optional ones'); + + try { + $input->setArgument('foo', 'bar'); + $this->fail('->setArgument() throws a \InvalidArgumentException if the argument does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->setOption() throws a \InvalidArgumentException if the option does not exist'); + $this->assertEquals('The "foo" argument does not exist.', $e->getMessage()); + } + + try { + $input->getArgument('foo'); + $this->fail('->getArgument() throws a \InvalidArgumentException if the argument does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->setOption() throws a \InvalidArgumentException if the option does not exist'); + $this->assertEquals('The "foo" argument does not exist.', $e->getMessage()); + } + } + + public function testValidate() + { + $input = new ArrayInput(array()); + $input->bind(new InputDefinition(array(new InputArgument('name', InputArgument::REQUIRED)))); + + try { + $input->validate(); + $this->fail('->validate() throws a \RuntimeException if not enough arguments are given'); + } catch (\Exception $e) { + $this->assertInstanceOf('\RuntimeException', $e, '->validate() throws a \RuntimeException if not enough arguments are given'); + $this->assertEquals('Not enough arguments.', $e->getMessage()); + } + + $input = new ArrayInput(array('name' => 'foo')); + $input->bind(new InputDefinition(array(new InputArgument('name', InputArgument::REQUIRED)))); + + try { + $input->validate(); + } catch (\RuntimeException $e) { + $this->fail('->validate() does not throw a \RuntimeException if enough arguments are given'); + } + } + + public function testSetFetInteractive() + { + $input = new ArrayInput(array()); + $this->assertTrue($input->isInteractive(), '->isInteractive() returns whether the input should be interactive or not'); + $input->setInteractive(false); + $this->assertFalse($input->isInteractive(), '->setInteractive() changes the interactive flag'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Input/StringInputTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/StringInputTest.php new file mode 100644 index 0000000..031797c --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Input/StringInputTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use Symfony\Component\Console\Input\StringInput; + +class StringInputTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getTokenizeData + */ + public function testTokenize($input, $tokens, $message) + { + $input = new StringInput($input); + $r = new \ReflectionClass('Symfony\Component\Console\Input\ArgvInput'); + $p = $r->getProperty('tokens'); + $p->setAccessible(true); + $this->assertEquals($tokens, $p->getValue($input), $message); + } + + public function getTokenizeData() + { + return array( + array('', array(), '->tokenize() parses an empty string'), + array('foo', array('foo'), '->tokenize() parses arguments'), + array(' foo bar ', array('foo', 'bar'), '->tokenize() ignores whitespaces between arguments'), + array('"quoted"', array('quoted'), '->tokenize() parses quoted arguments'), + array("'quoted'", array('quoted'), '->tokenize() parses quoted arguments'), + array('\"quoted\"', array('"quoted"'), '->tokenize() parses escaped-quoted arguments'), + array("\'quoted\'", array('\'quoted\''), '->tokenize() parses escaped-quoted arguments'), + array('-a', array('-a'), '->tokenize() parses short options'), + array('-azc', array('-azc'), '->tokenize() parses aggregated short options'), + array('-awithavalue', array('-awithavalue'), '->tokenize() parses short options with a value'), + array('-a"foo bar"', array('-afoo bar'), '->tokenize() parses short options with a value'), + array('-a"foo bar""foo bar"', array('-afoo barfoo bar'), '->tokenize() parses short options with a value'), + array('-a\'foo bar\'', array('-afoo bar'), '->tokenize() parses short options with a value'), + array('-a\'foo bar\'\'foo bar\'', array('-afoo barfoo bar'), '->tokenize() parses short options with a value'), + array('-a\'foo bar\'"foo bar"', array('-afoo barfoo bar'), '->tokenize() parses short options with a value'), + array('--long-option', array('--long-option'), '->tokenize() parses long options'), + array('--long-option=foo', array('--long-option=foo'), '->tokenize() parses long options with a value'), + array('--long-option="foo bar"', array('--long-option=foo bar'), '->tokenize() parses long options with a value'), + array('--long-option="foo bar""another"', array('--long-option=foo baranother'), '->tokenize() parses long options with a value'), + array('--long-option=\'foo bar\'', array('--long-option=foo bar'), '->tokenize() parses long options with a value'), + array("--long-option='foo bar''another'", array("--long-option=foo baranother"), '->tokenize() parses long options with a value'), + array("--long-option='foo bar'\"another\"", array("--long-option=foo baranother"), '->tokenize() parses long options with a value'), + array('foo -a -ffoo --long bar', array('foo', '-a', '-ffoo', '--long', 'bar'), '->tokenize() parses when several arguments and options'), + ); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Output/ConsoleOutputTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Output/ConsoleOutputTest.php new file mode 100644 index 0000000..7a3ede3 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Output/ConsoleOutputTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Output; + +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Console\Output\Output; + +class ConsoleOutputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $output = new ConsoleOutput(Output::VERBOSITY_QUIET, true); + $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity(), '__construct() takes the verbosity as its first argument'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Output/NullOutputTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Output/NullOutputTest.php new file mode 100644 index 0000000..8dd5f7c --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Output/NullOutputTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Output; + +use Symfony\Component\Console\Output\NullOutput; + +class NullOutputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $output = new NullOutput(); + $output->write('foo'); + $this->assertTrue(true, '->write() does nothing'); // FIXME + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Output/OutputTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Output/OutputTest.php new file mode 100644 index 0000000..aa4a204 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Output/OutputTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Output; + +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; + +class OutputTest extends \PHPUnit_Framework_TestCase +{ + public function testConstructor() + { + $output = new TestOutput(Output::VERBOSITY_QUIET, true); + $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity(), '__construct() takes the verbosity as its first argument'); + $this->assertTrue($output->isDecorated(), '__construct() takes the decorated flag as its second argument'); + } + + public function testSetIsDecorated() + { + $output = new TestOutput(); + $output->setDecorated(true); + $this->assertTrue($output->isDecorated(), 'setDecorated() sets the decorated flag'); + } + + public function testSetGetVerbosity() + { + $output = new TestOutput(); + $output->setVerbosity(Output::VERBOSITY_QUIET); + $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity(), '->setVerbosity() sets the verbosity'); + } + + public function testWrite() + { + $fooStyle = new OutputFormatterStyle('yellow', 'red', array('blink')); + $output = new TestOutput(Output::VERBOSITY_QUIET); + $output->writeln('foo'); + $this->assertEquals('', $output->output, '->writeln() outputs nothing if verbosity is set to VERBOSITY_QUIET'); + + $output = new TestOutput(); + $output->writeln(array('foo', 'bar')); + $this->assertEquals("foo\nbar\n", $output->output, '->writeln() can take an array of messages to output'); + + $output = new TestOutput(); + $output->writeln('foo', Output::OUTPUT_RAW); + $this->assertEquals("foo\n", $output->output, '->writeln() outputs the raw message if OUTPUT_RAW is specified'); + + $output = new TestOutput(); + $output->writeln('foo', Output::OUTPUT_PLAIN); + $this->assertEquals("foo\n", $output->output, '->writeln() strips decoration tags if OUTPUT_PLAIN is specified'); + + $output = new TestOutput(); + $output->setDecorated(false); + $output->writeln('foo'); + $this->assertEquals("foo\n", $output->output, '->writeln() strips decoration tags if decoration is set to false'); + + $output = new TestOutput(); + $output->getFormatter()->setStyle('FOO', $fooStyle); + $output->setDecorated(true); + $output->writeln('foo'); + $this->assertEquals("\033[33;41;5mfoo\033[0m\n", $output->output, '->writeln() decorates the output'); + + try { + $output->writeln('foo', 24); + $this->fail('->writeln() throws an \InvalidArgumentException when the type does not exist'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '->writeln() throws an \InvalidArgumentException when the type does not exist'); + $this->assertEquals('Unknown output type given (24)', $e->getMessage()); + } + + $output->clear(); + $output->write('foo'); + $this->assertEquals('foo', $output->output, '->write() do nothing when a style does not exist'); + + $output->clear(); + $output->writeln('foo'); + $this->assertEquals("foo\n", $output->output, '->writeln() do nothing when a style does not exist'); + } +} + +class TestOutput extends Output +{ + public $output = ''; + + public function clear() + { + $this->output = ''; + } + + protected function doWrite($message, $newline) + { + $this->output .= $message.($newline ? "\n" : ''); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Output/StreamOutputTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Output/StreamOutputTest.php new file mode 100644 index 0000000..b151a48 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Output/StreamOutputTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Output; + +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Output\StreamOutput; + +class StreamOutputTest extends \PHPUnit_Framework_TestCase +{ + protected $stream; + + protected function setUp() + { + $this->stream = fopen('php://memory', 'a', false); + } + + protected function tearDown() + { + $this->stream = null; + } + + public function testConstructor() + { + try { + $output = new StreamOutput('foo'); + $this->fail('__construct() throws an \InvalidArgumentException if the first argument is not a stream'); + } catch (\Exception $e) { + $this->assertInstanceOf('\InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the first argument is not a stream'); + $this->assertEquals('The StreamOutput class needs a stream as its first argument.', $e->getMessage()); + } + + $output = new StreamOutput($this->stream, Output::VERBOSITY_QUIET, true); + $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity(), '__construct() takes the verbosity as its first argument'); + $this->assertTrue($output->isDecorated(), '__construct() takes the decorated flag as its second argument'); + } + + public function testGetStream() + { + $output = new StreamOutput($this->stream); + $this->assertEquals($this->stream, $output->getStream(), '->getStream() returns the current stream'); + } + + public function testDoWrite() + { + $output = new StreamOutput($this->stream); + $output->writeln('foo'); + rewind($output->getStream()); + $this->assertEquals('foo'.PHP_EOL, stream_get_contents($output->getStream()), '->doWrite() writes to the stream'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Tester/ApplicationTesterTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Tester/ApplicationTesterTest.php new file mode 100644 index 0000000..6ce30ab --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Tester/ApplicationTesterTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Tester; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Tester\ApplicationTester; + +class ApplicationTesterTest extends \PHPUnit_Framework_TestCase +{ + protected $application; + protected $tester; + + protected function setUp() + { + $this->application = new Application(); + $this->application->setAutoExit(false); + $this->application->register('foo') + ->addArgument('foo') + ->setCode(function ($input, $output) { $output->writeln('foo'); }) + ; + + $this->tester = new ApplicationTester($this->application); + $this->tester->run(array('command' => 'foo', 'foo' => 'bar'), array('interactive' => false, 'decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE)); + } + + protected function tearDown() + { + $this->application = null; + $this->tester = null; + } + + public function testRun() + { + $this->assertFalse($this->tester->getInput()->isInteractive(), '->execute() takes an interactive option'); + $this->assertFalse($this->tester->getOutput()->isDecorated(), '->execute() takes a decorated option'); + $this->assertEquals(Output::VERBOSITY_VERBOSE, $this->tester->getOutput()->getVerbosity(), '->execute() takes a verbosity option'); + } + + public function testGetInput() + { + $this->assertEquals('bar', $this->tester->getInput()->getArgument('foo'), '->getInput() returns the current input instance'); + } + + public function testGetOutput() + { + rewind($this->tester->getOutput()->getStream()); + $this->assertEquals('foo'.PHP_EOL, stream_get_contents($this->tester->getOutput()->getStream()), '->getOutput() returns the current output instance'); + } + + public function testGetDisplay() + { + $this->assertEquals('foo'.PHP_EOL, $this->tester->getDisplay(), '->getDisplay() returns the display of the last execution'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php b/vendor/symfony/console/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php new file mode 100644 index 0000000..e64d967 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Tester; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Tester\CommandTester; + +class CommandTesterTest extends \PHPUnit_Framework_TestCase +{ + protected $application; + protected $tester; + + protected function setUp() + { + $this->command = new Command('foo'); + $this->command->addArgument('command'); + $this->command->addArgument('foo'); + $this->command->setCode(function ($input, $output) { $output->writeln('foo'); }); + + $this->tester = new CommandTester($this->command); + $this->tester->execute(array('foo' => 'bar'), array('interactive' => false, 'decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE)); + } + + protected function tearDown() + { + $this->command = null; + $this->tester = null; + } + + public function testExecute() + { + $this->assertFalse($this->tester->getInput()->isInteractive(), '->execute() takes an interactive option'); + $this->assertFalse($this->tester->getOutput()->isDecorated(), '->execute() takes a decorated option'); + $this->assertEquals(Output::VERBOSITY_VERBOSE, $this->tester->getOutput()->getVerbosity(), '->execute() takes a verbosity option'); + } + + public function testGetInput() + { + $this->assertEquals('bar', $this->tester->getInput()->getArgument('foo'), '->getInput() returns the current input instance'); + } + + public function testGetOutput() + { + rewind($this->tester->getOutput()->getStream()); + $this->assertEquals('foo'.PHP_EOL, stream_get_contents($this->tester->getOutput()->getStream()), '->getOutput() returns the current output instance'); + } + + public function testGetDisplay() + { + $this->assertEquals('foo'.PHP_EOL, $this->tester->getDisplay(), '->getDisplay() returns the display of the last execution'); + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/Tests/bootstrap.php b/vendor/symfony/console/Symfony/Component/Console/Tests/bootstrap.php new file mode 100644 index 0000000..c486b72 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/Tests/bootstrap.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +spl_autoload_register(function ($class) { + if (0 === strpos(ltrim($class, '/'), 'Symfony\Component\Console')) { + if (file_exists($file = __DIR__.'/../'.substr(str_replace('\\', '/', $class), strlen('Symfony\Component\Console')).'.php')) { + require_once $file; + } + } +}); diff --git a/vendor/symfony/console/Symfony/Component/Console/composer.json b/vendor/symfony/console/Symfony/Component/Console/composer.json new file mode 100644 index 0000000..4488bf6 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/composer.json @@ -0,0 +1,31 @@ +{ + "name": "symfony/console", + "type": "library", + "description": "Symfony Console Component", + "keywords": [], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3" + }, + "autoload": { + "psr-0": { "Symfony\\Component\\Console": "" } + }, + "target-dir": "Symfony/Component/Console", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + } +} diff --git a/vendor/symfony/console/Symfony/Component/Console/phpunit.xml.dist b/vendor/symfony/console/Symfony/Component/Console/phpunit.xml.dist new file mode 100644 index 0000000..fd1c069 --- /dev/null +++ b/vendor/symfony/console/Symfony/Component/Console/phpunit.xml.dist @@ -0,0 +1,30 @@ + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + -- 1.7.10.4