From 6fecac73545fcdf1474afa9cfcefb44e854583ab Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Mon, 30 Apr 2012 09:38:33 +0200 Subject: [PATCH 001/128] Upgrade Doctrine to latest version (2.2.2) #4681 --- .../Annotations/SimpleAnnotationReader.php | 3 - .../Doctrine/Common/Cache/MemcacheCache.php | 5 +- .../Doctrine/Common/Cache/MemcachedCache.php | 5 +- .../lib/symfony/Doctrine/Common/Version.php | 2 +- .../lib/symfony/Doctrine/DBAL/Connection.php | 2 +- .../DBAL/Driver/OCI8/OCI8Statement.php | 10 +- .../Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php | 10 +- .../Doctrine/DBAL/Platforms/MySqlPlatform.php | 41 + .../symfony/Doctrine/DBAL/SQLParserUtils.php | 6 +- .../symfony/Doctrine/DBAL/Schema/Schema.php | 3 + .../Doctrine/DBAL/Schema/TableDiff.php | 5 +- .../inc/lib/symfony/Doctrine/DBAL/Version.php | 2 +- .../symfony/Doctrine/ORM/AbstractQuery.php | 367 ++-- .../symfony/Doctrine/ORM/Configuration.php | 87 +- .../symfony/Doctrine/ORM/EntityManager.php | 199 ++- .../symfony/Doctrine/ORM/EntityRepository.php | 99 +- .../Doctrine/ORM/Event/LifecycleEventArgs.php | 43 +- .../ORM/Event/LoadClassMetadataEventArgs.php | 40 +- .../Doctrine/ORM/Event/OnClearEventArgs.php | 40 +- .../Doctrine/ORM/Event/OnFlushEventArgs.php | 46 +- .../Doctrine/ORM/Event/PostFlushEventArgs.php | 61 + .../Doctrine/ORM/Event/PreFlushEventArgs.php | 53 + .../Doctrine/ORM/Event/PreUpdateEventArgs.php | 79 +- main/inc/lib/symfony/Doctrine/ORM/Events.php | 66 +- .../Doctrine/ORM/Id/AbstractIdGenerator.php | 2 +- .../Doctrine/ORM/Id/AssignedGenerator.php | 56 +- .../Doctrine/ORM/Id/IdentityGenerator.php | 2 +- .../Doctrine/ORM/Id/SequenceGenerator.php | 13 +- .../Doctrine/ORM/Id/TableGenerator.php | 8 +- .../ORM/Internal/CommitOrderCalculator.php | 30 +- .../Internal/Hydration/AbstractHydrator.php | 214 ++- .../ORM/Internal/Hydration/ArrayHydrator.php | 154 +- .../Internal/Hydration/HydrationException.php | 11 +- .../ORM/Internal/Hydration/ObjectHydrator.php | 168 +- .../ORM/Internal/Hydration/ScalarHydrator.php | 23 +- .../Hydration/SimpleObjectHydrator.php | 182 +- .../Hydration/SingleScalarHydrator.php | 35 +- .../Doctrine/ORM/Mapping/Annotation.php | 24 + .../Mapping/Builder/AssociationBuilder.php | 167 ++ .../Mapping/Builder/ClassMetadataBuilder.php | 470 +++++ .../ORM/Mapping/Builder/FieldBuilder.php | 223 +++ .../Builder/ManyToManyAssociationBuilder.php | 86 + .../Builder/OneToManyAssociationBuilder.php | 62 + .../ORM/Mapping/ChangeTrackingPolicy.php | 30 + .../Doctrine/ORM/Mapping/ClassMetadata.php | 304 +--- .../ORM/Mapping/ClassMetadataFactory.php | 108 +- .../ORM/Mapping/ClassMetadataInfo.php | 463 ++++- .../symfony/Doctrine/ORM/Mapping/Column.php | 46 + .../ORM/Mapping/DiscriminatorColumn.php | 36 + .../Doctrine/ORM/Mapping/DiscriminatorMap.php | 30 + .../ORM/Mapping/Driver/AbstractFileDriver.php | 39 +- .../ORM/Mapping/Driver/AnnotationDriver.php | 101 +- .../ORM/Mapping/Driver/DatabaseDriver.php | 38 +- .../Mapping/Driver/DoctrineAnnotations.php | 222 +-- .../Doctrine/ORM/Mapping/Driver/Driver.php | 8 +- .../ORM/Mapping/Driver/DriverChain.php | 2 +- .../Mapping/Driver/SimplifiedXmlDriver.php | 176 ++ .../Mapping/Driver/SimplifiedYamlDriver.php | 181 ++ .../ORM/Mapping/Driver/StaticPHPDriver.php | 10 +- .../Doctrine/ORM/Mapping/Driver/XmlDriver.php | 41 +- .../ORM/Mapping/Driver/YamlDriver.php | 69 +- .../ORM/Mapping/ElementCollection.php | 31 + .../symfony/Doctrine/ORM/Mapping/Entity.php | 32 + .../Doctrine/ORM/Mapping/GeneratedValue.php | 30 + .../ORM/Mapping/HasLifecycleCallbacks.php | 28 + .../lib/symfony/Doctrine/ORM/Mapping/Id.php | 28 + .../symfony/Doctrine/ORM/Mapping/Index.php | 32 + .../Doctrine/ORM/Mapping/InheritanceType.php | 30 + .../Doctrine/ORM/Mapping/JoinColumn.php | 42 + .../Doctrine/ORM/Mapping/JoinColumns.php | 30 + .../Doctrine/ORM/Mapping/JoinTable.php | 36 + .../Doctrine/ORM/Mapping/ManyToMany.php | 42 + .../Doctrine/ORM/Mapping/ManyToOne.php | 36 + .../Doctrine/ORM/Mapping/MappedSuperclass.php | 30 + .../Doctrine/ORM/Mapping/MappingException.php | 46 +- .../Doctrine/ORM/Mapping/NamedQueries.php | 30 + .../Doctrine/ORM/Mapping/NamedQuery.php | 32 + .../Doctrine/ORM/Mapping/OneToMany.php | 40 + .../symfony/Doctrine/ORM/Mapping/OneToOne.php | 40 + .../symfony/Doctrine/ORM/Mapping/OrderBy.php | 30 + .../symfony/Doctrine/ORM/Mapping/PostLoad.php | 28 + .../Doctrine/ORM/Mapping/PostPersist.php | 28 + .../Doctrine/ORM/Mapping/PostRemove.php | 28 + .../Doctrine/ORM/Mapping/PostUpdate.php | 28 + .../symfony/Doctrine/ORM/Mapping/PreFlush.php | 28 + .../Doctrine/ORM/Mapping/PrePersist.php | 28 + .../Doctrine/ORM/Mapping/PreRemove.php | 28 + .../Doctrine/ORM/Mapping/PreUpdate.php | 28 + .../ORM/Mapping/SequenceGenerator.php | 34 + .../symfony/Doctrine/ORM/Mapping/Table.php | 36 + .../Doctrine/ORM/Mapping/UniqueConstraint.php | 32 + .../symfony/Doctrine/ORM/Mapping/Version.php | 28 + .../lib/symfony/Doctrine/ORM/NativeQuery.php | 23 +- .../Doctrine/ORM/NoResultException.php | 2 +- .../Doctrine/ORM/NonUniqueResultException.php | 2 +- .../lib/symfony/Doctrine/ORM/ORMException.php | 24 +- .../ORM/ORMInvalidArgumentException.php | 107 ++ .../Doctrine/ORM/PersistentCollection.php | 252 ++- .../AbstractCollectionPersister.php | 34 +- .../AbstractEntityInheritancePersister.php | 24 +- .../ORM/Persisters/BasicEntityPersister.php | 476 +++-- .../Persisters/JoinedSubclassPersister.php | 158 +- .../ORM/Persisters/ManyToManyPersister.php | 328 ++-- .../ORM/Persisters/OneToManyPersister.php | 165 +- .../ORM/Persisters/SingleTablePersister.php | 43 +- .../ORM/Persisters/UnionSubclassPersister.php | 2 +- .../symfony/Doctrine/ORM/Proxy/Autoloader.php | 78 + .../lib/symfony/Doctrine/ORM/Proxy/Proxy.php | 8 +- .../Doctrine/ORM/Proxy/ProxyException.php | 10 +- .../Doctrine/ORM/Proxy/ProxyFactory.php | 127 +- main/inc/lib/symfony/Doctrine/ORM/Query.php | 105 +- .../ORM/Query/AST/ArithmeticFactor.php | 2 +- .../ORM/Query/AST/CoalesceExpression.php | 6 +- .../Query/AST/CollectionMemberExpression.php | 2 +- .../ORM/Query/AST/DeleteStatement.php | 2 +- .../EmptyCollectionComparisonExpression.php | 2 +- .../Doctrine/ORM/Query/AST/FromClause.php | 4 +- .../ORM/Query/AST/Functions/AbsFunction.php | 4 +- .../Query/AST/Functions/BitAndFunction.php | 63 + .../ORM/Query/AST/Functions/BitOrFunction.php | 63 + .../AST/Functions/CurrentDateFunction.php | 2 +- .../Query/AST/Functions/IdentityFunction.php | 68 + .../Query/AST/Functions/LengthFunction.php | 4 +- .../Query/AST/Functions/LocateFunction.php | 12 +- .../ORM/Query/AST/Functions/LowerFunction.php | 4 +- .../ORM/Query/AST/Functions/ModFunction.php | 8 +- .../ORM/Query/AST/Functions/SizeFunction.php | 18 +- .../ORM/Query/AST/Functions/SqrtFunction.php | 4 +- .../Query/AST/Functions/SubstringFunction.php | 6 +- .../ORM/Query/AST/Functions/UpperFunction.php | 4 +- .../ORM/Query/AST/GeneralCaseExpression.php | 48 + .../AST/IdentificationVariableDeclaration.php | 2 +- .../Doctrine/ORM/Query/AST/InExpression.php | 6 +- .../Doctrine/ORM/Query/AST/IndexBy.php | 4 +- .../ORM/Query/AST/InstanceOfExpression.php | 5 +- .../symfony/Doctrine/ORM/Query/AST/Join.php | 4 +- .../AST/JoinAssociationPathExpression.php | 2 +- .../ORM/Query/AST/JoinVariableDeclaration.php | 2 +- .../Doctrine/ORM/Query/AST/Literal.php | 6 +- .../symfony/Doctrine/ORM/Query/AST/Node.php | 26 +- .../Query/AST/NullComparisonExpression.php | 2 +- .../ORM/Query/AST/NullIfExpression.php | 6 +- .../Doctrine/ORM/Query/AST/OrderByItem.php | 2 +- .../ORM/Query/AST/PartialObjectExpression.php | 2 +- .../Doctrine/ORM/Query/AST/PathExpression.php | 10 +- .../Query/AST/RangeVariableDeclaration.php | 4 +- .../Doctrine/ORM/Query/AST/SelectClause.php | 2 +- .../ORM/Query/AST/SelectExpression.php | 10 +- .../ORM/Query/AST/SelectStatement.php | 4 +- .../ORM/Query/AST/SimpleCaseExpression.php | 50 + .../ORM/Query/AST/SimpleSelectClause.php | 2 +- .../ORM/Query/AST/SimpleSelectExpression.php | 4 +- .../ORM/Query/AST/SimpleWhenClause.php | 48 + .../Doctrine/ORM/Query/AST/Subselect.php | 4 +- .../ORM/Query/AST/SubselectFromClause.php | 4 +- .../ORM/Query/AST/UpdateStatement.php | 2 +- .../Doctrine/ORM/Query/AST/WhenClause.php | 48 + .../ORM/Query/Exec/AbstractSqlExecutor.php | 19 +- .../Query/Exec/MultiTableDeleteExecutor.php | 17 +- .../Query/Exec/MultiTableUpdateExecutor.php | 36 +- .../ORM/Query/Exec/SingleSelectExecutor.php | 8 +- .../Exec/SingleTableDeleteUpdateExecutor.php | 10 +- .../lib/symfony/Doctrine/ORM/Query/Expr.php | 10 +- .../symfony/Doctrine/ORM/Query/Expr/Andx.php | 1 + .../symfony/Doctrine/ORM/Query/Expr/Base.php | 12 +- .../Doctrine/ORM/Query/Expr/Comparison.php | 2 +- .../Doctrine/ORM/Query/Expr/Composite.php | 2 +- .../symfony/Doctrine/ORM/Query/Expr/From.php | 36 +- .../symfony/Doctrine/ORM/Query/Expr/Join.php | 4 +- .../symfony/Doctrine/ORM/Query/Expr/Math.php | 8 +- .../symfony/Doctrine/ORM/Query/Expr/Orx.php | 3 +- .../Doctrine/ORM/Query/Filter/SQLFilter.php | 122 ++ .../Doctrine/ORM/Query/FilterCollection.php | 198 +++ .../lib/symfony/Doctrine/ORM/Query/Lexer.php | 180 +- .../ORM/Query/ParameterTypeInferer.php | 4 +- .../lib/symfony/Doctrine/ORM/Query/Parser.php | 1162 +++++++----- .../Doctrine/ORM/Query/ParserResult.php | 20 +- .../Doctrine/ORM/Query/QueryException.php | 5 + .../Doctrine/ORM/Query/ResultSetMapping.php | 177 +- .../ORM/Query/ResultSetMappingBuilder.php | 6 +- .../symfony/Doctrine/ORM/Query/SqlWalker.php | 1307 ++++++++------ .../symfony/Doctrine/ORM/Query/TreeWalker.php | 10 +- .../Doctrine/ORM/Query/TreeWalkerAdapter.php | 22 +- .../Doctrine/ORM/Query/TreeWalkerChain.php | 33 +- .../lib/symfony/Doctrine/ORM/QueryBuilder.php | 150 +- .../Command/ClearCache/MetadataCommand.php | 49 +- .../Command/ClearCache/QueryCommand.php | 49 +- .../Command/ClearCache/ResultCommand.php | 132 +- .../Command/ConvertDoctrine1SchemaCommand.php | 4 +- .../Console/Command/ConvertMappingCommand.php | 2 +- .../Command/GenerateEntitiesCommand.php | 6 +- .../Command/GenerateProxiesCommand.php | 4 +- .../Command/GenerateRepositoriesCommand.php | 4 +- .../Command/SchemaTool/UpdateCommand.php | 2 +- .../Console/Command/ValidateSchemaCommand.php | 2 +- .../ORM/Tools/Console/ConsoleRunner.php | 2 +- .../ORM/Tools/Console/MetadataFilter.php | 2 +- .../ORM/Tools/ConvertDoctrine1Schema.php | 2 +- .../ORM/Tools/DebugUnitOfWorkListener.php | 151 ++ .../DisconnectedClassMetadataFactory.php | 36 +- .../Doctrine/ORM/Tools/EntityGenerator.php | 95 +- .../Tools/Export/Driver/AbstractExporter.php | 42 +- .../Export/Driver/AnnotationExporter.php | 2 +- .../ORM/Tools/Export/Driver/PhpExporter.php | 12 +- .../ORM/Tools/Export/Driver/XmlExporter.php | 23 +- .../ORM/Tools/Export/Driver/YamlExporter.php | 12 +- .../ORM/Tools/Pagination/CountWalker.php | 80 + .../Tools/Pagination/LimitSubqueryWalker.php | 115 ++ .../ORM/Tools/Pagination/Paginator.php | 180 ++ .../ORM/Tools/Pagination/WhereInWalker.php | 142 ++ .../ORM/Tools/ResolveTargetEntityListener.php | 94 + .../symfony/Doctrine/ORM/Tools/SchemaTool.php | 40 +- .../Doctrine/ORM/Tools/SchemaValidator.php | 262 +-- .../lib/symfony/Doctrine/ORM/Tools/Setup.php | 60 +- .../Doctrine/ORM/Tools/ToolsException.php | 27 + .../lib/symfony/Doctrine/ORM/UnitOfWork.php | 1565 +++++++++++------ main/inc/lib/symfony/Doctrine/ORM/Version.php | 6 +- 217 files changed, 11124 insertions(+), 4306 deletions(-) create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Event/PostFlushEventArgs.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Event/PreFlushEventArgs.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Annotation.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/FieldBuilder.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/ManyToManyAssociationBuilder.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/OneToManyAssociationBuilder.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Column.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/DiscriminatorColumn.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/DiscriminatorMap.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/ElementCollection.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Entity.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/GeneratedValue.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Id.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Index.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/InheritanceType.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinColumn.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinColumns.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinTable.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/ManyToMany.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/ManyToOne.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/MappedSuperclass.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/NamedQueries.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/NamedQuery.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/OneToMany.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/OneToOne.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/OrderBy.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/PostLoad.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/PostPersist.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/PostRemove.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/PostUpdate.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/PreFlush.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/PrePersist.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/PreRemove.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/PreUpdate.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/SequenceGenerator.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Table.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/UniqueConstraint.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Mapping/Version.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/ORMInvalidArgumentException.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Proxy/Autoloader.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Query/AST/GeneralCaseExpression.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleCaseExpression.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleWhenClause.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Query/AST/WhenClause.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Query/Filter/SQLFilter.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Query/FilterCollection.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Tools/DebugUnitOfWorkListener.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/CountWalker.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/Paginator.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/WhereInWalker.php create mode 100644 main/inc/lib/symfony/Doctrine/ORM/Tools/ResolveTargetEntityListener.php diff --git a/main/inc/lib/symfony/Doctrine/Common/Annotations/SimpleAnnotationReader.php b/main/inc/lib/symfony/Doctrine/Common/Annotations/SimpleAnnotationReader.php index ade6dced04..a13c7fa072 100644 --- a/main/inc/lib/symfony/Doctrine/Common/Annotations/SimpleAnnotationReader.php +++ b/main/inc/lib/symfony/Doctrine/Common/Annotations/SimpleAnnotationReader.php @@ -68,7 +68,6 @@ class SimpleAnnotationReader implements Reader */ public function getClassAnnotations(\ReflectionClass $class) { - $this->parser->setTarget(Target::TARGET_CLASS); return $this->parser->parse($class->getDocComment(), 'class '.$class->getName()); } @@ -81,7 +80,6 @@ class SimpleAnnotationReader implements Reader */ public function getMethodAnnotations(\ReflectionMethod $method) { - $this->parser->setTarget(Target::TARGET_METHOD); return $this->parser->parse($method->getDocComment(), 'method '.$method->getDeclaringClass()->name.'::'.$method->getName().'()'); } @@ -94,7 +92,6 @@ class SimpleAnnotationReader implements Reader */ public function getPropertyAnnotations(\ReflectionProperty $property) { - $this->parser->setTarget(Target::TARGET_PROPERTY); return $this->parser->parse($property->getDocComment(), 'property '.$property->getDeclaringClass()->name.'::$'.$property->getName()); } diff --git a/main/inc/lib/symfony/Doctrine/Common/Cache/MemcacheCache.php b/main/inc/lib/symfony/Doctrine/Common/Cache/MemcacheCache.php index aacbfd3887..dd6d1e3147 100644 --- a/main/inc/lib/symfony/Doctrine/Common/Cache/MemcacheCache.php +++ b/main/inc/lib/symfony/Doctrine/Common/Cache/MemcacheCache.php @@ -82,6 +82,9 @@ class MemcacheCache extends CacheProvider */ protected function doSave($id, $data, $lifeTime = 0) { + if ($lifeTime > 30 * 24 * 3600) { + $lifeTime = time() + $lifeTime; + } return $this->memcache->set($id, $data, 0, (int) $lifeTime); } @@ -115,4 +118,4 @@ class MemcacheCache extends CacheProvider Cache::STATS_MEMORY_AVAILIABLE => $stats['limit_maxbytes'], ); } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/Common/Cache/MemcachedCache.php b/main/inc/lib/symfony/Doctrine/Common/Cache/MemcachedCache.php index 3f7f8e8c53..4675fae70b 100644 --- a/main/inc/lib/symfony/Doctrine/Common/Cache/MemcachedCache.php +++ b/main/inc/lib/symfony/Doctrine/Common/Cache/MemcachedCache.php @@ -82,6 +82,9 @@ class MemcachedCache extends CacheProvider */ protected function doSave($id, $data, $lifeTime = 0) { + if ($lifeTime > 30 * 24 * 3600) { + $lifeTime = time() + $lifeTime; + } return $this->memcached->set($id, $data, (int) $lifeTime); } @@ -118,4 +121,4 @@ class MemcachedCache extends CacheProvider Cache::STATS_MEMORY_AVAILIABLE => $stats['limit_maxbytes'], ); } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/Common/Version.php b/main/inc/lib/symfony/Doctrine/Common/Version.php index c5e1a2c73b..b7c9a8284e 100644 --- a/main/inc/lib/symfony/Doctrine/Common/Version.php +++ b/main/inc/lib/symfony/Doctrine/Common/Version.php @@ -36,7 +36,7 @@ class Version /** * Current Doctrine Version */ - const VERSION = '2.2.0'; + const VERSION = '2.2.2'; /** * Compares a Doctrine version with the current one. diff --git a/main/inc/lib/symfony/Doctrine/DBAL/Connection.php b/main/inc/lib/symfony/Doctrine/DBAL/Connection.php index bf864b112d..abe93763c6 100644 --- a/main/inc/lib/symfony/Doctrine/DBAL/Connection.php +++ b/main/inc/lib/symfony/Doctrine/DBAL/Connection.php @@ -565,7 +565,7 @@ class Connection implements DriverConnection $this->connect(); list($value, $bindingType) = $this->getBindingInfo($input, $type); - return $this->_conn->quote($input, $bindingType); + return $this->_conn->quote($value, $bindingType); } /** diff --git a/main/inc/lib/symfony/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php b/main/inc/lib/symfony/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php index c2f74017b3..048cbe6727 100644 --- a/main/inc/lib/symfony/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php +++ b/main/inc/lib/symfony/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php @@ -227,8 +227,14 @@ class OCI8Statement implements \IteratorAggregate, Statement } $result = array(); - oci_fetch_all($this->_sth, $result, 0, -1, - self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_FETCHSTATEMENT_BY_ROW | OCI_RETURN_LOBS); + if (self::$fetchStyleMap[$fetchStyle] === OCI_BOTH) { + while ($row = $this->fetch($fetchStyle)) { + $result[] = $row; + } + } else { + oci_fetch_all($this->_sth, $result, 0, -1, + self::$fetchStyleMap[$fetchStyle] | OCI_RETURN_NULLS | OCI_FETCHSTATEMENT_BY_ROW | OCI_RETURN_LOBS); + } return $result; } diff --git a/main/inc/lib/symfony/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php b/main/inc/lib/symfony/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php index 4ecd8366b3..d3c6bf1ece 100644 --- a/main/inc/lib/symfony/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php +++ b/main/inc/lib/symfony/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php @@ -53,9 +53,13 @@ class Driver implements \Doctrine\DBAL\Driver $dsn .= ',' . $params['port']; } - if (isset($params['dbname'])) { - $dsn .= ';Database=' . $params['dbname']; - } + if (isset($params['dbname'])) {; + $dsn .= ';Database=' . $params['dbname']; + } + + if (isset($params['MultipleActiveResultSets'])) { + $dsn .= '; MultipleActiveResultSets=' . ($params['MultipleActiveResultSets'] ? 'true' : 'false'); + } return $dsn; } diff --git a/main/inc/lib/symfony/Doctrine/DBAL/Platforms/MySqlPlatform.php b/main/inc/lib/symfony/Doctrine/DBAL/Platforms/MySqlPlatform.php index c4e685dba9..8520e4543b 100644 --- a/main/inc/lib/symfony/Doctrine/DBAL/Platforms/MySqlPlatform.php +++ b/main/inc/lib/symfony/Doctrine/DBAL/Platforms/MySqlPlatform.php @@ -519,6 +519,47 @@ class MySqlPlatform extends AbstractPlatform return array_merge($sql, $tableSql, $columnSql); } + /** + * Fix for DROP/CREATE index after foreign key change from OneToOne to ManyToOne + * + * @param TableDiff $diff + * @return array + */ + 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; + } + /** * Obtain DBMS specific SQL code portion needed to declare an integer type * field to be used in statements like CREATE TABLE. diff --git a/main/inc/lib/symfony/Doctrine/DBAL/SQLParserUtils.php b/main/inc/lib/symfony/Doctrine/DBAL/SQLParserUtils.php index cc980ea3fd..b3704df99e 100644 --- a/main/inc/lib/symfony/Doctrine/DBAL/SQLParserUtils.php +++ b/main/inc/lib/symfony/Doctrine/DBAL/SQLParserUtils.php @@ -61,7 +61,7 @@ class SQLParserUtils } else { $name = ""; // TODO: Something faster/better to match this than regex? - for ($j = $i; ($j < $stmtLen && preg_match('(([:a-zA-Z0-9]{1}))', $statement[$j])); $j++) { + for ($j = $i; ($j < $stmtLen && preg_match('(([:a-zA-Z0-9_]{1}))', $statement[$j])); $j++) { $name .= $statement[$j]; } $paramMap[$name][] = $i; // named parameters can be duplicated! @@ -90,7 +90,7 @@ class SQLParserUtils $bindIndex = -1; foreach ($types AS $name => $type) { ++$bindIndex; - if ($type === Connection::PARAM_INT_ARRAY || $type == Connection::PARAM_STR_ARRAY) { + if ($type === Connection::PARAM_INT_ARRAY || $type === Connection::PARAM_STR_ARRAY) { if ($isPositional) { $name = $bindIndex; } @@ -176,4 +176,4 @@ class SQLParserUtils return array($query, $params, $types); } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/DBAL/Schema/Schema.php b/main/inc/lib/symfony/Doctrine/DBAL/Schema/Schema.php index 53b53f1328..2c1b642c57 100644 --- a/main/inc/lib/symfony/Doctrine/DBAL/Schema/Schema.php +++ b/main/inc/lib/symfony/Doctrine/DBAL/Schema/Schema.php @@ -155,6 +155,9 @@ class Schema extends AbstractAsset */ private function getFullQualifiedAssetName($name) { + if ($this->isQuoted($name)) { + $name = $this->trimQuotes($name); + } if (strpos($name, ".") === false) { $name = $this->getName() . "." . $name; } diff --git a/main/inc/lib/symfony/Doctrine/DBAL/Schema/TableDiff.php b/main/inc/lib/symfony/Doctrine/DBAL/Schema/TableDiff.php index f03e271264..5f99ce29e6 100644 --- a/main/inc/lib/symfony/Doctrine/DBAL/Schema/TableDiff.php +++ b/main/inc/lib/symfony/Doctrine/DBAL/Schema/TableDiff.php @@ -1,7 +1,5 @@ */ class TableDiff @@ -136,4 +133,4 @@ class TableDiff $this->changedIndexes = $changedIndexes; $this->removedIndexes = $removedIndexes; } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/DBAL/Version.php b/main/inc/lib/symfony/Doctrine/DBAL/Version.php index a534b02b6e..0fb2e779ea 100644 --- a/main/inc/lib/symfony/Doctrine/DBAL/Version.php +++ b/main/inc/lib/symfony/Doctrine/DBAL/Version.php @@ -36,7 +36,7 @@ class Version /** * Current Doctrine Version */ - const VERSION = '2.2.1'; + const VERSION = '2.2.2'; /** * Compares a Doctrine version with the current one. diff --git a/main/inc/lib/symfony/Doctrine/ORM/AbstractQuery.php b/main/inc/lib/symfony/Doctrine/ORM/AbstractQuery.php index 559d3e32bc..0dba9dc6ee 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/AbstractQuery.php +++ b/main/inc/lib/symfony/Doctrine/ORM/AbstractQuery.php @@ -20,7 +20,9 @@ namespace Doctrine\ORM; use Doctrine\DBAL\Types\Type, - Doctrine\ORM\Query\QueryException; + Doctrine\DBAL\Cache\QueryCacheProfile, + Doctrine\ORM\Query\QueryException, + Doctrine\ORM\Internal\Hydration\CacheHydrator; /** * Base contract for ORM queries. Base class for Query and NativeQuery. @@ -28,7 +30,6 @@ use Doctrine\DBAL\Types\Type, * @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 @@ -91,23 +92,9 @@ abstract class AbstractQuery protected $_hydrationMode = self::HYDRATE_OBJECT; /** - * The locally set cache driver used for caching result sets of this query. - * - * @var CacheDriver - */ - protected $_resultCacheDriver; - - /** - * Boolean flag for whether or not to cache the results of this query. - * - * @var boolean + * @param \Doctrine\DBAL\Cache\QueryCacheProfile */ - protected $_useResultCache; - - /** - * @var string The id to store the result cache entry under. - */ - protected $_resultCacheId; + protected $_queryCacheProfile; /** * @var boolean Boolean value that indicates whether or not expire the result cache. @@ -115,9 +102,9 @@ abstract class AbstractQuery protected $_expireResultCache = false; /** - * @var int Result Cache lifetime. + * @param \Doctrine\DBAL\Cache\QueryCacheProfile */ - protected $_resultCacheTTL; + protected $_hydrationCacheProfile; /** * Initializes a new instance of a class derived from AbstractQuery. @@ -162,7 +149,7 @@ abstract class AbstractQuery { return $this->_params; } - + /** * Get all defined parameter types. * @@ -181,7 +168,11 @@ abstract class AbstractQuery */ public function getParameter($key) { - return isset($this->_params[$key]) ? $this->_params[$key] : null; + if (isset($this->_params[$key])) { + return $this->_params[$key]; + } + + return null; } /** @@ -192,7 +183,11 @@ abstract class AbstractQuery */ public function getParameterType($key) { - return isset($this->_paramTypes[$key]) ? $this->_paramTypes[$key] : null; + if (isset($this->_paramTypes[$key])) { + return $this->_paramTypes[$key]; + } + + return null; } /** @@ -216,16 +211,66 @@ abstract class AbstractQuery */ public function setParameter($key, $value, $type = null) { + $key = trim($key, ':'); + + $value = $this->processParameterValue($value); if ($type === null) { $type = Query\ParameterTypeInferer::inferType($value); } - + $this->_paramTypes[$key] = $type; $this->_params[$key] = $value; - + return $this; } + /** + * Process an individual parameter value + * + * @param mixed $value + * @return array + */ + private function processParameterValue($value) + { + switch (true) { + case is_array($value): + for ($i = 0, $l = count($value); $i < $l; $i++) { + $paramValue = $this->processParameterValue($value[$i]); + $value[$i] = is_array($paramValue) ? $paramValue[key($paramValue)] : $paramValue; + } + + return $value; + + case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value)): + return $this->convertObjectParameterToScalarValue($value); + + default: + return $value; + } + } + + protected 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."); + } + + if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) { + $values = $this->_em->getUnitOfWork()->getEntityIdentifier($value); + } else { + $values = $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 a collection of query parameters. * @@ -236,12 +281,9 @@ abstract class AbstractQuery public function setParameters(array $params, array $types = array()) { foreach ($params as $key => $value) { - if (isset($types[$key])) { - $this->setParameter($key, $value, $types[$key]); - } else { - $this->setParameter($key, $value); - } + $this->setParameter($key, $value, isset($types[$key]) ? $types[$key] : null); } + return $this; } @@ -254,11 +296,74 @@ abstract class AbstractQuery public function setResultSetMapping(Query\ResultSetMapping $rsm) { $this->_resultSetMapping = $rsm; + return $this; } /** - * Defines a cache driver to be used for caching result sets. + * 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 @@ -268,25 +373,27 @@ abstract class AbstractQuery if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) { throw ORMException::invalidResultCacheDriver(); } - $this->_resultCacheDriver = $resultCacheDriver; - if ($resultCacheDriver) { - $this->_useResultCache = true; - } + + $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->_resultCacheDriver) { - return $this->_resultCacheDriver; - } else { - return $this->_em->getConfiguration()->getResultCacheImpl(); + if ($this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) { + return $this->_queryCacheProfile->getResultCacheDriver(); } + + return $this->_em->getConfiguration()->getResultCacheImpl(); } /** @@ -294,46 +401,50 @@ abstract class AbstractQuery * how long and which ID to use for the cache entry. * * @param boolean $bool - * @param integer $timeToLive + * @param integer $lifetime * @param string $resultCacheId * @return \Doctrine\ORM\AbstractQuery This query instance. */ - public function useResultCache($bool, $timeToLive = null, $resultCacheId = null) + public function useResultCache($bool, $lifetime = null, $resultCacheId = null) { - $this->_useResultCache = $bool; - if ($timeToLive) { - $this->setResultCacheLifetime($timeToLive); - } - if ($resultCacheId) { - $this->_resultCacheId = $resultCacheId; + 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 $timeToLive How long the cache entry is valid. + * @param integer $lifetime How long the cache entry is valid. * @return \Doctrine\ORM\AbstractQuery This query instance. */ - public function setResultCacheLifetime($timeToLive) + public function setResultCacheLifetime($lifetime) { - if ($timeToLive !== null) { - $timeToLive = (int) $timeToLive; - } + $lifetime = ($lifetime !== null) ? (int) $lifetime : 0; + + $this->_queryCacheProfile = $this->_queryCacheProfile + ? $this->_queryCacheProfile->setLifetime($lifetime) + : new QueryCacheProfile($lifetime, null, $this->_em->getConfiguration()->getResultCacheImpl()); - $this->_resultCacheTTL = $timeToLive; return $this; } /** * Retrieves the lifetime of resultset cache. * + * @deprecated * @return integer */ public function getResultCacheLifetime() { - return $this->_resultCacheTTL; + return $this->_queryCacheProfile ? $this->_queryCacheProfile->getLifetime() : 0; } /** @@ -345,6 +456,7 @@ abstract class AbstractQuery public function expireResultCache($expire = true) { $this->_expireResultCache = $expire; + return $this; } @@ -358,6 +470,14 @@ abstract class AbstractQuery return $this->_expireResultCache; } + /** + * @return QueryCacheProfile + */ + public function getQueryCacheProfile() + { + return $this->_queryCacheProfile; + } + /** * Change the default fetch mode of an association for this query. * @@ -375,6 +495,7 @@ abstract class AbstractQuery } $this->_hints['fetchMode'][$class][$assocName] = $fetchMode; + return $this; } @@ -388,6 +509,7 @@ abstract class AbstractQuery public function setHydrationMode($hydrationMode) { $this->_hydrationMode = $hydrationMode; + return $this; } @@ -452,14 +574,15 @@ abstract class AbstractQuery return null; } - if (is_array($result)) { - if (count($result) > 1) { - throw new NonUniqueResultException; - } - return array_shift($result); + if ( ! is_array($result)) { + return $result; + } + + if (count($result) > 1) { + throw new NonUniqueResultException; } - return $result; + return array_shift($result); } /** @@ -483,14 +606,15 @@ abstract class AbstractQuery throw new NoResultException; } - if (is_array($result)) { - if (count($result) > 1) { - throw new NonUniqueResultException; - } - return array_shift($result); + if ( ! is_array($result)) { + return $result; + } + + if (count($result) > 1) { + throw new NonUniqueResultException; } - return $result; + return array_shift($result); } /** @@ -516,6 +640,7 @@ abstract class AbstractQuery public function setHint($name, $value) { $this->_hints[$name] = $value; + return $this; } @@ -532,7 +657,7 @@ abstract class AbstractQuery /** * Return the key value map of query hints that are currently set. - * + * * @return array */ public function getHints() @@ -546,7 +671,7 @@ abstract class AbstractQuery * * @param array $params The query parameters. * @param integer $hydrationMode The hydration mode to use. - * @return IterableResult + * @return \Doctrine\ORM\Internal\Hydration\IterableResult */ public function iterate(array $params = array(), $hydrationMode = null) { @@ -582,37 +707,68 @@ abstract class AbstractQuery $this->setParameters($params); } - // Check result cache - if ($this->_useResultCache && $cacheDriver = $this->getResultCacheDriver()) { - list($key, $hash) = $this->getResultCacheId(); - $cached = $this->_expireResultCache ? false : $cacheDriver->fetch($hash); + $setCacheEntry = function() {}; - if ($cached === false || !isset($cached[$key])) { - // Cache miss. - $stmt = $this->_doExecute(); + if ($this->_hydrationCacheProfile !== null) { + list($cacheKey, $realCacheKey) = $this->getHydrationCacheId(); - $result = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll( - $stmt, $this->_resultSetMapping, $this->_hints - ); + $queryCacheProfile = $this->getHydrationCacheProfile(); + $cache = $queryCacheProfile->getResultCacheDriver(); + $result = $cache->fetch($cacheKey); - $cacheDriver->save($hash, array($key => $result), $this->_resultCacheTTL); + if (isset($result[$realCacheKey])) { + return $result[$realCacheKey]; + } - return $result; - } else { - // Cache hit. - return $cached[$key]; + 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; } - return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll( - $stmt, $this->_resultSetMapping, $this->_hints - ); + $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() + { + $params = $this->getParameters(); + + foreach ($params AS $key => $value) { + $params[$key] = $this->processParameterValue($value); + } + + $sql = $this->getSQL(); + $queryCacheProfile = $this->getHydrationCacheProfile(); + $hints = $this->getHints(); + $hints['hydrationMode'] = $this->getHydrationMode(); + ksort($hints); + + return $queryCacheProfile->generateCacheKeys($sql, $params, $hints); } /** @@ -625,43 +781,22 @@ abstract class AbstractQuery */ public function setResultCacheId($id) { - $this->_resultCacheId = $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. - * Will return the configured id if it exists otherwise a hash will be - * automatically generated for you. + * Get the result cache id to use to store the result set cache entry if set. * - * @return array ($key, $hash) + * @deprecated + * @return string */ - protected function getResultCacheId() + public function getResultCacheId() { - if ($this->_resultCacheId) { - return array($this->_resultCacheId, $this->_resultCacheId); - } else { - $params = $this->_params; - foreach ($params AS $key => $value) { - if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($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); - } - $params[$key] = $idValues; - } else { - $params[$key] = $value; - } - } - - $sql = $this->getSql(); - ksort($this->_hints); - $key = implode(";", (array)$sql) . var_export($params, true) . - var_export($this->_hints, true)."&hydrationMode=".$this->_hydrationMode; - return array($key, md5($key)); - } + return $this->_queryCacheProfile ? $this->_queryCacheProfile->getCacheKey() : null; } /** diff --git a/main/inc/lib/symfony/Doctrine/ORM/Configuration.php b/main/inc/lib/symfony/Doctrine/ORM/Configuration.php index bb1ba2b50f..4189f91ac4 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Configuration.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Configuration.php @@ -23,7 +23,6 @@ use Doctrine\Common\Cache\Cache, Doctrine\Common\Cache\ArrayCache, Doctrine\Common\Annotations\AnnotationRegistry, Doctrine\Common\Annotations\AnnotationReader, - Doctrine\Common\Annotations\SimpleAnnotationReader, Doctrine\ORM\Mapping\Driver\Driver, Doctrine\ORM\Mapping\Driver\AnnotationDriver; @@ -129,7 +128,7 @@ class Configuration extends \Doctrine\DBAL\Configuration // Register the ORM Annotations in the AnnotationRegistry AnnotationRegistry::registerFile(__DIR__ . '/Mapping/Driver/DoctrineAnnotations.php'); - $reader = new SimpleAnnotationReader(); + $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-DEV', '>=')) { @@ -211,45 +210,46 @@ class Configuration extends \Doctrine\DBAL\Configuration } /** - * Gets the cache driver implementation that is used for query result caching. + * Gets the cache driver implementation that is used for the query cache (SQL cache). * * @return \Doctrine\Common\Cache\Cache */ - public function getResultCacheImpl() + public function getQueryCacheImpl() { - return isset($this->_attributes['resultCacheImpl']) ? - $this->_attributes['resultCacheImpl'] : null; + return isset($this->_attributes['queryCacheImpl']) ? + $this->_attributes['queryCacheImpl'] : null; } /** - * Sets the cache driver implementation that is used for query result caching. + * Sets the cache driver implementation that is used for the query cache (SQL cache). * * @param \Doctrine\Common\Cache\Cache $cacheImpl */ - public function setResultCacheImpl(Cache $cacheImpl) + public function setQueryCacheImpl(Cache $cacheImpl) { - $this->_attributes['resultCacheImpl'] = $cacheImpl; + $this->_attributes['queryCacheImpl'] = $cacheImpl; } /** - * Gets the cache driver implementation that is used for the query cache (SQL cache). + * Gets the cache driver implementation that is used for the hydration cache (SQL cache). * * @return \Doctrine\Common\Cache\Cache */ - public function getQueryCacheImpl() + public function getHydrationCacheImpl() { - return isset($this->_attributes['queryCacheImpl']) ? - $this->_attributes['queryCacheImpl'] : null; + return isset($this->_attributes['hydrationCacheImpl']) + ? $this->_attributes['hydrationCacheImpl'] + : null; } /** - * Sets the cache driver implementation that is used for the query cache (SQL cache). + * Sets the cache driver implementation that is used for the hydration cache (SQL cache). * * @param \Doctrine\Common\Cache\Cache $cacheImpl */ - public function setQueryCacheImpl(Cache $cacheImpl) + public function setHydrationCacheImpl(Cache $cacheImpl) { - $this->_attributes['queryCacheImpl'] = $cacheImpl; + $this->_attributes['hydrationCacheImpl'] = $cacheImpl; } /** @@ -517,4 +517,57 @@ class Configuration extends \Doctrine\DBAL\Configuration } return $this->_attributes['classMetadataFactoryName']; } -} \ No newline at end of file + + /** + * 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\ORM\EntityRepository + */ + public function setDefaultRepositoryClassName($className) + { + if ($className != "Doctrine\ORM\EntityRepository" && + !is_subclass_of($className, 'Doctrine\ORM\EntityRepository')){ + 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'; + } +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/EntityManager.php b/main/inc/lib/symfony/Doctrine/ORM/EntityManager.php index ad7ef20565..ab3e4c7ee9 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/EntityManager.php +++ b/main/inc/lib/symfony/Doctrine/ORM/EntityManager.php @@ -27,7 +27,8 @@ use Closure, Exception, Doctrine\ORM\Mapping\ClassMetadata, Doctrine\ORM\Mapping\ClassMetadataFactory, Doctrine\ORM\Query\ResultSetMapping, - Doctrine\ORM\Proxy\ProxyFactory; + Doctrine\ORM\Proxy\ProxyFactory, + Doctrine\ORM\Query\FilterCollection; /** * The EntityManager is the central access point to ORM functionality. @@ -110,6 +111,13 @@ class EntityManager implements ObjectManager */ 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. @@ -130,10 +138,12 @@ class EntityManager implements ObjectManager $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl()); $this->unitOfWork = new UnitOfWork($this); - $this->proxyFactory = new ProxyFactory($this, - $config->getProxyDir(), - $config->getProxyNamespace(), - $config->getAutoGenerateProxyClasses()); + $this->proxyFactory = new ProxyFactory( + $this, + $config->getProxyDir(), + $config->getProxyNamespace(), + $config->getAutoGenerateProxyClasses() + ); } /** @@ -175,6 +185,7 @@ class EntityManager implements ObjectManager if ($this->expressionBuilder === null) { $this->expressionBuilder = new Query\Expr; } + return $this->expressionBuilder; } @@ -199,6 +210,7 @@ class EntityManager implements ObjectManager * the transaction is rolled back, the EntityManager closed and the exception re-thrown. * * @param Closure $func The function to execute transactionally. + * @return mixed Returns the non-empty value returned from the closure or true instead */ public function transactional(Closure $func) { @@ -266,9 +278,11 @@ class EntityManager implements ObjectManager public function createQuery($dql = "") { $query = new Query($this); + if ( ! empty($dql)) { $query->setDql($dql); } + return $query; } @@ -295,6 +309,7 @@ class EntityManager implements ObjectManager $query = new NativeQuery($this); $query->setSql($sql); $query->setResultSetMapping($rsm); + return $query; } @@ -307,6 +322,7 @@ class EntityManager implements ObjectManager public function createNamedNativeQuery($name) { list($sql, $rsm) = $this->config->getNamedNativeQuery($name); + return $this->createNativeQuery($sql, $rsm); } @@ -325,13 +341,18 @@ class EntityManager implements ObjectManager * 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() + public function flush($entity = null) { $this->errorIfClosed(); - $this->unitOfWork->commit(); + + $this->unitOfWork->commit($entity); } /** @@ -355,27 +376,39 @@ class EntityManager implements ObjectManager * without actually loading it, if the entity is not yet loaded. * * @param string $entityName The name of the entity type. - * @param mixed $identifier The entity identifier. + * @param mixed $id The entity identifier. * @return object The entity reference. */ - public function getReference($entityName, $identifier) + 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($identifier, $class->rootEntityName)) { + if ($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) { return ($entity instanceof $class->name) ? $entity : null; } + if ($class->subClasses) { - $entity = $this->find($entityName, $identifier); - } else { - if ( ! is_array($identifier)) { - $identifier = array($class->identifier[0] => $identifier); - } - $entity = $this->proxyFactory->getProxy($class->name, $identifier); - $this->unitOfWork->registerManaged($entity, $identifier, array()); + 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; } @@ -406,6 +439,7 @@ class EntityManager implements ObjectManager if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) { return ($entity instanceof $class->name) ? $entity : null; } + if ( ! is_array($identifier)) { $identifier = array($class->identifier[0] => $identifier); } @@ -422,16 +456,11 @@ class EntityManager implements ObjectManager * Clears the EntityManager. All entities that are currently managed * by this EntityManager become detached. * - * @param string $entityName + * @param string $entityName if given, only entities of this type will get detached */ public function clear($entityName = null) { - if ($entityName === null) { - $this->unitOfWork->clear(); - } else { - //TODO - throw new ORMException("EntityManager#clear(\$entityName) not yet implemented."); - } + $this->unitOfWork->clear($entityName); } /** @@ -461,7 +490,9 @@ class EntityManager implements ObjectManager if ( ! is_object($entity)) { throw new \InvalidArgumentException(gettype($entity)); } + $this->errorIfClosed(); + $this->unitOfWork->persist($entity); } @@ -478,7 +509,9 @@ class EntityManager implements ObjectManager if ( ! is_object($entity)) { throw new \InvalidArgumentException(gettype($entity)); } + $this->errorIfClosed(); + $this->unitOfWork->remove($entity); } @@ -493,7 +526,9 @@ class EntityManager implements ObjectManager if ( ! is_object($entity)) { throw new \InvalidArgumentException(gettype($entity)); } + $this->errorIfClosed(); + $this->unitOfWork->refresh($entity); } @@ -511,6 +546,7 @@ class EntityManager implements ObjectManager if ( ! is_object($entity)) { throw new \InvalidArgumentException(gettype($entity)); } + $this->unitOfWork->detach($entity); } @@ -527,7 +563,9 @@ class EntityManager implements ObjectManager if ( ! is_object($entity)) { throw new \InvalidArgumentException(gettype($entity)); } + $this->errorIfClosed(); + return $this->unitOfWork->merge($entity); } @@ -567,19 +605,20 @@ class EntityManager implements ObjectManager public function getRepository($entityName) { $entityName = ltrim($entityName, '\\'); + if (isset($this->repositories[$entityName])) { return $this->repositories[$entityName]; } $metadata = $this->getClassMetadata($entityName); - $customRepositoryClassName = $metadata->customRepositoryClassName; + $repositoryClassName = $metadata->customRepositoryClassName; - if ($customRepositoryClassName !== null) { - $repository = new $customRepositoryClassName($this, $metadata); - } else { - $repository = new EntityRepository($this, $metadata); + if ($repositoryClassName === null) { + $repositoryClassName = $this->config->getDefaultRepositoryClassName(); } + $repository = new $repositoryClassName($this, $metadata); + $this->repositories[$entityName] = $repository; return $repository; @@ -593,9 +632,9 @@ class EntityManager implements ObjectManager */ public function contains($entity) { - return $this->unitOfWork->isScheduledForInsert($entity) || - $this->unitOfWork->isInIdentityMap($entity) && - ! $this->unitOfWork->isScheduledForDelete($entity); + return $this->unitOfWork->isScheduledForInsert($entity) + || $this->unitOfWork->isInIdentityMap($entity) + && ! $this->unitOfWork->isScheduledForDelete($entity); } /** @@ -678,29 +717,27 @@ class EntityManager implements ObjectManager { switch ($hydrationMode) { case Query::HYDRATE_OBJECT: - $hydrator = new Internal\Hydration\ObjectHydrator($this); - break; + return new Internal\Hydration\ObjectHydrator($this); + case Query::HYDRATE_ARRAY: - $hydrator = new Internal\Hydration\ArrayHydrator($this); - break; + return new Internal\Hydration\ArrayHydrator($this); + case Query::HYDRATE_SCALAR: - $hydrator = new Internal\Hydration\ScalarHydrator($this); - break; + return new Internal\Hydration\ScalarHydrator($this); + case Query::HYDRATE_SINGLE_SCALAR: - $hydrator = new Internal\Hydration\SingleScalarHydrator($this); - break; + return new Internal\Hydration\SingleScalarHydrator($this); + case Query::HYDRATE_SIMPLEOBJECT: - $hydrator = new Internal\Hydration\SimpleObjectHydrator($this); - break; + return new Internal\Hydration\SimpleObjectHydrator($this); + default: if ($class = $this->config->getCustomHydrationMode($hydrationMode)) { - $hydrator = new $class($this); - break; + return new $class($this); } - throw ORMException::invalidHydrationMode($hydrationMode); } - return $hydrator; + throw ORMException::invalidHydrationMode($hydrationMode); } /** @@ -714,11 +751,15 @@ class EntityManager implements ObjectManager } /** - * {@inheritDoc} + * 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($entity) + public function initializeObject($obj) { - $this->unitOfWork->initializeObject($entity); + $this->unitOfWork->initializeObject($obj); } /** @@ -732,20 +773,62 @@ class EntityManager implements ObjectManager */ public static function create($conn, Configuration $config, EventManager $eventManager = null) { - if (!$config->getMetadataDriverImpl()) { + if ( ! $config->getMetadataDriverImpl()) { throw ORMException::missingMappingDriverImpl(); } - if (is_array($conn)) { - $conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ?: new EventManager())); - } else if ($conn instanceof Connection) { - if ($eventManager !== null && $conn->getEventManager() !== $eventManager) { - throw ORMException::mismatchedEventManager(); - } - } else { - throw new \InvalidArgumentException("Invalid argument: " . $conn); + 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/main/inc/lib/symfony/Doctrine/ORM/EntityRepository.php b/main/inc/lib/symfony/Doctrine/ORM/EntityRepository.php index fd29e194c8..17cc298074 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/EntityRepository.php +++ b/main/inc/lib/symfony/Doctrine/ORM/EntityRepository.php @@ -107,42 +107,51 @@ class EntityRepository implements ObjectRepository */ public function find($id, $lockMode = LockMode::NONE, $lockVersion = null) { + if ( ! is_array($id)) { + $id = array($this->_class->identifier[0] => $id); + } + $sortedId = array(); + foreach ($this->_class->identifier as $identifier) { + if (!isset($id[$identifier])) { + throw ORMException::missingIdentifierField($this->_class->name, $identifier); + } + $sortedId[$identifier] = $id[$identifier]; + } + // Check identity map first - if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_class->rootEntityName)) { - if (!($entity instanceof $this->_class->name)) { + if ($entity = $this->_em->getUnitOfWork()->tryGetById($sortedId, $this->_class->rootEntityName)) { + if ( ! ($entity instanceof $this->_class->name)) { return null; } - if ($lockMode != LockMode::NONE) { + if ($lockMode !== LockMode::NONE) { $this->_em->lock($entity, $lockMode, $lockVersion); } return $entity; // Hit! } - if ( ! is_array($id) || count($id) <= 1) { - // @todo FIXME: Not correct. Relies on specific order. - $value = is_array($id) ? array_values($id) : array($id); - $id = array_combine($this->_class->identifier, $value); - } + switch ($lockMode) { + case LockMode::NONE: + return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId); - if ($lockMode == LockMode::NONE) { - return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id); - } else if ($lockMode == LockMode::OPTIMISTIC) { - if (!$this->_class->isVersioned) { - throw OptimisticLockException::notVersioned($this->_entityName); - } - $entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id); + case LockMode::OPTIMISTIC: + if ( ! $this->_class->isVersioned) { + throw OptimisticLockException::notVersioned($this->_entityName); + } - $this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion); + $entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId); - return $entity; - } else { - if (!$this->_em->getConnection()->isTransactionActive()) { - throw TransactionRequiredException::transactionRequired(); - } + $this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion); + + return $entity; + + default: + if ( ! $this->_em->getConnection()->isTransactionActive()) { + throw TransactionRequiredException::transactionRequired(); + } - return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id, null, null, array(), $lockMode); + return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId, null, null, array(), $lockMode); } } @@ -178,7 +187,7 @@ class EntityRepository implements ObjectRepository */ public function findOneBy(array $criteria) { - return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria); + return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria, null, null, array(), 0, 1); } /** @@ -191,31 +200,35 @@ class EntityRepository implements ObjectRepository */ public function __call($method, $arguments) { - if (substr($method, 0, 6) == 'findBy') { - $by = substr($method, 6, strlen($method)); - $method = 'findBy'; - } else if (substr($method, 0, 9) == 'findOneBy') { - $by = substr($method, 9, strlen($method)); - $method = 'findOneBy'; - } else { - throw new \BadMethodCallException( - "Undefined method '$method'. The method name must start with ". - "either findBy or findOneBy!" - ); + switch (true) { + case (substr($method, 0, 6) == 'findBy'): + $by = substr($method, 6, strlen($method)); + $method = 'findBy'; + break; + + case (substr($method, 0, 9) == 'findOneBy'): + $by = substr($method, 9, strlen($method)); + $method = 'findOneBy'; + break; + + default: + throw new \BadMethodCallException( + "Undefined method '$method'. The method name must start with ". + "either findBy or findOneBy!" + ); } - if ( !isset($arguments[0])) { - // we dont even want to allow null at this point, because we cannot (yet) transform it into IS NULL. - throw ORMException::findByRequiresParameter($method.$by); + 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)) { return $this->$method(array($fieldName => $arguments[0])); - } else { - throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by); } + + throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by); } /** @@ -226,6 +239,14 @@ class EntityRepository implements ObjectRepository return $this->_entityName; } + /** + * @return string + */ + public function getClassName() + { + return $this->getEntityName(); + } + /** * @return EntityManager */ diff --git a/main/inc/lib/symfony/Doctrine/ORM/Event/LifecycleEventArgs.php b/main/inc/lib/symfony/Doctrine/ORM/Event/LifecycleEventArgs.php index a5dd39cfd4..6740a3e12a 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Event/LifecycleEventArgs.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Event/LifecycleEventArgs.php @@ -19,42 +19,59 @@ namespace Doctrine\ORM\Event; +use Doctrine\Common\EventArgs; +use Doctrine\ORM\EntityManager; + /** * Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions * of entities. * - * @since 2.0 + * @link www.doctrine-project.org + * @since 2.0 * @author Roman Borschel * @author Benjamin Eberlei */ -class LifecycleEventArgs extends \Doctrine\Common\EventArgs +class LifecycleEventArgs extends EventArgs { /** - * @var EntityManager + * @var \Doctrine\ORM\EntityManager */ - private $_em; + private $em; /** * @var object */ - private $_entity; - - public function __construct($entity, $em) + private $entity; + + /** + * Constructor + * + * @param object $entity + * @param \Doctrine\ORM\EntityManager $em + */ + public function __construct($entity, EntityManager $em) { - $this->_entity = $entity; - $this->_em = $em; + $this->entity = $entity; + $this->em = $em; } - + + /** + * Retireve associated Entity. + * + * @return object + */ public function getEntity() { - return $this->_entity; + return $this->entity; } /** - * @return EntityManager + * Retrieve associated EntityManager. + * + * @return \Doctrine\ORM\EntityManager */ public function getEntityManager() { - return $this->_em; + return $this->em; } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php b/main/inc/lib/symfony/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php index f00520a208..901bf3a780 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php @@ -1,9 +1,25 @@ . + */ namespace Doctrine\ORM\Event; use Doctrine\Common\EventArgs; - use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\EntityManager; @@ -11,32 +27,36 @@ use Doctrine\ORM\EntityManager; * Class that holds event arguments for a loadMetadata event. * * @author Jonathan H. Wage - * @since 2.0 + * @since 2.0 */ class LoadClassMetadataEventArgs extends EventArgs { /** - * @var ClassMetadata + * @var \Doctrine\ORM\Mapping\ClassMetadata */ private $classMetadata; /** - * @var EntityManager + * @var \Doctrine\ORM\EntityManager */ private $em; /** - * @param ClassMetadataInfo $classMetadata - * @param EntityManager $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; + $this->em = $em; } /** - * @return ClassMetadataInfo + * Retrieve associated ClassMetadata. + * + * @return \Doctrine\ORM\Mapping\ClassMetadataInfo */ public function getClassMetadata() { @@ -44,7 +64,9 @@ class LoadClassMetadataEventArgs extends EventArgs } /** - * @return EntityManager + * Retrieve associated EntityManager. + * + * @return \Doctrine\ORM\EntityManager */ public function getEntityManager() { diff --git a/main/inc/lib/symfony/Doctrine/ORM/Event/OnClearEventArgs.php b/main/inc/lib/symfony/Doctrine/ORM/Event/OnClearEventArgs.php index ad89fbc90d..542ac45e3a 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Event/OnClearEventArgs.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Event/OnClearEventArgs.php @@ -15,7 +15,7 @@ * This software consists of voluntary contributions made by many individuals * and is licensed under the LGPL. For more information, see * . -*/ + */ namespace Doctrine\ORM\Event; @@ -23,9 +23,8 @@ 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.com + * @link www.doctrine-project.org * @since 2.0 - * @version $Revision$ * @author Roman Borschel * @author Benjamin Eberlei */ @@ -37,18 +36,49 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs private $em; /** + * @var string + */ + private $entityClass; + + /** + * Constructor. + * * @param \Doctrine\ORM\EntityManager $em + * @param string $entityClass Optional entity class */ - public function __construct($em) + public function __construct($em, $entityClass = null) { - $this->em = $em; + $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); + } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Event/OnFlushEventArgs.php b/main/inc/lib/symfony/Doctrine/ORM/Event/OnFlushEventArgs.php index 1b4cb9ba81..c4aeb2a164 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Event/OnFlushEventArgs.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Event/OnFlushEventArgs.php @@ -21,55 +21,63 @@ 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.com + * @link www.doctrine-project.org * @since 2.0 - * @version $Revision$ * @author Roman Borschel * @author Benjamin Eberlei */ class OnFlushEventArgs extends \Doctrine\Common\EventArgs { /** - * @var EntityManager + * @var Doctirne\ORM\EntityManager + */ + private $em; + + //private $entitiesToPersist = array(); + //private $entitiesToRemove = array(); + + /** + * Constructor. + * + * @param \Doctrine\ORM\EntityManager $em */ - private $_em; - - //private $_entitiesToPersist = array(); - //private $_entitiesToRemove = array(); - - public function __construct($em) + public function __construct(EntityManager $em) { - $this->_em = $em; + $this->em = $em; } /** - * @return EntityManager + * Retrieve associated EntityManager. + * + * @return \Doctrine\ORM\EntityManager */ public function getEntityManager() { - return $this->_em; + return $this->em; } - + /* public function addEntityToPersist($entity) { - + } - + public function addEntityToRemove($entity) { - + } - + public function addEntityToUpdate($entity) { - + } - + public function getEntitiesToPersist() { return $this->_entitiesToPersist; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Event/PostFlushEventArgs.php b/main/inc/lib/symfony/Doctrine/ORM/Event/PostFlushEventArgs.php new file mode 100644 index 0000000000..f45030de73 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Event/PostFlushEventArgs.php @@ -0,0 +1,61 @@ +. + */ + +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; + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Event/PreFlushEventArgs.php b/main/inc/lib/symfony/Doctrine/ORM/Event/PreFlushEventArgs.php new file mode 100644 index 0000000000..b86967a72f --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Event/PreFlushEventArgs.php @@ -0,0 +1,53 @@ +. +*/ + +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 + * @version $Revision$ + * @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/main/inc/lib/symfony/Doctrine/ORM/Event/PreUpdateEventArgs.php b/main/inc/lib/symfony/Doctrine/ORM/Event/PreUpdateEventArgs.php index c61e26d4cd..0bebba1c8b 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Event/PreUpdateEventArgs.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Event/PreUpdateEventArgs.php @@ -1,4 +1,23 @@ . + */ namespace Doctrine\ORM\Event; @@ -8,55 +27,63 @@ use Doctrine\Common\EventArgs, /** * Class that holds event arguments for a preInsert/preUpdate event. * + * @author Guilherme Blanco * @author Roman Borschel * @author Benjamin Eberlei - * @since 2.0 + * @since 2.0 */ class PreUpdateEventArgs extends LifecycleEventArgs { /** * @var array */ - private $_entityChangeSet; + private $entityChangeSet; /** + * Constructor. * * @param object $entity - * @param EntityManager $em + * @param \Doctrine\ORM\EntityManager $em * @param array $changeSet */ - public function __construct($entity, $em, array &$changeSet) + public function __construct($entity, EntityManager $em, array &$changeSet) { parent::__construct($entity, $em); - $this->_entityChangeSet = &$changeSet; + + $this->entityChangeSet = &$changeSet; } + /** + * Retrieve entity changeset. + * + * @return array + */ public function getEntityChangeSet() { - return $this->_entityChangeSet; + return $this->entityChangeSet; } /** - * Field has a changeset? + * Check if field has a changeset. * - * @return bool + * @return boolean */ public function hasChangedField($field) { - return isset($this->_entityChangeSet[$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); + $this->assertValidField($field); - return $this->_entityChangeSet[$field][0]; + return $this->entityChangeSet[$field][0]; } /** @@ -67,31 +94,37 @@ class PreUpdateEventArgs extends LifecycleEventArgs */ public function getNewValue($field) { - $this->_assertValidField($field); + $this->assertValidField($field); - return $this->_entityChangeSet[$field][1]; + 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->assertValidField($field); - $this->_entityChangeSet[$field][1] = $value; + $this->entityChangeSet[$field][1] = $value; } - private function _assertValidField($field) + /** + * Assert the field exists in changeset. + * + * @param string $field + */ + private function assertValidField($field) { - if (!isset($this->_entityChangeSet[$field])) { - throw new \InvalidArgumentException( - "Field '".$field."' is not a valid field of the entity ". - "'".get_class($this->getEntity())."' in PreInsertUpdateEventArgs." - ); + 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/main/inc/lib/symfony/Doctrine/ORM/Events.php b/main/inc/lib/symfony/Doctrine/ORM/Events.php index 8344b07c1d..45424e7c23 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Events.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Events.php @@ -35,55 +35,55 @@ final class Events /** * 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 + * 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 + * 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. - * + * 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. - * + * The postUpdate event occurs after the database update operations to + * entity data. + * * This is an entity lifecycle event. - * + * * @var string */ const postUpdate = 'postUpdate'; @@ -91,35 +91,53 @@ final class Events * 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. diff --git a/main/inc/lib/symfony/Doctrine/ORM/Id/AbstractIdGenerator.php b/main/inc/lib/symfony/Doctrine/ORM/Id/AbstractIdGenerator.php index 6772382898..d27c00b772 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Id/AbstractIdGenerator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Id/AbstractIdGenerator.php @@ -35,7 +35,7 @@ abstract class AbstractIdGenerator * 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. * diff --git a/main/inc/lib/symfony/Doctrine/ORM/Id/AssignedGenerator.php b/main/inc/lib/symfony/Doctrine/ORM/Id/AssignedGenerator.php index 05c3790afb..c9f9adad88 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Id/AssignedGenerator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Id/AssignedGenerator.php @@ -20,6 +20,7 @@ namespace Doctrine\ORM\Id; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\ORMException; /** @@ -42,46 +43,29 @@ class AssignedGenerator extends AbstractIdGenerator */ public function generate(EntityManager $em, $entity) { - $class = $em->getClassMetadata(get_class($entity)); + $class = $em->getClassMetadata(get_class($entity)); + $idFields = $class->getIdentifierFieldNames(); $identifier = array(); - if ($class->isIdentifierComposite) { - $idFields = $class->getIdentifierFieldNames(); - foreach ($idFields as $idField) { - $value = $class->reflFields[$idField]->getValue($entity); - if (isset($value)) { - 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. - $identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value)); - } else { - $identifier[$idField] = $value; - } - } else { - throw ORMException::entityMissingAssignedId($entity); - } - } - } else { - $idField = $class->identifier[0]; + + foreach ($idFields as $idField) { $value = $class->reflFields[$idField]->getValue($entity); - if (isset($value)) { - 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. - $identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value)); - } else { - $identifier[$idField] = $value; + + if ( ! isset($value)) { + throw ORMException::entityMissingAssignedIdForField($entity, $idField); + } + + if (isset($class->associationMappings[$idField])) { + if ( ! $em->getUnitOfWork()->isInIdentityMap($value)) { + throw ORMException::entityMissingForeignAssignedId($entity, $value); } - } else { - throw ORMException::entityMissingAssignedId($entity); + + // NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced. + $value = current($em->getUnitOfWork()->getEntityIdentifier($value)); } + + $identifier[$idField] = $value; } - + return $identifier; } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Id/IdentityGenerator.php b/main/inc/lib/symfony/Doctrine/ORM/Id/IdentityGenerator.php index 75da2733d4..d244871f2f 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Id/IdentityGenerator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Id/IdentityGenerator.php @@ -46,7 +46,7 @@ class IdentityGenerator extends AbstractIdGenerator */ public function generate(EntityManager $em, $entity) { - return $em->getConnection()->lastInsertId($this->_seqName); + return (int)$em->getConnection()->lastInsertId($this->_seqName); } /** diff --git a/main/inc/lib/symfony/Doctrine/ORM/Id/SequenceGenerator.php b/main/inc/lib/symfony/Doctrine/ORM/Id/SequenceGenerator.php index 50b8bb22d9..79240610e4 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Id/SequenceGenerator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Id/SequenceGenerator.php @@ -46,7 +46,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable $this->_sequenceName = $sequenceName; $this->_allocationSize = $allocationSize; } - + /** * Generates an ID for the given entity. * @@ -59,10 +59,12 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) { // Allocate new values $conn = $em->getConnection(); - $sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName); - $this->_nextValue = $conn->fetchColumn($sql); - $this->_maxValue = $this->_nextValue + $this->_allocationSize; + $sql = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName); + + $this->_nextValue = (int)$conn->fetchColumn($sql); + $this->_maxValue = $this->_nextValue + $this->_allocationSize; } + return $this->_nextValue++; } @@ -90,13 +92,14 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable { return serialize(array( 'allocationSize' => $this->_allocationSize, - 'sequenceName' => $this->_sequenceName + 'sequenceName' => $this->_sequenceName )); } public function unserialize($serialized) { $array = unserialize($serialized); + $this->_sequenceName = $array['sequenceName']; $this->_allocationSize = $array['allocationSize']; } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Id/TableGenerator.php b/main/inc/lib/symfony/Doctrine/ORM/Id/TableGenerator.php index 5c46f8b5c1..24b1d90e56 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Id/TableGenerator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Id/TableGenerator.php @@ -50,11 +50,12 @@ class TableGenerator extends AbstractIdGenerator if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) { // Allocate new values $conn = $em->getConnection(); - if ($conn->getTransactionNestingLevel() == 0) { + if ($conn->getTransactionNestingLevel() === 0) { // use select for update - $sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName); + $sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName); $currentLevel = $conn->fetchColumn($sql); + if ($currentLevel != null) { $this->_nextValue = $currentLevel; $this->_maxValue = $this->_nextValue + $this->_allocationSize; @@ -62,7 +63,7 @@ class TableGenerator extends AbstractIdGenerator $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 } @@ -74,6 +75,7 @@ class TableGenerator extends AbstractIdGenerator // or do we want to work with table locks exclusively? } } + return $this->_nextValue++; } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Internal/CommitOrderCalculator.php b/main/inc/lib/symfony/Doctrine/ORM/Internal/CommitOrderCalculator.php index 8997b1ea53..049cab060a 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Internal/CommitOrderCalculator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Internal/CommitOrderCalculator.php @@ -23,20 +23,21 @@ 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 + * @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. * @@ -47,10 +48,10 @@ class CommitOrderCalculator $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. * @@ -60,17 +61,16 @@ class CommitOrderCalculator { // Check whether we need to do anything. 0 or 1 node is easy. $nodeCount = count($this->_classes); - if ($nodeCount == 0) { - return array(); - } else if ($nodeCount == 1) { - return array_values($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) { @@ -100,17 +100,17 @@ class CommitOrderCalculator $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/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php index 272e4588ff..945288b768 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -22,15 +22,17 @@ namespace Doctrine\ORM\Internal\Hydration; use PDO, Doctrine\DBAL\Connection, Doctrine\DBAL\Types\Type, - Doctrine\ORM\EntityManager; + Doctrine\ORM\EntityManager, + 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 + * @since 2.0 + * @author Konsta Vesterinen + * @author Roman Borschel + * @author Guilherme Blanco */ abstract class AbstractHydrator { @@ -62,9 +64,9 @@ abstract class AbstractHydrator */ public function __construct(EntityManager $em) { - $this->_em = $em; + $this->_em = $em; $this->_platform = $em->getConnection()->getDatabasePlatform(); - $this->_uow = $em->getUnitOfWork(); + $this->_uow = $em->getUnitOfWork(); } /** @@ -72,14 +74,17 @@ abstract class AbstractHydrator * * @param object $stmt * @param object $resultSetMapping + * * @return IterableResult */ public function iterate($stmt, $resultSetMapping, array $hints = array()) { - $this->_stmt = $stmt; - $this->_rsm = $resultSetMapping; + $this->_stmt = $stmt; + $this->_rsm = $resultSetMapping; $this->_hints = $hints; - $this->_prepare(); + + $this->prepare(); + return new IterableResult($this); } @@ -92,12 +97,16 @@ abstract class AbstractHydrator */ public function hydrateAll($stmt, $resultSetMapping, array $hints = array()) { - $this->_stmt = $stmt; - $this->_rsm = $resultSetMapping; + $this->_stmt = $stmt; + $this->_rsm = $resultSetMapping; $this->_hints = $hints; - $this->_prepare(); - $result = $this->_hydrateAll(); - $this->_cleanup(); + + $this->prepare(); + + $result = $this->hydrateAllData(); + + $this->cleanup(); + return $result; } @@ -110,12 +119,17 @@ abstract class AbstractHydrator public function hydrateRow() { $row = $this->_stmt->fetch(PDO::FETCH_ASSOC); + if ( ! $row) { - $this->_cleanup(); + $this->cleanup(); + return false; } + $result = array(); - $this->_hydrateRow($row, $this->_cache, $result); + + $this->hydrateRowData($row, $this->_cache, $result); + return $result; } @@ -123,16 +137,17 @@ abstract class AbstractHydrator * Excutes one-time preparation tasks, once each time hydration is started * through {@link hydrateAll} or {@link iterate()}. */ - protected function _prepare() + 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() + protected function cleanup() { $this->_rsm = null; + $this->_stmt->closeCursor(); $this->_stmt = null; } @@ -146,23 +161,24 @@ abstract class AbstractHydrator * @param array $cache The cache to use. * @param mixed $result The result to fill. */ - protected function _hydrateRow(array $data, array &$cache, array &$result) + protected function hydrateRowData(array $data, array &$cache, array &$result) { - throw new HydrationException("_hydrateRow() not implemented by this hydrator."); + throw new HydrationException("hydrateRowData() not implemented by this hydrator."); } /** * Hydrates all rows from the current statement instance at once. */ - abstract protected function _hydrateAll(); + 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 class + * 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. + * 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 @@ -172,40 +188,54 @@ abstract class AbstractHydrator * @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) + 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])) { - if (isset($this->_rsm->scalarMappings[$key])) { - $cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key]; - $cache[$key]['isScalar'] = true; - } else if (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]; - } else if (!isset($this->_rsm->metaMappings[$key])) { - // 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; - } else { - // Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns). - $fieldName = $this->_rsm->metaMappings[$key]; - $cache[$key]['isMetaColumn'] = true; - $cache[$key]['fieldName'] = $fieldName; - $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; - $classMetadata = $this->_em->getClassMetadata($this->_rsm->aliasMap[$cache[$key]['dqlAlias']]); - $cache[$key]['isIdentifier'] = isset($this->_rsm->isIdentifierColumn[$cache[$key]['dqlAlias']][$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; } @@ -222,10 +252,11 @@ abstract class AbstractHydrator $nonemptyComponents[$dqlAlias] = true; } } + continue; } - - // in an inheritance hierachy the same field could be defined several times. + + // 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) { @@ -244,6 +275,7 @@ abstract class AbstractHydrator /** * 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 @@ -251,52 +283,77 @@ abstract class AbstractHydrator * * @param array $data * @param array $cache + * * @return array The processed row. */ - protected function _gatherScalarRowData(&$data, &$cache) + 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])) { - if (isset($this->_rsm->scalarMappings[$key])) { - $cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key]; - $cache[$key]['isScalar'] = true; - } else if (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]; - } else if (!isset($this->_rsm->metaMappings[$key])) { - // 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; - } else { - // 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]; + 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']; - if (isset($cache[$key]['isScalar'])) { - $rowData[$fieldName] = $value; - } else if (isset($cache[$key]['isMetaColumn'])) { - $rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $value; - } else { - $rowData[$cache[$key]['dqlAlias'] . '_' . $fieldName] = $cache[$key]['type'] - ->convertToPHPValue($value, $this->_platform); + 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; } - - protected function registerManaged($class, $entity, $data) + + /** + * 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(); @@ -314,6 +371,7 @@ abstract class AbstractHydrator $id = array($class->identifier[0] => $data[$class->identifier[0]]); } } + $this->_em->getUnitOfWork()->registerManaged($entity, $id, $data); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php index 4b1c21c6fb..9a8fcee83e 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php @@ -25,8 +25,9 @@ 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 - * @since 1.0 + * @author Guilherme Blanco */ class ArrayHydrator extends AbstractHydrator { @@ -38,45 +39,55 @@ class ArrayHydrator extends AbstractHydrator private $_idTemplate = array(); private $_resultCounter = 0; - /** @override */ - protected function _prepare() + /** + * {@inheritdoc} + */ + protected function prepare() { - $this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1; - $this->_identifierMap = array(); + $this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1; + $this->_identifierMap = array(); $this->_resultPointers = array(); - $this->_idTemplate = array(); - $this->_resultCounter = 0; + $this->_idTemplate = array(); + $this->_resultCounter = 0; + foreach ($this->_rsm->aliasMap as $dqlAlias => $className) { - $this->_identifierMap[$dqlAlias] = array(); + $this->_identifierMap[$dqlAlias] = array(); $this->_resultPointers[$dqlAlias] = array(); - $this->_idTemplate[$dqlAlias] = ''; + $this->_idTemplate[$dqlAlias] = ''; } } - /** @override */ - protected function _hydrateAll() + /** + * {@inheritdoc} + */ + protected function hydrateAllData() { $result = array(); - $cache = array(); + $cache = array(); + while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { - $this->_hydrateRow($data, $cache, $result); + $this->hydrateRowData($data, $cache, $result); } return $result; } - /** @override */ - protected function _hydrateRow(array $data, array &$cache, array &$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($data, $cache, $id, $nonemptyComponents); + $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; } @@ -90,7 +101,7 @@ class ArrayHydrator extends AbstractHydrator // It's a joined result $parent = $this->_rsm->parentAliasMap[$dqlAlias]; - $path = $parent . '.' . $dqlAlias; + $path = $parent . '.' . $dqlAlias; // missing parent data, skipping as RIGHT JOIN hydration is not supported. if ( ! isset($nonemptyComponents[$parent]) ) { @@ -109,39 +120,41 @@ class ArrayHydrator extends AbstractHydrator unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 continue; } - + $relationAlias = $this->_rsm->relationMap[$dqlAlias]; - $relation = $this->_getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias]; + $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; + + $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])) { - $field = $this->_rsm->indexByMap[$dqlAlias]; - $baseElement[$relationAlias][$element[$field]] = $element; + $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]); + + $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])) { @@ -157,43 +170,42 @@ class ArrayHydrator extends AbstractHydrator } 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(0 => null); + $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])) { - $field = $this->_rsm->indexByMap[$dqlAlias]; - if ($this->_rsm->isMixed) { - $result[] = array($element[$field] => $element); - ++$this->_resultCounter; - } else { - $result[$element[$field]] = $element; - } + $resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]]; + $result[$resultKey] = $element; } else { - if ($this->_rsm->isMixed) { - $result[] = array($element); - ++$this->_resultCounter; - } else { - $result[] = $element; - } + $resultKey = $this->_resultCounter; + $result[] = $element; + ++$this->_resultCounter; } - end($result); - $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result); + + $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey; } else { $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; + $resultKey = $index; /*if ($this->_rsm->isMixed) { $result[] =& $result[$index]; ++$this->_resultCounter; @@ -205,8 +217,17 @@ class ArrayHydrator extends AbstractHydrator // 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[$this->_resultCounter - 1][$name] = $value; + $result[$resultKey][$name] = $value; } } } @@ -224,28 +245,45 @@ class ArrayHydrator extends AbstractHydrator { if ($coll === null) { unset($this->_resultPointers[$dqlAlias]); // Ticket #1228 + return; } + if ($index !== false) { $this->_resultPointers[$dqlAlias] =& $coll[$index]; + + return; + } + + if ( ! $coll) { return; - } else { - if ($coll) { - if ($oneToOne) { - $this->_resultPointers[$dqlAlias] =& $coll; - } else { - end($coll); - $this->_resultPointers[$dqlAlias] =& $coll[key($coll)]; - } - } } + + if ($oneToOne) { + $this->_resultPointers[$dqlAlias] =& $coll; + + return; + } + + end($coll); + $this->_resultPointers[$dqlAlias] =& $coll[key($coll)]; + + return; } - - private function _getClassMetadata($className) + + /** + * 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]; } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/HydrationException.php b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/HydrationException.php index 886b42dec7..147f6acae8 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/HydrationException.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/HydrationException.php @@ -8,10 +8,19 @@ class HydrationException extends \Doctrine\ORM\ORMException { return new self("The result returned by the query was not unique."); } - + public static function parentObjectOfRelationNotFound($alias, $parentAlias) { return new self("The parent object of entity result with alias '$alias' was not found." . " The parent alias is '$parentAlias'."); } + + public static function emptyDiscriminatorValue($dqlAlias) + { + return new self("The DQL alias '" . $dqlAlias . "' contains an entity ". + "of an inheritance hierachy with an empty discriminator value. This means " . + "that the database contains inconsistent data with an empty " . + "discriminator value in a table row." + ); + } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php index e0edc3cedd..83b0954b7c 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php @@ -23,6 +23,8 @@ 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; @@ -30,8 +32,10 @@ use PDO, /** * The ObjectHydrator constructs an object graph out of an SQL result set. * + * @since 2.0 * @author Roman Borschel - * @since 2.0 + * @author Guilherme Blanco + * * @internal Highly performance-sensitive code. */ class ObjectHydrator extends AbstractHydrator @@ -54,51 +58,63 @@ class ObjectHydrator extends AbstractHydrator /** @override */ - protected function _prepare() + protected function prepare() { $this->_identifierMap = $this->_resultPointers = $this->_idTemplate = array(); + $this->_resultCounter = 0; - if (!isset($this->_hints['deferEagerLoad'])) { + + if ( ! isset($this->_hints['deferEagerLoad'])) { $this->_hints['deferEagerLoad'] = true; } foreach ($this->_rsm->aliasMap as $dqlAlias => $className) { $this->_identifierMap[$dqlAlias] = array(); - $this->_idTemplate[$dqlAlias] = ''; - $class = $this->_em->getClassMetadata($className); + $this->_idTemplate[$dqlAlias] = ''; if ( ! isset($this->_ce[$className])) { - $this->_ce[$className] = $class; + $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])) { - if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) { - throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]); - } + if ( ! isset($this->_rsm->relationMap[$dqlAlias])) { + continue; + } - $sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]]; - $sourceClass = $this->_getClassMetadata($sourceClassName); - $assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]]; + if ( ! isset($this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]])) { + throw HydrationException::parentObjectOfRelationNotFound($dqlAlias, $this->_rsm->parentAliasMap[$dqlAlias]); + } - $this->_hints['fetched'][$this->_rsm->parentAliasMap[$dqlAlias]][$assoc['fieldName']] = true; + $sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]]; + $sourceClass = $this->_getClassMetadata($sourceClassName); + $assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]]; - if ($assoc['type'] != ClassMetadata::MANY_TO_MANY) { - // Mark any non-collection opposite sides as fetched, too. - if ($assoc['mappedBy']) { - $this->_hints['fetched'][$dqlAlias][$assoc['mappedBy']] = true; - } else { - if ($assoc['inversedBy']) { - $inverseAssoc = $class->associationMappings[$assoc['inversedBy']]; - if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) { - $this->_hints['fetched'][$dqlAlias][$inverseAssoc['fieldName']] = true; - } - } - } + $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; } } } @@ -106,11 +122,12 @@ class ObjectHydrator extends AbstractHydrator /** * {@inheritdoc} */ - protected function _cleanup() + protected function cleanup() { $eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true; - parent::_cleanup(); + parent::cleanup(); + $this->_identifierMap = $this->_initializedCollections = $this->_existingCollections = @@ -124,13 +141,13 @@ class ObjectHydrator extends AbstractHydrator /** * {@inheritdoc} */ - protected function _hydrateAll() + protected function hydrateAllData() { $result = array(); - $cache = array(); + $cache = array(); while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { - $this->_hydrateRow($row, $cache, $result); + $this->hydrateRowData($row, $cache, $result); } // Take snapshots from all newly initialized collections @@ -145,35 +162,40 @@ class ObjectHydrator extends AbstractHydrator * Initializes a related collection. * * @param object $entity The entity to which the collection belongs. + * @param ClassMetadata $class * @param string $name 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); + $oid = spl_object_hash($entity); $relation = $class->associationMappings[$fieldName]; + $value = $class->reflFields[$fieldName]->getValue($entity); - $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 + $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()) { + } 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! @@ -193,18 +215,25 @@ class ObjectHydrator extends AbstractHydrator private function _getEntity(array $data, $dqlAlias) { $className = $this->_rsm->aliasMap[$dqlAlias]; + if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) { $discrColumn = $this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$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])) { - $class = $this->_ce[$className]; - $this->registerManaged($class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data); + $this->registerManaged($this->_ce[$className], $this->_hints[Query::HINT_REFRESH_ENTITY], $data); } $this->_hints['fetchAlias'] = $dqlAlias; + return $this->_uow->createEntity($className, $data, $this->_hints); } @@ -212,6 +241,7 @@ class ObjectHydrator extends AbstractHydrator { // TODO: Abstract this code and UnitOfWork::createEntity() equivalent? $class = $this->_ce[$className]; + /* @var $class ClassMetadata */ if ($class->isIdentifierComposite) { $idHash = ''; @@ -243,6 +273,7 @@ class ObjectHydrator extends AbstractHydrator if ( ! isset($this->_ce[$className])) { $this->_ce[$className] = $this->_em->getClassMetadata($className); } + return $this->_ce[$className]; } @@ -267,18 +298,20 @@ class ObjectHydrator extends AbstractHydrator * @param array $cache The cache to use. * @param array $result The result array to fill. */ - protected function _hydrateRow(array $data, array &$cache, array &$result) + 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($data, $cache, $id, $nonemptyComponents); + $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; } @@ -347,8 +380,7 @@ class ObjectHydrator extends AbstractHydrator $element = $this->_getEntity($data, $dqlAlias); if (isset($this->_rsm->indexByMap[$dqlAlias])) { - $field = $this->_rsm->indexByMap[$dqlAlias]; - $indexValue = $this->_ce[$entityName]->reflFields[$field]->getValue($element); + $indexValue = $row[$this->_rsm->indexByMap[$dqlAlias]]; $reflFieldValue->hydrateSet($indexValue, $element); $this->_identifierMap[$path][$id[$parentAlias]][$id[$dqlAlias]] = $indexValue; } else { @@ -380,6 +412,7 @@ class ObjectHydrator extends AbstractHydrator $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 @@ -412,14 +445,16 @@ class ObjectHydrator extends AbstractHydrator } 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(0 => null); + $result[] = array($entityKey => null); } else { $result[] = null; } + $resultKey = $this->_resultCounter; ++$this->_resultCounter; continue; } @@ -427,35 +462,31 @@ class ObjectHydrator extends AbstractHydrator // 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])) { - $field = $this->_rsm->indexByMap[$dqlAlias]; - $key = $this->_ce[$entityName]->reflFields[$field]->getValue($element); - if ($this->_rsm->isMixed) { - $element = array($key => $element); - $result[] = $element; - $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter; - ++$this->_resultCounter; - } else { - $result[$key] = $element; - $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $key; - } + $resultKey = $row[$this->_rsm->indexByMap[$dqlAlias]]; if (isset($this->_hints['collection'])) { - $this->_hints['collection']->hydrateSet($key, $element); + $this->_hints['collection']->hydrateSet($resultKey, $element); } + + $result[$resultKey] = $element; } else { - if ($this->_rsm->isMixed) { - $element = array(0 => $element); - } - $result[] = $element; - $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter; + $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; @@ -463,6 +494,7 @@ class ObjectHydrator extends AbstractHydrator // 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; @@ -473,8 +505,16 @@ class ObjectHydrator extends AbstractHydrator // 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[$this->_resultCounter - 1][$name] = $value; + $result[$resultKey][$name] = $value; } } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ScalarHydrator.php b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ScalarHydrator.php index f153073107..d02651b29a 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ScalarHydrator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/ScalarHydrator.php @@ -26,25 +26,32 @@ use Doctrine\DBAL\Connection; * 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 - * @since 2.0 + * @author Guilherme Blanco */ class ScalarHydrator extends AbstractHydrator { - /** @override */ - protected function _hydrateAll() + /** + * {@inheritdoc} + */ + protected function hydrateAllData() { $result = array(); - $cache = array(); + $cache = array(); + while ($data = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) { - $result[] = $this->_gatherScalarRowData($data, $cache); + $this->hydrateRowData($data, $cache, $result); } + return $result; } - /** @override */ - protected function _hydrateRow(array $data, array &$cache, array &$result) + /** + * {@inheritdoc} + */ + protected function hydrateRowData(array $data, array &$cache, array &$result) { - $result[] = $this->_gatherScalarRowData($data, $cache); + $result[] = $this->gatherScalarRowData($data, $cache); } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php index 34d8e31b14..09c2c7f3db 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php @@ -17,13 +17,14 @@ * . */ - namespace Doctrine\ORM\Internal\Hydration; -use \PDO; -use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\DBAL\Types\Type; -use Doctrine\ORM\Query; +use \PDO, + Doctrine\DBAL\Types\Type, + Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\Event\LifecycleEventArgs, + Doctrine\ORM\Events, + Doctrine\ORM\Query; class SimpleObjectHydrator extends AbstractHydrator { @@ -32,15 +33,21 @@ class SimpleObjectHydrator extends AbstractHydrator */ private $class; + /** + * @var array + */ private $declaringClasses = array(); - protected function _hydrateAll() + /** + * {@inheritdoc} + */ + protected function hydrateAllData() { $result = array(); $cache = array(); while ($row = $this->_stmt->fetch(PDO::FETCH_ASSOC)) { - $this->_hydrateRow($row, $cache, $result); + $this->hydrateRowData($row, $cache, $result); } $this->_em->getUnitOfWork()->triggerEagerLoads(); @@ -48,77 +55,71 @@ class SimpleObjectHydrator extends AbstractHydrator return $result; } - protected function _prepare() + /** + * {@inheritdoc} + */ + protected function prepare() { - if (count($this->_rsm->aliasMap) == 1) { - $this->class = $this->_em->getClassMetadata(reset($this->_rsm->aliasMap)); - if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { - foreach ($this->_rsm->declaringClasses AS $column => $class) { - $this->declaringClasses[$column] = $this->_em->getClassMetadata($class); - } - } - } else { - throw new \RuntimeException("Cannot use SimpleObjectHydrator with a ResultSetMapping not containing exactly one object result."); + 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); + } } - protected function _hydrateRow(array $sqlResult, array &$cache, array &$result) + /** + * {@inheritdoc} + */ + protected function hydrateRowData(array $sqlResult, array &$cache, array &$result) { - $data = array(); - if ($this->class->inheritanceType == ClassMetadata::INHERITANCE_TYPE_NONE) { - foreach ($sqlResult as $column => $value) { - - if (!isset($cache[$column])) { - if (isset($this->_rsm->fieldMappings[$column])) { - $cache[$column]['name'] = $this->_rsm->fieldMappings[$column]; - $cache[$column]['field'] = true; - } else { - $cache[$column]['name'] = $this->_rsm->metaMappings[$column]; - } - } + $entityName = $this->class->name; + $data = array(); - if (isset($cache[$column]['field'])) { - $value = Type::getType($this->class->fieldMappings[$cache[$column]['name']]['type']) - ->convertToPHPValue($value, $this->_platform); - } - $data[$cache[$column]['name']] = $value; - } - $entityName = $this->class->name; - } else { + // 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 ($sqlResult[$discrColumnName] === '') { + throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap)); + } + $entityName = $this->class->discriminatorMap[$sqlResult[$discrColumnName]]; + unset($sqlResult[$discrColumnName]); - foreach ($sqlResult as $column => $value) { - if (!isset($cache[$column])) { - if (isset($this->_rsm->fieldMappings[$column])) { - $field = $this->_rsm->fieldMappings[$column]; - $class = $this->declaringClasses[$column]; - if ($class->name == $entityName || is_subclass_of($entityName, $class->name)) { - $cache[$column]['name'] = $field; - $cache[$column]['class'] = $class; - } - } else if (isset($this->_rsm->relationMap[$column])) { - if ($this->_rsm->relationMap[$column] == $entityName || is_subclass_of($entityName, $this->_rsm->relationMap[$column])) { - $cache[$column]['name'] = $field; - } - } else { - $cache[$column]['name'] = $this->_rsm->metaMappings[$column]; - } - } + } - if (isset($cache[$column]['class'])) { - $value = Type::getType($cache[$column]['class']->fieldMappings[$cache[$column]['name']]['type']) - ->convertToPHPValue($value, $this->_platform); + foreach ($sqlResult as $column => $value) { + // Hydrate column information if not yet present + if ( ! isset($cache[$column])) { + if (($info = $this->hydrateColumnInfo($entityName, $column)) === null) { + continue; } - // the second and part is to prevent overwrites in case of multiple - // inheritance classes using the same property name (See AbstractHydrator) - if (isset($cache[$column]) && (!isset($data[$cache[$column]['name']]) || $value !== null)) { - $data[$cache[$column]['name']] = $value; - } + $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; } } @@ -126,6 +127,57 @@ class SimpleObjectHydrator extends AbstractHydrator $this->registerManaged($this->class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data); } - $result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints); + $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] + ); + } } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php index 4668155213..a5dabc60ce 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php @@ -19,31 +19,38 @@ namespace Doctrine\ORM\Internal\Hydration; -use Doctrine\DBAL\Connection; +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 - * @since 2.0 + * @author Guilherme Blanco */ class SingleScalarHydrator extends AbstractHydrator { - /** @override */ - protected function _hydrateAll() + /** + * {@inheritdoc} + */ + protected function hydrateAllData() { - $cache = array(); - $result = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC); - $num = count($result); + $data = $this->_stmt->fetchAll(\PDO::FETCH_ASSOC); + $numRows = count($data); - if ($num == 0) { - throw new \Doctrine\ORM\NoResultException; - } else if ($num > 1 || count($result[key($result)]) > 1) { - throw new \Doctrine\ORM\NonUniqueResultException; + if ($numRows === 0) { + throw new NoResultException(); } - - $result = $this->_gatherScalarRowData($result[key($result)], $cache); - + + if ($numRows > 1 || count($data[key($data)]) > 1) { + throw new NonUniqueResultException(); + } + + $cache = array(); + $result = $this->gatherScalarRowData($data[key($data)], $cache); + return array_shift($result); } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Annotation.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Annotation.php new file mode 100644 index 0000000000..dd8f4efeec --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Annotation.php @@ -0,0 +1,24 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +interface Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/AssociationBuilder.php new file mode 100644 index 0000000000..843e2ce5d3 --- /dev/null +++ b/main/inc/lib/symfony/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; + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php new file mode 100644 index 0000000000..fb1f1d5e52 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/FieldBuilder.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/FieldBuilder.php new file mode 100644 index 0000000000..3f4a5bbafb --- /dev/null +++ b/main/inc/lib/symfony/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; + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/ManyToManyAssociationBuilder.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/ManyToManyAssociationBuilder.php new file mode 100644 index 0000000000..c1dd1e568a --- /dev/null +++ b/main/inc/lib/symfony/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; + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/OneToManyAssociationBuilder.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Builder/OneToManyAssociationBuilder.php new file mode 100644 index 0000000000..be55c2d6b7 --- /dev/null +++ b/main/inc/lib/symfony/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; + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php new file mode 100644 index 0000000000..a9cc3725a6 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadata.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadata.php index bbabc2fe00..70b8f9e40b 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadata.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadata.php @@ -24,7 +24,7 @@ use ReflectionClass, ReflectionProperty; /** * 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: @@ -41,306 +41,4 @@ use ReflectionClass, ReflectionProperty; */ class ClassMetadata extends ClassMetadataInfo { - /** - * 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. - */ - public function __construct($entityName) - { - $this->reflClass = new ReflectionClass($entityName); - $this->namespace = $this->reflClass->getNamespaceName(); - $this->table['name'] = $this->reflClass->getShortName(); - parent::__construct($this->reflClass->getName()); // do not use $entityName, possible case-problems - } - - /** - * 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]]; - } - - /** - * Validates & completes the given field mapping. - * - * @param array $mapping The field mapping to validated & complete. - * @return array The validated and completed field mapping. - * - * @throws MappingException - */ - protected function _validateAndCompleteFieldMapping(array &$mapping) - { - parent::_validateAndCompleteFieldMapping($mapping); - - // Store ReflectionProperty of mapped field - $refProp = $this->reflClass->getProperty($mapping['fieldName']); - $refProp->setAccessible(true); - $this->reflFields[$mapping['fieldName']] = $refProp; - } - - /** - * 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; - } else { - $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); - } - - /** - * Stores the association mapping. - * - * @param AssociationMapping $assocMapping - */ - protected function _storeAssociationMapping(array $assocMapping) - { - parent::_storeAssociationMapping($assocMapping); - - // Store ReflectionProperty of mapped field - $sourceFieldName = $assocMapping['fieldName']; - - $refProp = $this->reflClass->getProperty($sourceFieldName); - $refProp->setAccessible(true); - $this->reflFields[$sourceFieldName] = $refProp; - } - - /** - * 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->isReadOnly) { - $serialized[] = 'isReadOnly'; - } - - return $serialized; - } - - /** - * Restores some state that can not be serialized/unserialized. - * - * @return void - */ - public function __wakeup() - { - // Restore ReflectionClass and properties - $this->reflClass = new ReflectionClass($this->name); - - foreach ($this->fieldMappings as $field => $mapping) { - if (isset($mapping['declared'])) { - $reflField = new ReflectionProperty($mapping['declared'], $field); - } else { - $reflField = $this->reflClass->getProperty($field); - } - $reflField->setAccessible(true); - $this->reflFields[$field] = $reflField; - } - - foreach ($this->associationMappings as $field => $mapping) { - if (isset($mapping['declared'])) { - $reflField = new ReflectionProperty($mapping['declared'], $field); - } else { - $reflField = $this->reflClass->getProperty($field); - } - - $reflField->setAccessible(true); - $this->reflFields[$field] = $reflField; - } - } - - /** - * 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; - } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadataFactory.php index ae7a612b18..e2a562168f 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -24,6 +24,8 @@ use ReflectionException, Doctrine\ORM\EntityManager, Doctrine\DBAL\Platforms, Doctrine\ORM\Events, + Doctrine\Common\Persistence\Mapping\RuntimeReflectionService, + Doctrine\Common\Persistence\Mapping\ReflectionService, Doctrine\Common\Persistence\Mapping\ClassMetadataFactory as ClassMetadataFactoryInterface; /** @@ -50,7 +52,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface private $targetPlatform; /** - * @var Driver\Driver + * @var \Doctrine\ORM\Mapping\Driver\Driver */ private $driver; @@ -74,6 +76,11 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface */ private $initialized = false; + /** + * @var ReflectionService + */ + private $reflectionService; + /** * @param EntityManager $$em */ @@ -165,6 +172,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface if ($this->cacheDriver) { if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) { + $this->wakeupReflection($cached, $this->getReflectionService()); $this->loadedMetadata[$realClassName] = $cached; } else { foreach ($this->loadMetadata($realClassName) as $loadedClassName) { @@ -220,7 +228,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface { // Collect parent classes, ignoring transient (not-mapped) classes. $parentClasses = array(); - foreach (array_reverse(class_parents($name)) as $parentClass) { + foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) { if ( ! $this->driver->isTransient($parentClass)) { $parentClasses[] = $parentClass; } @@ -261,6 +269,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface } $class = $this->newClassMetadataInstance($className); + $this->initializeReflection($class, $this->getReflectionService()); if ($parent) { $class->setInheritanceType($parent->inheritanceType); @@ -274,6 +283,9 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface $class->setDiscriminatorMap($parent->discriminatorMap); $class->setLifecycleCallbacks($parent->lifecycleCallbacks); $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); + if ($parent->isMappedSuperclass) { + $class->setCustomRepositoryClass($parent->customRepositoryClassName); + } } // Invoke driver @@ -310,12 +322,17 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface $class->containsForeignIdentifier = true; } + if ($parent && !empty ($parent->namedQueries)) { + $this->addInheritedNamedQueries($class, $parent); + } + $class->setParentClasses($visited); if ($this->evm->hasListeners(Events::loadClassMetadata)) { $eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class, $this->em); $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); } + $this->wakeupReflection($class, $this->getReflectionService()); $this->validateRuntimeMetadata($class, $parent); @@ -342,11 +359,15 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface */ protected function validateRuntimeMetadata($class, $parent) { - // Verify & complete identifier mapping - if ( ! $class->identifier && ! $class->isMappedSuperclass) { - throw MappingException::identifierRequired($class->name); + 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) { @@ -426,6 +447,25 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface } } + /** + * 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'] + )); + } + } + } + /** * Completes the ID generator mapping. If "auto" is specified we choose the generator * most appropriate for the targeted database platform. @@ -452,7 +492,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface // __seq in PostgreSQL for SERIAL columns. // Not pretty but necessary and the simplest solution that currently works. $seqName = $this->targetPlatform instanceof Platforms\PostgreSQLPlatform ? - $class->table['name'] . '_' . $class->columnNames[$class->identifier[0]] . '_seq' : + $class->getTableName() . '_' . $class->columnNames[$class->identifier[0]] . '_seq' : null; $class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($seqName)); break; @@ -484,20 +524,70 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface } /** - * {@inheritDoc} + * Check if this class is mapped by this EntityManager + 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->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName; } - + return $this->driver->isTransient($class); } + + /** + * Get reflectionService. + * + * @return \Doctrine\Common\Persistence\Mapping\ReflectionService + */ + public function getReflectionService() + { + if ($this->reflectionService === null) { + $this->reflectionService = new RuntimeReflectionService(); + } + return $this->reflectionService; + } + + /** + * Set reflectionService. + * + * @param reflectionService the value to set. + */ + public function setReflectionService(ReflectionService $reflectionService) + { + $this->reflectionService = $reflectionService; + } + + /** + * Wakeup reflection after ClassMetadata gets unserialized from cache. + * + * @param ClassMetadataInfo $class + * @param ReflectionService $reflService + * @return void + */ + protected function wakeupReflection(ClassMetadataInfo $class, ReflectionService $reflService) + { + $class->wakeupReflection($reflService); + } + + /** + * Initialize Reflection after ClassMetadata was constructed. + * + * @param ClassMetadataInfo $class + * @param ReflectionService $reflService + * @return void + */ + protected function initializeReflection(ClassMetadataInfo $class, ReflectionService $reflService) + { + $class->initializeReflection($reflService); + } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadataInfo.php index ddb2b258d9..31e2b754d3 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -19,8 +19,9 @@ namespace Doctrine\ORM\Mapping; -use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\DBAL\Types\Type; use ReflectionClass; +use Doctrine\Common\Persistence\Mapping\ClassMetadata; /** * A ClassMetadata instance holds all the object-relational mapping metadata @@ -136,10 +137,6 @@ class ClassMetadataInfo implements ClassMetadata * Identifies a many-to-one association. */ const MANY_TO_ONE = 2; - /** - * Combined bitmask for to-one (single-valued) associations. - */ - const TO_ONE = 3; /** * Identifies a one-to-many association. */ @@ -148,6 +145,10 @@ class ClassMetadataInfo implements ClassMetadata * 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. */ @@ -318,7 +319,7 @@ class ClassMetadataInfo implements ClassMetadata public $discriminatorMap = array(); /** - * READ-ONLY: The definition of the descriminator column used in JOINED and SINGLE_TABLE + * READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE * inheritance mappings. * * @var array @@ -494,6 +495,20 @@ class ClassMetadataInfo implements ClassMetadata */ public $isReadOnly = false; + /** + * 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. @@ -506,6 +521,308 @@ class ClassMetadataInfo implements ClassMetadata $this->rootEntityName = $entityName; } + /** + * 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->isReadOnly) { + $serialized[] = 'isReadOnly'; + } + + 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 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 string $entityName The name of the entity class the new instance is used for. + */ + public function initializeReflection($reflService) + { + $this->reflClass = $reflService->getClass($this->name); + $this->namespace = $reflService->getClassNamespace($this->name); + $this->table['name'] = $reflService->getClassShortName($this->name); + + if ($this->reflClass) { + $this->name = $this->rootEntityName = $this->reflClass->getName(); + } + } + + /** + * Validate Identifier + * + * @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. + * + * @return void + */ + public function validateAssocations() + { + foreach ($this->associationMappings as $field => $mapping) { + if ( ! \Doctrine\Common\ClassLoader::classExists($mapping['targetEntity']) ) { + throw MappingException::invalidTargetEntityClass($mapping['targetEntity'], $this->name, $mapping['fieldName']); + } + } + } + + /** + * Validate lifecycle callbacks + * + * @param ReflectionService $reflService + * @return void + */ + public function validateLifecycleCallbacks($reflService) + { + foreach ($this->lifecycleCallbacks as $event => $callbacks) { + foreach ($callbacks as $callbackFuncName) { + if ( ! $reflService->hasPublicMethod($this->name, $callbackFuncName)) { + throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callbackFuncName); + } + } + } + } + /** * Gets the ReflectionClass instance of the mapped class. * @@ -513,9 +830,6 @@ class ClassMetadataInfo implements ClassMetadata */ public function getReflectionClass() { - if ( ! $this->reflClass) { - $this->reflClass = new ReflectionClass($this->name); - } return $this->reflClass; } @@ -685,7 +999,7 @@ class ClassMetadataInfo implements ClassMetadata if ( ! isset($this->namedQueries[$queryName])) { throw MappingException::queryNotFound($this->name, $queryName); } - return $this->namedQueries[$queryName]; + return $this->namedQueries[$queryName]['dql']; } /** @@ -746,6 +1060,14 @@ class ClassMetadataInfo implements ClassMetadata $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; + } } /** @@ -783,6 +1105,13 @@ class ClassMetadataInfo implements ClassMetadata $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) { @@ -837,15 +1166,11 @@ class ClassMetadataInfo implements ClassMetadata // Cascades $cascades = isset($mapping['cascade']) ? array_map('strtolower', $mapping['cascade']) : array(); + if (in_array('all', $cascades)) { - $cascades = array( - 'remove', - 'persist', - 'refresh', - 'merge', - 'detach' - ); + $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach'); } + $mapping['cascade'] = $cascades; $mapping['isCascadeRemove'] = in_array('remove', $cascades); $mapping['isCascadePersist'] = in_array('persist', $cascades); @@ -882,9 +1207,11 @@ class ClassMetadataInfo implements ClassMetadata $uniqueContraintColumns = array(); foreach ($mapping['joinColumns'] as $key => &$joinColumn) { - if ($mapping['type'] === self::ONE_TO_ONE) { + if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) { if (count($mapping['joinColumns']) == 1) { - $joinColumn['unique'] = true; + if (! isset($mapping['id']) || ! $mapping['id']) { + $joinColumn['unique'] = true; + } } else { $uniqueContraintColumns[] = $joinColumn['name']; } @@ -1011,6 +1338,8 @@ class ClassMetadataInfo implements ClassMetadata } } + $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'])); @@ -1274,7 +1603,7 @@ class ClassMetadataInfo implements ClassMetadata public function getTemporaryIdTableName() { // replace dots with underscores because PostgreSQL creates temporary tables in a special schema - return str_replace('.', '_', $this->table['name'] . '_id_tmp'); + return str_replace('.', '_', $this->getTableName() . '_id_tmp'); } /** @@ -1367,15 +1696,17 @@ class ClassMetadataInfo implements ClassMetadata { if (isset($table['name'])) { if ($table['name'][0] == '`') { - $this->table['name'] = trim($table['name'], '`'); + $this->table['name'] = str_replace("`", "", $table['name']); $this->table['quoted'] = true; } else { $this->table['name'] = $table['name']; } } + if (isset($table['indexes'])) { $this->table['indexes'] = $table['indexes']; } + if (isset($table['uniqueConstraints'])) { $this->table['uniqueConstraints'] = $table['uniqueConstraints']; } @@ -1450,8 +1781,15 @@ class ClassMetadataInfo implements ClassMetadata if (isset($this->namedQueries[$queryMapping['name']])) { throw MappingException::duplicateQueryMapping($this->name, $queryMapping['name']); } - $query = str_replace('__CLASS__', $this->name, $queryMapping['query']); - $this->namedQueries[$queryMapping['name']] = $query; + + $name = $queryMapping['name']; + $query = $queryMapping['query']; + $dql = str_replace('__CLASS__', $this->name, $query); + $this->namedQueries[$name] = array( + 'name' => $name, + 'query' => $query, + 'dql' => $dql + ); } /** @@ -1506,14 +1844,16 @@ class ClassMetadataInfo implements ClassMetadata /** * Stores the association mapping. * - * @param AssociationMapping $assocMapping + * @param array $assocMapping */ 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; } @@ -1524,6 +1864,10 @@ class ClassMetadataInfo implements ClassMetadata */ public function setCustomRepositoryClass($repositoryClassName) { + if ($repositoryClassName !== null && strpos($repositoryClassName, '\\') === false + && strlen($this->namespace) > 0) { + $repositoryClassName = $this->namespace . '\\' . $repositoryClassName; + } $this->customRepositoryClassName = $repositoryClassName; } @@ -1566,9 +1910,6 @@ class ClassMetadataInfo implements ClassMetadata /** * Adds a lifecycle callback for entities of this class. * - * Note: If the same callback is registered more than once, the old one - * will be overridden. - * * @param string $callback * @param string $event */ @@ -1627,22 +1968,33 @@ class ClassMetadataInfo implements ClassMetadata public function setDiscriminatorMap(array $map) { foreach ($map as $value => $className) { - if (strlen($this->namespace) > 0 && strpos($className, '\\') === false) { - $className = $this->namespace . '\\' . $className; - } + $this->addDiscriminatorMapClass($value, $className); + } + } - $className = ltrim($className, '\\'); - $this->discriminatorMap[$value] = $className; + /** + * Add one entry of the discriminator map with a new class and corresponding name. + * + * @param string $name + * @param string $className + */ + public function addDiscriminatorMapClass($name, $className) + { + if (strlen($this->namespace) > 0 && strpos($className, '\\') === false) { + $className = $this->namespace . '\\' . $className; + } - if ($this->name == $className) { - $this->discriminatorValue = $value; - } else { - if ( ! class_exists($className)) { - throw MappingException::invalidClassInDiscriminatorMap($className, $this->name); - } - if (is_subclass_of($className, $this->name)) { - $this->subClasses[] = $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; } } } @@ -1804,7 +2156,7 @@ class ClassMetadataInfo implements ClassMetadata $this->versionField = $mapping['fieldName']; if ( ! isset($mapping['default'])) { - if ($mapping['type'] == 'integer') { + if (in_array($mapping['type'], array('integer', 'bigint', 'smallint'))) { $mapping['default'] = 1; } else if ($mapping['type'] == 'datetime') { $mapping['default'] = 'CURRENT_TIMESTAMP'; @@ -1877,9 +2229,10 @@ class ClassMetadataInfo implements ClassMetadata */ public function getAssociationTargetClass($assocName) { - if (!isset($this->associationMappings[$assocName])) { + if ( ! isset($this->associationMappings[$assocName])) { throw new \InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association."); } + return $this->associationMappings[$assocName]['targetEntity']; } @@ -1939,9 +2292,9 @@ class ClassMetadataInfo implements ClassMetadata */ public function getQuotedColumnName($field, $platform) { - return isset($this->fieldMappings[$field]['quoted']) ? - $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) : - $this->fieldMappings[$field]['columnName']; + return isset($this->fieldMappings[$field]['quoted']) + ? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) + : $this->fieldMappings[$field]['columnName']; } /** @@ -1953,9 +2306,7 @@ class ClassMetadataInfo implements ClassMetadata */ public function getQuotedTableName($platform) { - return isset($this->table['quoted']) ? - $platform->quoteIdentifier($this->table['name']) : - $this->table['name']; + return isset($this->table['quoted']) ? $platform->quoteIdentifier($this->table['name']) : $this->table['name']; } /** @@ -1966,16 +2317,22 @@ class ClassMetadataInfo implements ClassMetadata */ public function getQuotedJoinTableName(array $assoc, $platform) { - return isset($assoc['joinTable']['quoted']) - ? $platform->quoteIdentifier($assoc['joinTable']['name']) - : $assoc['joinTable']['name']; + return isset($assoc['joinTable']['quoted']) ? $platform->quoteIdentifier($assoc['joinTable']['name']) : $assoc['joinTable']['name']; } + /** + * @param string $fieldName + * @return bool + */ public function isAssociationInverseSide($fieldName) { - return isset($this->associationMappings[$fieldName]) && !$this->associationMappings[$fieldName]['isOwningSide']; + return isset($this->associationMappings[$fieldName]) && ! $this->associationMappings[$fieldName]['isOwningSide']; } + /** + * @param string $fieldName + * @return string + */ public function getAssociationMappedByTargetField($fieldName) { return $this->associationMappings[$fieldName]['mappedBy']; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Column.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Column.php new file mode 100644 index 0000000000..5f7dd7f644 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Column.php @@ -0,0 +1,46 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +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/main/inc/lib/symfony/Doctrine/ORM/Mapping/DiscriminatorColumn.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/DiscriminatorColumn.php new file mode 100644 index 0000000000..aec011538b --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/DiscriminatorColumn.php @@ -0,0 +1,36 @@ +. + */ + +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) +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/DiscriminatorMap.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/DiscriminatorMap.php new file mode 100644 index 0000000000..8505cf92f2 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/AbstractFileDriver.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/AbstractFileDriver.php index 457b7cda7c..6953bf2d14 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/AbstractFileDriver.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/AbstractFileDriver.php @@ -25,7 +25,7 @@ use Doctrine\ORM\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 @@ -56,16 +56,16 @@ abstract class AbstractFileDriver implements Driver */ 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. - */ - public function __construct($paths) - { + /** + * 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. + */ + public function __construct($paths) + { $this->addPaths((array) $paths); - } + } /** * Append lookup paths to metadata driver. @@ -117,7 +117,10 @@ abstract class AbstractFileDriver implements Driver public function getElement($className) { $result = $this->_loadMappingFile($this->_findMappingFile($className)); - + + if(!isset($result[$className])){ + throw MappingException::invalidMappingFile($className, str_replace('\\', '.', $className) . $this->_fileExtension); + } return $result[$className]; } @@ -145,7 +148,7 @@ abstract class AbstractFileDriver implements Driver /** * 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() @@ -157,23 +160,23 @@ abstract class AbstractFileDriver implements Driver if ( ! is_dir($path)) { throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); } - + $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::LEAVES_ONLY ); - + foreach ($iterator as $file) { if (($fileName = $file->getBasename($this->_fileExtension)) == $file->getBasename()) { continue; } - + // NOTE: All files found here means classes are not transient! $classes[] = str_replace('.', '\\', $fileName); } } } - + return $classes; } @@ -188,7 +191,7 @@ abstract class AbstractFileDriver implements Driver protected function _findMappingFile($className) { $fileName = str_replace('\\', '.', $className) . $this->_fileExtension; - + // Check whether file exists foreach ((array) $this->_paths as $path) { if (file_exists($path . DIRECTORY_SEPARATOR . $fileName)) { @@ -202,7 +205,7 @@ abstract class AbstractFileDriver implements Driver /** * Loads a mapping file with the given name and returns a map * from class/entity names to their corresponding elements. - * + * * @param string $file The mapping file to load. * @return array */ diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index 23cdb4b91c..ace39c4615 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -97,6 +97,16 @@ class AnnotationDriver implements Driver 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 * @@ -124,11 +134,15 @@ class AnnotationDriver implements Driver public function loadMetadataForClass($className, ClassMetadataInfo $metadata) { $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); - // Compatibility with Doctrine Common 3.x - if ($classAnnotations && is_int(key($classAnnotations))) { + if ($classAnnotations && is_numeric(key($classAnnotations))) { foreach ($classAnnotations as $annot) { $classAnnotations[get_class($annot)] = $annot; } @@ -137,12 +151,15 @@ class AnnotationDriver implements Driver // Evaluate Entity annotation if (isset($classAnnotations['Doctrine\ORM\Mapping\Entity'])) { $entityAnnot = $classAnnotations['Doctrine\ORM\Mapping\Entity']; - $metadata->setCustomRepositoryClass($entityAnnot->repositoryClass); - + 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); @@ -158,17 +175,25 @@ class AnnotationDriver implements Driver if ($tableAnnot->indexes !== null) { foreach ($tableAnnot->indexes as $indexAnnot) { - $primaryTable['indexes'][$indexAnnot->name] = array( - 'columns' => $indexAnnot->columns - ); + $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 $uniqueConstraint) { - $primaryTable['uniqueConstraints'][$uniqueConstraint->name] = array( - 'columns' => $uniqueConstraint->columns - ); + foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) { + $uniqueConstraint = array('columns' => $uniqueConstraintAnnot->columns); + + if ( ! empty($uniqueConstraintAnnot->name)) { + $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint; + } else { + $primaryTable['uniqueConstraints'][] = $uniqueConstraint; + } } } @@ -179,7 +204,14 @@ class AnnotationDriver implements Driver 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 @@ -243,7 +275,6 @@ class AnnotationDriver implements Driver 'unique' => $joinColumnAnnot->unique, 'nullable' => $joinColumnAnnot->nullable, 'onDelete' => $joinColumnAnnot->onDelete, - 'onUpdate' => $joinColumnAnnot->onUpdate, 'columnDefinition' => $joinColumnAnnot->columnDefinition, ); } else if ($joinColumnsAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) { @@ -254,7 +285,6 @@ class AnnotationDriver implements Driver 'unique' => $joinColumn->unique, 'nullable' => $joinColumn->nullable, 'onDelete' => $joinColumn->onDelete, - 'onUpdate' => $joinColumn->onUpdate, 'columnDefinition' => $joinColumn->columnDefinition, ); } @@ -320,7 +350,7 @@ class AnnotationDriver implements Driver $mapping['inversedBy'] = $oneToOneAnnot->inversedBy; $mapping['cascade'] = $oneToOneAnnot->cascade; $mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval; - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneAnnot->fetch); + $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; @@ -328,7 +358,7 @@ class AnnotationDriver implements Driver $mapping['cascade'] = $oneToManyAnnot->cascade; $mapping['indexBy'] = $oneToManyAnnot->indexBy; $mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval; - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyAnnot->fetch); + $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch); if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) { $mapping['orderBy'] = $orderByAnnot->value; @@ -344,7 +374,7 @@ class AnnotationDriver implements Driver $mapping['cascade'] = $manyToOneAnnot->cascade; $mapping['inversedBy'] = $manyToOneAnnot->inversedBy; $mapping['targetEntity'] = $manyToOneAnnot->targetEntity; - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneAnnot->fetch); + $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch); $metadata->mapManyToOne($mapping); } else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) { $joinTable = array(); @@ -362,7 +392,6 @@ class AnnotationDriver implements Driver 'unique' => $joinColumn->unique, 'nullable' => $joinColumn->nullable, 'onDelete' => $joinColumn->onDelete, - 'onUpdate' => $joinColumn->onUpdate, 'columnDefinition' => $joinColumn->columnDefinition, ); } @@ -374,7 +403,6 @@ class AnnotationDriver implements Driver 'unique' => $joinColumn->unique, 'nullable' => $joinColumn->nullable, 'onDelete' => $joinColumn->onDelete, - 'onUpdate' => $joinColumn->onUpdate, 'columnDefinition' => $joinColumn->columnDefinition, ); } @@ -386,7 +414,8 @@ class AnnotationDriver implements Driver $mapping['inversedBy'] = $manyToManyAnnot->inversedBy; $mapping['cascade'] = $manyToManyAnnot->cascade; $mapping['indexBy'] = $manyToManyAnnot->indexBy; - $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyAnnot->fetch); + $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; @@ -403,8 +432,7 @@ class AnnotationDriver implements Driver if ($method->isPublic() && $method->getDeclaringClass()->getName() == $class->name) { $annotations = $this->_reader->getMethodAnnotations($method); - // Compatibility with Doctrine Common 3.x - if ($annotations && is_int(key($annotations))) { + if ($annotations && is_numeric(key($annotations))) { foreach ($annotations as $annot) { $annotations[get_class($annot)] = $annot; } @@ -437,6 +465,10 @@ class AnnotationDriver implements Driver 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); + } } } } @@ -455,8 +487,7 @@ class AnnotationDriver implements Driver { $classAnnotations = $this->_reader->getClassAnnotations(new \ReflectionClass($className)); - // Compatibility with Doctrine Common 3.x - if ($classAnnotations && is_int(key($classAnnotations))) { + if ($classAnnotations && is_numeric(key($classAnnotations))) { foreach ($classAnnotations as $annot) { if ($annot instanceof \Doctrine\ORM\Mapping\Entity) { return false; @@ -499,15 +530,15 @@ class AnnotationDriver implements Driver new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY ), - '/^.+\\' . $this->_fileExtension . '$/i', + '/^.+' . str_replace('.', '\.', $this->_fileExtension) . '$/i', \RecursiveRegexIterator::GET_MATCH ); - + foreach ($iterator as $file) { $sourceFile = realpath($file[0]); - + require_once $sourceFile; - + $includedFiles[] = $sourceFile; } } @@ -527,6 +558,22 @@ class AnnotationDriver implements Driver return $classes; } + /** + * 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); + } /** * Factory method for the Annotation Driver * diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php index c2d9240a27..bcbdbd500e 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php @@ -76,7 +76,7 @@ class DatabaseDriver implements Driver /** * Initializes a new AnnotationDriver that uses the given AnnotationReader for reading * docblock annotations. - * + * * @param AnnotationReader $reader The AnnotationReader to use. */ public function __construct(AbstractSchemaManager $schemaManager) @@ -111,7 +111,7 @@ class DatabaseDriver implements Driver } $tables = array(); - + foreach ($this->_sm->listTableNames() as $tableName) { $tables[$tableName] = $this->_sm->listTableDetails($tableName); } @@ -129,7 +129,14 @@ class DatabaseDriver implements Driver 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); @@ -145,7 +152,7 @@ class DatabaseDriver implements Driver } } } - + /** * {@inheritdoc} */ @@ -169,7 +176,7 @@ class DatabaseDriver implements Driver } catch(SchemaException $e) { $primaryKeyColumns = array(); } - + if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) { $foreignKeys = $this->tables[$tableName]->getForeignKeys(); } else { @@ -185,12 +192,13 @@ class DatabaseDriver implements Driver $fieldMappings = array(); foreach ($columns as $column) { $fieldMapping = array(); - if ($primaryKeyColumns && in_array($column->getName(), $primaryKeyColumns)) { - $fieldMapping['id'] = true; - } else if (in_array($column->getName(), $allForeignKeyColumns)) { + + 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()); @@ -291,13 +299,23 @@ class DatabaseDriver implements Driver $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], ); } - $metadata->mapManyToOne($associationMapping); + + //Here we need to check if $cols are the same as $primaryKeyColums + if (!array_diff($cols,$primaryKeyColumns)) { + $metadata->mapOneToOne($associationMapping); + } else { + $metadata->mapManyToOne($associationMapping); + } } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php index 532ee1c771..290fc6529e 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php @@ -17,190 +17,38 @@ * . */ -namespace Doctrine\ORM\Mapping; - -use Doctrine\Common\Annotations\Annotation; - -/* Annotations */ - -/** @Annotation */ -final class Entity extends Annotation { - public $repositoryClass; - public $readOnly = false; -} - -/** @Annotation */ -final class MappedSuperclass extends Annotation {} - -/** @Annotation */ -final class InheritanceType extends Annotation {} - -/** @Annotation */ -final class DiscriminatorColumn extends Annotation { - public $name; - public $fieldName; // field name used in non-object hydration (array/scalar) - public $type; - public $length; -} - -/** @Annotation */ -final class DiscriminatorMap extends Annotation {} - -/** @Annotation */ -final class Id extends Annotation {} - -/** @Annotation */ -final class GeneratedValue extends Annotation { - public $strategy = 'AUTO'; -} - -/** @Annotation */ -final class Version extends Annotation {} - -/** @Annotation */ -final class JoinColumn extends Annotation { - public $name; - public $fieldName; // field name used in non-object hydration (array/scalar) - public $referencedColumnName = 'id'; - public $unique = false; - public $nullable = true; - public $onDelete; - public $onUpdate; - public $columnDefinition; -} - -/** @Annotation */ -final class JoinColumns extends Annotation {} - -/** @Annotation */ -final class Column extends Annotation { - public $type = 'string'; - public $length; - // The precision for a decimal (exact numeric) column (Applies only for decimal column) - public $precision = 0; - // The scale for a decimal (exact numeric) column (Applies only for decimal column) - public $scale = 0; - public $unique = false; - public $nullable = false; - public $name; - public $options = array(); - public $columnDefinition; -} - -/** @Annotation */ -final class OneToOne extends Annotation { - public $targetEntity; - public $mappedBy; - public $inversedBy; - public $cascade; - public $fetch = 'LAZY'; - public $orphanRemoval = false; -} - -/** @Annotation */ -final class OneToMany extends Annotation { - public $mappedBy; - public $targetEntity; - public $cascade; - public $fetch = 'LAZY'; - public $orphanRemoval = false; - public $indexBy; -} - -/** @Annotation */ -final class ManyToOne extends Annotation { - public $targetEntity; - public $cascade; - public $fetch = 'LAZY'; - public $inversedBy; -} - -/** @Annotation */ -final class ManyToMany extends Annotation { - public $targetEntity; - public $mappedBy; - public $inversedBy; - public $cascade; - public $fetch = 'LAZY'; - public $indexBy; -} - -/** @Annotation */ -final class ElementCollection extends Annotation { - public $tableName; -} - -/** @Annotation */ -final class Table extends Annotation { - public $name; - public $schema; - public $indexes; - public $uniqueConstraints; -} - -/** @Annotation */ -final class UniqueConstraint extends Annotation { - public $name; - public $columns; -} - -/** @Annotation */ -final class Index extends Annotation { - public $name; - public $columns; -} - -/** @Annotation */ -final class JoinTable extends Annotation { - public $name; - public $schema; - public $joinColumns = array(); - public $inverseJoinColumns = array(); -} - -/** @Annotation */ -final class SequenceGenerator extends Annotation { - public $sequenceName; - public $allocationSize = 1; - public $initialValue = 1; -} - -/** @Annotation */ -final class ChangeTrackingPolicy extends Annotation {} - -/** @Annotation */ -final class OrderBy extends Annotation {} - -/** @Annotation */ -final class NamedQueries extends Annotation {} - -/** @Annotation */ -final class NamedQuery extends Annotation { - public $name; - public $query; -} - -/* Annotations for lifecycle callbacks */ -/** @Annotation */ -final class HasLifecycleCallbacks extends Annotation {} - -/** @Annotation */ -final class PrePersist extends Annotation {} - -/** @Annotation */ -final class PostPersist extends Annotation {} - -/** @Annotation */ -final class PreUpdate extends Annotation {} - -/** @Annotation */ -final class PostUpdate extends Annotation {} - -/** @Annotation */ -final class PreRemove extends Annotation {} - -/** @Annotation */ -final class PostRemove extends Annotation {} - -/** @Annotation */ -final class PostLoad extends Annotation {} +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__.'/../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'; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/Driver.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/Driver.php index b6cfe36b4a..28654a82bf 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/Driver.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/Driver.php @@ -34,18 +34,18 @@ interface Driver { /** * Loads the metadata for the specified class into the provided container. - * + * * @param string $className * @param ClassMetadataInfo $metadata */ function loadMetadataForClass($className, ClassMetadataInfo $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(); + function getAllClassNames(); /** * Whether the class with the specified name should have its metadata loaded. diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DriverChain.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DriverChain.php index d84d2344bd..321962d2c1 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DriverChain.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/DriverChain.php @@ -94,7 +94,7 @@ class DriverChain implements Driver if (!isset($driverClasses[$oid])) { $driverClasses[$oid] = $driver->getAllClassNames(); } - + foreach ($driverClasses[$oid] AS $className) { if (strpos($className, $namespace) === 0) { $classNames[$className] = true; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php new file mode 100644 index 0000000000..e60eab7791 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php @@ -0,0 +1,176 @@ +. +*/ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\ORM\Mapping\MappingException; + +/** + * XmlDriver that additionally looks for mapping information in a global file. + * + * @author Fabien Potencier + * @author Benjamin Eberlei + * @license MIT + */ +class SimplifiedXmlDriver extends XmlDriver +{ + protected $_prefixes = array(); + protected $_globalBasename; + protected $_classCache; + protected $_fileExtension = '.orm.xml'; + + public function __construct($prefixes) + { + $this->addNamespacePrefixes($prefixes); + } + + public function setGlobalBasename($file) + { + $this->_globalBasename = $file; + } + + public function getGlobalBasename() + { + return $this->_globalBasename; + } + + public function addNamespacePrefixes($prefixes) + { + $this->_prefixes = array_merge($this->_prefixes, $prefixes); + $this->addPaths(array_flip($prefixes)); + } + + public function getNamespacePrefixes() + { + return $this->_prefixes; + } + + public function isTransient($className) + { + if (null === $this->_classCache) { + $this->initialize(); + } + + // The mapping is defined in the global mapping file + if (isset($this->_classCache[$className])) { + return false; + } + + try { + $this->_findMappingFile($className); + + return false; + } catch (MappingException $e) { + return true; + } + } + + public function getAllClassNames() + { + if (null === $this->_classCache) { + $this->initialize(); + } + + $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 == $this->_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 array_merge($classes, array_keys($this->_classCache)); + } + + public function getElement($className) + { + if (null === $this->_classCache) { + $this->initialize(); + } + + if (!isset($this->_classCache[$className])) { + $this->_classCache[$className] = parent::getElement($className); + } + + return $this->_classCache[$className]; + } + + protected function initialize() + { + $this->_classCache = array(); + if (null !== $this->_globalBasename) { + foreach ($this->_paths as $path) { + if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) { + $this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file)); + } + } + } + } + + protected 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/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php new file mode 100644 index 0000000000..b88a769392 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php @@ -0,0 +1,181 @@ +. +*/ + +namespace Doctrine\ORM\Mapping\Driver; + +use Doctrine\ORM\Mapping\MappingException; + +/** + * YamlDriver that additionally looks for mapping information in a global file. + * + * @author Fabien Potencier + * @author Benjamin Eberlei + * @license MIT + */ +class SimplifiedYamlDriver extends YamlDriver +{ + protected $_prefixes = array(); + protected $_globalBasename; + protected $_classCache; + protected $_fileExtension = '.orm.yml'; + + public function __construct($prefixes) + { + $this->addNamespacePrefixes($prefixes); + } + + public function setGlobalBasename($file) + { + $this->_globalBasename = $file; + } + + public function getGlobalBasename() + { + return $this->_globalBasename; + } + + public function addNamespacePrefixes($prefixes) + { + $this->_prefixes = array_merge($this->_prefixes, $prefixes); + $this->addPaths(array_flip($prefixes)); + } + + public function addNamespacePrefix($prefix, $path) + { + $this->_prefixes[$path] = $prefix; + } + + public function getNamespacePrefixes() + { + return $this->_prefixes; + } + + public function isTransient($className) + { + if (null === $this->_classCache) { + $this->initialize(); + } + + // The mapping is defined in the global mapping file + if (isset($this->_classCache[$className])) { + return false; + } + + try { + $this->_findMappingFile($className); + + return false; + } catch (MappingException $e) { + return true; + } + } + + public function getAllClassNames() + { + if (null === $this->_classCache) { + $this->initialize(); + } + + $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 == $this->_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 array_merge($classes, array_keys($this->_classCache)); + } + + public function getElement($className) + { + if (null === $this->_classCache) { + $this->initialize(); + } + + if (!isset($this->_classCache[$className])) { + $this->_classCache[$className] = parent::getElement($className); + } + + return $this->_classCache[$className]; + } + + protected function initialize() + { + $this->_classCache = array(); + if (null !== $this->_globalBasename) { + foreach ($this->_paths as $path) { + if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) { + $this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file)); + } + } + } + } + + protected 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/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php index 916113c1d2..4e593ea8c0 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/StaticPHPDriver.php @@ -38,21 +38,21 @@ class StaticPHPDriver implements Driver { /** * Paths of entity directories. - * + * * @var array */ private $_paths = array(); - + /** * Map of all class names. - * + * * @var array */ private $_classNames; - + /** * The file extension of mapping documents. - * + * * @var string */ private $_fileExtension = '.php'; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/XmlDriver.php index 8df60a982a..31f31916be 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -52,13 +52,16 @@ class XmlDriver extends AbstractFileDriver $xmlRoot = $this->getElement($className); if ($xmlRoot->getName() == 'entity') { - $metadata->setCustomRepositoryClass( - isset($xmlRoot['repository-class']) ? (string)$xmlRoot['repository-class'] : null - ); + 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); @@ -163,9 +166,12 @@ class XmlDriver extends AbstractFileDriver foreach ($xmlRoot->field as $fieldMapping) { $mapping = array( 'fieldName' => (string)$fieldMapping['name'], - 'type' => (string)$fieldMapping['type'] ); + if (isset($fieldMapping['type'])) { + $mapping['type'] = (string)$fieldMapping['type']; + } + if (isset($fieldMapping['column'])) { $mapping['columnName'] = (string)$fieldMapping['column']; } @@ -216,14 +222,21 @@ class XmlDriver extends AbstractFileDriver $mapping = array( 'id' => true, - 'fieldName' => (string)$idElement['name'], - 'type' => (string)$idElement['type'] + 'fieldName' => (string)$idElement['name'] ); + if (isset($idElement['type'])) { + $mapping['type'] = (string)$idElement['type']; + } + 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)) { @@ -368,10 +381,6 @@ class XmlDriver extends AbstractFileDriver $mapping['cascade'] = $this->_getCascadeMappings($manyToOneElement->cascade); } - if (isset($manyToOneElement->{'orphan-removal'})) { - $mapping['orphanRemoval'] = (bool)$manyToOneElement->{'orphan-removal'}; - } - $metadata->mapManyToOne($mapping); } } @@ -388,6 +397,10 @@ class XmlDriver extends AbstractFileDriver $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'})) { @@ -419,10 +432,6 @@ class XmlDriver extends AbstractFileDriver $mapping['cascade'] = $this->_getCascadeMappings($manyToManyElement->cascade); } - if (isset($manyToManyElement->{'orphan-removal'})) { - $mapping['orphanRemoval'] = (bool)$manyToManyElement->{'orphan-removal'}; - } - if (isset($manyToManyElement->{'order-by'})) { $orderBy = array(); foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} AS $orderByField) { @@ -475,10 +484,6 @@ class XmlDriver extends AbstractFileDriver $joinColumn['onDelete'] = (string)$joinColumnElement['on-delete']; } - if (isset($joinColumnElement['on-update'])) { - $joinColumn['onUpdate'] = (string)$joinColumnElement['on-update']; - } - if (isset($joinColumnElement['column-definition'])) { $joinColumn['columnDefinition'] = (string)$joinColumnElement['column-definition']; } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/YamlDriver.php index ae488ce63f..c8baa2fd82 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -46,13 +46,16 @@ class YamlDriver extends AbstractFileDriver $element = $this->getElement($className); if ($element['type'] == 'entity') { - $metadata->setCustomRepositoryClass( - isset($element['repositoryClass']) ? $element['repositoryClass'] : null - ); + 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); @@ -162,16 +165,15 @@ class YamlDriver extends AbstractFileDriver continue; } - if (!isset($idElement['type'])) { - throw MappingException::propertyTypeIsRequired($className, $name); - } - $mapping = array( 'id' => true, - 'fieldName' => $name, - 'type' => $idElement['type'] + 'fieldName' => $name ); + if (isset($idElement['type'])) { + $mapping['type'] = $idElement['type']; + } + if (isset($idElement['column'])) { $mapping['columnName'] = $idElement['column']; } @@ -180,6 +182,10 @@ class YamlDriver extends AbstractFileDriver $mapping['length'] = $idElement['length']; } + if (isset($idElement['columnDefinition'])) { + $mapping['columnDefinition'] = $idElement['columnDefinition']; + } + $metadata->mapField($mapping); if (isset($idElement['generator'])) { @@ -198,19 +204,21 @@ class YamlDriver extends AbstractFileDriver // Evaluate fields if (isset($element['fields'])) { foreach ($element['fields'] as $name => $fieldMapping) { - if (!isset($fieldMapping['type'])) { - throw MappingException::propertyTypeIsRequired($className, $name); - } - $e = explode('(', $fieldMapping['type']); - $fieldMapping['type'] = $e[0]; - if (isset($e[1])) { - $fieldMapping['length'] = substr($e[1], 0, strlen($e[1]) - 1); - } $mapping = array( - 'fieldName' => $name, - 'type' => $fieldMapping['type'] + 'fieldName' => $name ); + + if (isset($fieldMapping['type'])) { + $e = explode('(', $fieldMapping['type']); + $fieldMapping['type'] = $e[0]; + $mapping['type'] = $fieldMapping['type']; + + if (isset($e[1])) { + $fieldMapping['length'] = substr($e[1], 0, strlen($e[1]) - 1); + } + } + if (isset($fieldMapping['id'])) { $mapping['id'] = true; if (isset($fieldMapping['generator']['strategy'])) { @@ -375,10 +383,6 @@ class YamlDriver extends AbstractFileDriver $mapping['cascade'] = $manyToOneElement['cascade']; } - if (isset($manyToOneElement['orphanRemoval'])) { - $mapping['orphanRemoval'] = (bool)$manyToOneElement['orphanRemoval']; - } - $metadata->mapManyToOne($mapping); } } @@ -398,9 +402,6 @@ class YamlDriver extends AbstractFileDriver if (isset($manyToManyElement['mappedBy'])) { $mapping['mappedBy'] = $manyToManyElement['mappedBy']; } else if (isset($manyToManyElement['joinTable'])) { - if (isset($manyToManyElement['inversedBy'])) { - $mapping['inversedBy'] = $manyToManyElement['inversedBy']; - } $joinTableElement = $manyToManyElement['joinTable']; $joinTable = array( @@ -430,12 +431,12 @@ class YamlDriver extends AbstractFileDriver $mapping['joinTable'] = $joinTable; } - if (isset($manyToManyElement['cascade'])) { - $mapping['cascade'] = $manyToManyElement['cascade']; + if (isset($manyToManyElement['inversedBy'])) { + $mapping['inversedBy'] = $manyToManyElement['inversedBy']; } - if (isset($manyToManyElement['orphanRemoval'])) { - $mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval']; + if (isset($manyToManyElement['cascade'])) { + $mapping['cascade'] = $manyToManyElement['cascade']; } if (isset($manyToManyElement['orderBy'])) { @@ -446,6 +447,10 @@ class YamlDriver extends AbstractFileDriver $mapping['indexBy'] = $manyToManyElement['indexBy']; } + if (isset($manyToManyElement['orphanRemoval'])) { + $mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval']; + } + $metadata->mapManyToMany($mapping); } } @@ -490,10 +495,6 @@ class YamlDriver extends AbstractFileDriver $joinColumn['onDelete'] = $joinColumnElement['onDelete']; } - if (isset($joinColumnElement['onUpdate'])) { - $joinColumn['onUpdate'] = $joinColumnElement['onUpdate']; - } - if (isset($joinColumnElement['columnDefinition'])) { $joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition']; } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/ElementCollection.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ElementCollection.php new file mode 100644 index 0000000000..f127174191 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/Entity.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Entity.php new file mode 100644 index 0000000000..075a5ecec4 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/GeneratedValue.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/GeneratedValue.php new file mode 100644 index 0000000000..8558d21c38 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php new file mode 100644 index 0000000000..a65fbb522c --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("CLASS") + */ +final class HasLifecycleCallbacks implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Id.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Id.php new file mode 100644 index 0000000000..a670e3ddba --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Id.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class Id implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/Index.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Index.php new file mode 100644 index 0000000000..e0a2db36cd --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/InheritanceType.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/InheritanceType.php new file mode 100644 index 0000000000..009f3abf3d --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinColumn.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinColumn.php new file mode 100644 index 0000000000..bf5c51d07b --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinColumns.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinColumns.php new file mode 100644 index 0000000000..525105fabb --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinTable.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinTable.php new file mode 100644 index 0000000000..9ff9d4511e --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/JoinTable.php @@ -0,0 +1,36 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +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/main/inc/lib/symfony/Doctrine/ORM/Mapping/ManyToMany.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ManyToMany.php new file mode 100644 index 0000000000..28f41aaffe --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/ManyToOne.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/ManyToOne.php new file mode 100644 index 0000000000..1bc83769cf --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/MappedSuperclass.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/MappedSuperclass.php new file mode 100644 index 0000000000..639d21642a --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/MappingException.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/MappingException.php index 5bedf3a06d..c71c2e91cf 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Mapping/MappingException.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/MappingException.php @@ -68,6 +68,11 @@ class MappingException extends \Doctrine\ORM\ORMException return new self("No mapping file found named '$fileName' for class '$entityName'."); } + public static function invalidMappingFile($entityName, $fileName) + { + return new self("Invalid mapping file '$fileName' for class '$entityName'."); + } + public static function mappingNotFound($className, $fieldName) { return new self("No mapping found for field '$fieldName' on class '$className'."); @@ -184,7 +189,7 @@ class MappingException extends \Doctrine\ORM\ORMException 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!' @@ -226,6 +231,11 @@ class MappingException extends \Doctrine\ORM\ORMException 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 @@ -270,6 +280,12 @@ class MappingException extends \Doctrine\ORM\ORMException "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'."); @@ -279,18 +295,38 @@ class MappingException extends \Doctrine\ORM\ORMException { 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 descriminator map of '" . $rootClassName . "' " . + "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." ); } -} \ No newline at end of file + + 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."'."); + } +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/NamedQueries.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/NamedQueries.php new file mode 100644 index 0000000000..1ab2bf2334 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/NamedQuery.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/NamedQuery.php new file mode 100644 index 0000000000..656a4eabf7 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/OneToMany.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/OneToMany.php new file mode 100644 index 0000000000..b4d8ad3f8f --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/OneToOne.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/OneToOne.php new file mode 100644 index 0000000000..4baa121968 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/OrderBy.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/OrderBy.php new file mode 100644 index 0000000000..c28f110428 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostLoad.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostLoad.php new file mode 100644 index 0000000000..169bb4904a --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostLoad.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PostLoad implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostPersist.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostPersist.php new file mode 100644 index 0000000000..5b5baed12c --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostPersist.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PostPersist implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostRemove.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostRemove.php new file mode 100644 index 0000000000..4798e26e84 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostRemove.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PostRemove implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostUpdate.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostUpdate.php new file mode 100644 index 0000000000..f7e7539734 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PostUpdate.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PostUpdate implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/PreFlush.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PreFlush.php new file mode 100644 index 0000000000..f5eb086364 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PreFlush.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PreFlush implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/PrePersist.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PrePersist.php new file mode 100644 index 0000000000..c3827006e1 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PrePersist.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PrePersist implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/PreRemove.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PreRemove.php new file mode 100644 index 0000000000..adcb837d7a --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PreRemove.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PreRemove implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/PreUpdate.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PreUpdate.php new file mode 100644 index 0000000000..2afd38120b --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/PreUpdate.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("METHOD") + */ +final class PreUpdate implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/SequenceGenerator.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/SequenceGenerator.php new file mode 100644 index 0000000000..be3d700f9c --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/Table.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Table.php new file mode 100644 index 0000000000..41db294de0 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Table.php @@ -0,0 +1,36 @@ +. + */ + +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; +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Mapping/UniqueConstraint.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/UniqueConstraint.php new file mode 100644 index 0000000000..db9f8fd41b --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Mapping/Version.php b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Version.php new file mode 100644 index 0000000000..313e7519c8 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Mapping/Version.php @@ -0,0 +1,28 @@ +. + */ + +namespace Doctrine\ORM\Mapping; + +/** + * @Annotation + * @Target("PROPERTY") + */ +final class Version implements Annotation +{ +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/NativeQuery.php b/main/inc/lib/symfony/Doctrine/ORM/NativeQuery.php index 2c0a5ab284..2ab87441a2 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/NativeQuery.php +++ b/main/inc/lib/symfony/Doctrine/ORM/NativeQuery.php @@ -1,4 +1,4 @@ -_sql = $sql; + return $this; } @@ -57,17 +58,19 @@ final class NativeQuery extends AbstractQuery */ protected function _doExecute() { - $stmt = $this->_em->getConnection()->prepare($this->_sql); $params = $this->_params; - foreach ($params as $key => $value) { - if (isset($this->_paramTypes[$key])) { - $stmt->bindValue($key, $value, $this->_paramTypes[$key]); - } else { - $stmt->bindValue($key, $value); - } + $types = $this->_paramTypes; + + if ($params && is_int(key($params))) { + ksort($params); + ksort($types); + + $params = array_values($params); + $types = array_values($types); } - $stmt->execute(); - return $stmt; + return $this->_em->getConnection()->executeQuery( + $this->_sql, $params, $types, $this->_queryCacheProfile + ); } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/NoResultException.php b/main/inc/lib/symfony/Doctrine/ORM/NoResultException.php index 80f08bb932..eb31f7cc93 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/NoResultException.php +++ b/main/inc/lib/symfony/Doctrine/ORM/NoResultException.php @@ -21,7 +21,7 @@ namespace Doctrine\ORM; /** * Exception thrown when an ORM query unexpectedly does not return any results. - * + * * @author robo * @since 2.0 */ diff --git a/main/inc/lib/symfony/Doctrine/ORM/NonUniqueResultException.php b/main/inc/lib/symfony/Doctrine/ORM/NonUniqueResultException.php index 811df75c1e..1a3a8b7eb4 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/NonUniqueResultException.php +++ b/main/inc/lib/symfony/Doctrine/ORM/NonUniqueResultException.php @@ -21,7 +21,7 @@ namespace Doctrine\ORM; /** * Exception thrown when an ORM query unexpectedly returns more than one result. - * + * * @author robo * @since 2.0 */ diff --git a/main/inc/lib/symfony/Doctrine/ORM/ORMException.php b/main/inc/lib/symfony/Doctrine/ORM/ORMException.php index 72e05113ac..bd16839f3b 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/ORMException.php +++ b/main/inc/lib/symfony/Doctrine/ORM/ORMException.php @@ -34,27 +34,26 @@ class ORMException extends Exception return new self("It's a requirement to specify a Metadata Driver and pass it ". "to Doctrine\ORM\Configuration::setMetadataDriverImpl()."); } - + 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 ientity itself. You have to call EntityManager#persist() on the related entity " . - "and make sure it an identifier was generated before trying to persist '" . get_class($entity) . "'. In case " . + "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 entityMissingAssignedId($entity) + public static function entityMissingAssignedIdForField($entity, $field) { - return new self("Entity of type " . get_class($entity) . " is missing an assigned ID. " . + 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 " . + "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"); @@ -139,4 +138,15 @@ class ORMException extends Exception "Unknown Entity namespace alias '$entityNamespaceAlias'." ); } + + public static function invalidEntityRepository($className) + { + return new self("Invalid repository class '".$className."'. ". + "it must be a Doctrine\ORM\EntityRepository."); + } + + public static function missingIdentifierField($className, $fieldName) + { + return new self("The identifier $fieldName is missing for a query of " . $className); + } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/ORMInvalidArgumentException.php b/main/inc/lib/symfony/Doctrine/ORM/ORMInvalidArgumentException.php new file mode 100644 index 0000000000..878ee4b71e --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/ORMInvalidArgumentException.php @@ -0,0 +1,107 @@ +. + */ + +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) + { + throw 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\"}). " + . " 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) + { + throw 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) + { + throw 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) + { + throw new self("Entity has no identity, therefore " . $operation ." cannot be performed. " . self::objToStr($entity)); + } + + static public function entityIsRemoved($entity, $operation) + { + throw new self("Entity is removed, therefore " . $operation ." cannot be performed. " . self::objToStr($entity)); + } + + static public function detachedEntityCannot($entity, $operation) + { + throw new self("A detached entity was found during " . $operation . " " . self::objToStr($entity)); + } + + /** + * 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); + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/PersistentCollection.php b/main/inc/lib/symfony/Doctrine/ORM/PersistentCollection.php index feb8a0ef32..3bfb0d1ebf 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/PersistentCollection.php +++ b/main/inc/lib/symfony/Doctrine/ORM/PersistentCollection.php @@ -21,6 +21,7 @@ namespace Doctrine\ORM; use Doctrine\ORM\Mapping\ClassMetadata, Doctrine\Common\Collections\Collection, + Doctrine\Common\Collections\ArrayCollection, Closure; /** @@ -114,8 +115,8 @@ final class PersistentCollection implements Collection */ public function __construct(EntityManager $em, $class, $coll) { - $this->coll = $coll; - $this->em = $em; + $this->coll = $coll; + $this->em = $em; $this->typeClass = $class; } @@ -129,8 +130,8 @@ final class PersistentCollection implements Collection */ public function setOwner($entity, array $assoc) { - $this->owner = $entity; - $this->association = $assoc; + $this->owner = $entity; + $this->association = $assoc; $this->backRefFieldName = $assoc['inversedBy'] ?: $assoc['mappedBy']; } @@ -160,16 +161,18 @@ final class PersistentCollection implements Collection 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) { + 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->typeClass->reflFields[$this->backRefFieldName]->setValue( + $element, $this->owner + ); + $this->em->getUnitOfWork()->setOriginalEntityProperty( - spl_object_hash($element), - $this->backRefFieldName, - $this->owner); + spl_object_hash($element), $this->backRefFieldName, $this->owner + ); } } @@ -183,12 +186,14 @@ final class PersistentCollection implements Collection 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) { + 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->typeClass->reflFields[$this->backRefFieldName]->setValue( + $element, $this->owner + ); } } @@ -198,23 +203,31 @@ final class PersistentCollection implements Collection */ public function initialize() { - if ( ! $this->initialized && $this->association) { - if ($this->isDirty) { - // Has NEW objects added through add(). Remember them. - $newObjects = $this->coll->toArray(); - } - $this->coll->clear(); - $this->em->getUnitOfWork()->loadCollection($this); - $this->takeSnapshot(); - // Reattach NEW objects added through add(), if any. - if (isset($newObjects)) { - foreach ($newObjects as $obj) { - $this->coll->add($obj); - } - $this->isDirty = true; + 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->initialized = true; + + $this->isDirty = true; } + + $this->initialized = true; } /** @@ -224,7 +237,7 @@ final class PersistentCollection implements Collection public function takeSnapshot() { $this->snapshot = $this->coll->toArray(); - $this->isDirty = false; + $this->isDirty = false; } /** @@ -246,8 +259,11 @@ final class PersistentCollection implements Collection */ public function getDeleteDiff() { - return array_udiff_assoc($this->snapshot, $this->coll->toArray(), - function($a, $b) {return $a === $b ? 0 : 1;}); + return array_udiff_assoc( + $this->snapshot, + $this->coll->toArray(), + function($a, $b) { return $a === $b ? 0 : 1; } + ); } /** @@ -258,8 +274,11 @@ final class PersistentCollection implements Collection */ public function getInsertDiff() { - return array_udiff_assoc($this->coll->toArray(), $this->snapshot, - function($a, $b) {return $a === $b ? 0 : 1;}); + return array_udiff_assoc( + $this->coll->toArray(), + $this->snapshot, + function($a, $b) { return $a === $b ? 0 : 1; } + ); } /** @@ -277,12 +296,18 @@ final class PersistentCollection implements Collection */ private function changed() { - if ( ! $this->isDirty) { - $this->isDirty = true; - if ($this->association !== null && $this->association['isOwningSide'] && $this->association['type'] == ClassMetadata::MANY_TO_MANY && - $this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) { - $this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner); - } + 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); } } @@ -331,6 +356,7 @@ final class PersistentCollection implements Collection public function first() { $this->initialize(); + return $this->coll->first(); } @@ -338,6 +364,7 @@ final class PersistentCollection implements Collection public function last() { $this->initialize(); + return $this->coll->last(); } @@ -351,13 +378,19 @@ final class PersistentCollection implements Collection // 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) { - $this->changed(); - if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY && - $this->association['orphanRemoval']) { - $this->em->getUnitOfWork()->scheduleOrphanRemoval($removed); - } + + if ( ! $removed) { + return $removed; + } + + $this->changed(); + + if ($this->association !== null && + $this->association['type'] & ClassMetadata::TO_MANY && + $this->association['orphanRemoval']) { + $this->em->getUnitOfWork()->scheduleOrphanRemoval($removed); } return $removed; @@ -368,25 +401,36 @@ final class PersistentCollection implements Collection */ public function removeElement($element) { - // TODO: Assuming the identity of entities in a collection is always based - // on their primary key (there is no equals/hashCode in PHP), - // if the collection is not initialized, we could issue a straight - // SQL DELETE/UPDATE on the association (table) without initializing - // the collection. - /*if ( ! $this->initialized) { - $this->em->getUnitOfWork()->getCollectionPersister($this->association) - ->deleteRows($this, $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) { - $this->changed(); - if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY && - $this->association['orphanRemoval']) { - $this->em->getUnitOfWork()->scheduleOrphanRemoval($element); - } + + if ( ! $removed) { + return $removed; + } + + $this->changed(); + + if ($this->association !== null && + $this->association['type'] & ClassMetadata::TO_MANY && + $this->association['orphanRemoval']) { + $this->em->getUnitOfWork()->scheduleOrphanRemoval($element); } + return $removed; } @@ -396,6 +440,7 @@ final class PersistentCollection implements Collection public function containsKey($key) { $this->initialize(); + return $this->coll->containsKey($key); } @@ -404,14 +449,14 @@ final class PersistentCollection implements Collection */ public function contains($element) { - if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { - return $this->coll->contains($element) || - $this->em->getUnitOfWork() - ->getCollectionPersister($this->association) - ->contains($this, $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); } @@ -421,6 +466,7 @@ final class PersistentCollection implements Collection public function exists(Closure $p) { $this->initialize(); + return $this->coll->exists($p); } @@ -430,6 +476,7 @@ final class PersistentCollection implements Collection public function indexOf($element) { $this->initialize(); + return $this->coll->indexOf($element); } @@ -439,6 +486,7 @@ final class PersistentCollection implements Collection public function get($key) { $this->initialize(); + return $this->coll->get($key); } @@ -448,6 +496,7 @@ final class PersistentCollection implements Collection public function getKeys() { $this->initialize(); + return $this->coll->getKeys(); } @@ -457,6 +506,7 @@ final class PersistentCollection implements Collection public function getValues() { $this->initialize(); + return $this->coll->getValues(); } @@ -465,13 +515,14 @@ final class PersistentCollection implements Collection */ public function count() { - if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { - return $this->em->getUnitOfWork() - ->getCollectionPersister($this->association) - ->count($this) + ($this->isDirty ? $this->coll->count() : 0); + 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(); } @@ -481,7 +532,9 @@ final class PersistentCollection implements Collection public function set($key, $value) { $this->initialize(); + $this->coll->set($key, $value); + $this->changed(); } @@ -491,7 +544,9 @@ final class PersistentCollection implements Collection public function add($value) { $this->coll->add($value); + $this->changed(); + return true; } @@ -501,6 +556,7 @@ final class PersistentCollection implements Collection public function isEmpty() { $this->initialize(); + return $this->coll->isEmpty(); } @@ -510,6 +566,7 @@ final class PersistentCollection implements Collection public function getIterator() { $this->initialize(); + return $this->coll->getIterator(); } @@ -519,6 +576,7 @@ final class PersistentCollection implements Collection public function map(Closure $func) { $this->initialize(); + return $this->coll->map($func); } @@ -528,6 +586,7 @@ final class PersistentCollection implements Collection public function filter(Closure $p) { $this->initialize(); + return $this->coll->filter($p); } @@ -537,6 +596,7 @@ final class PersistentCollection implements Collection public function forAll(Closure $p) { $this->initialize(); + return $this->coll->forAll($p); } @@ -546,6 +606,7 @@ final class PersistentCollection implements Collection public function partition(Closure $p) { $this->initialize(); + return $this->coll->partition($p); } @@ -555,6 +616,7 @@ final class PersistentCollection implements Collection public function toArray() { $this->initialize(); + return $this->coll->toArray(); } @@ -566,19 +628,28 @@ final class PersistentCollection implements Collection if ($this->initialized && $this->isEmpty()) { return; } - if ($this->association['type'] == ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) { + + $uow = $this->em->getUnitOfWork(); + + if ($this->association['type'] & ClassMetadata::TO_MANY && $this->association['orphanRemoval']) { // 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) { - $this->em->getUnitOfWork()->scheduleOrphanRemoval($element); + $uow->scheduleOrphanRemoval($element); } } + $this->coll->clear(); + $this->initialized = true; // direct call, {@link initialize()} is too expensive + if ($this->association['isOwningSide']) { $this->changed(); - $this->em->getUnitOfWork()->scheduleCollectionDeletion($this); + + $uow->scheduleCollectionDeletion($this); + $this->takeSnapshot(); } } @@ -622,6 +693,7 @@ final class PersistentCollection implements Collection if ( ! isset($offset)) { return $this->add($value); } + return $this->set($offset, $value); } @@ -656,6 +728,8 @@ final class PersistentCollection implements Collection /** * Retrieves the wrapped Collection instance. + * + * @return \Doctrine\Common\Collections\Collection */ public function unwrap() { @@ -671,20 +745,42 @@ final class PersistentCollection implements Collection * * @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) { + if ( ! $this->initialized && ! $this->isDirty && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { + $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); - return $this->em->getUnitOfWork() - ->getCollectionPersister($this->association) - ->slice($this, $offset, $length); + 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() + { + $this->initialize(); + $this->owner = null; + + if (is_object($this->coll)) { + $this->coll = clone $this->coll; + } + $this->snapshot = array(); + $this->changed(); + } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Persisters/AbstractCollectionPersister.php b/main/inc/lib/symfony/Doctrine/ORM/Persisters/AbstractCollectionPersister.php index 9367aeeb78..8c129481e7 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Persisters/AbstractCollectionPersister.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Persisters/AbstractCollectionPersister.php @@ -65,11 +65,11 @@ abstract class AbstractCollectionPersister 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)); } @@ -98,34 +98,34 @@ abstract class AbstractCollectionPersister 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)); } @@ -151,6 +151,16 @@ abstract class AbstractCollectionPersister 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."); @@ -158,7 +168,7 @@ abstract class AbstractCollectionPersister /** * Gets the SQL statement used for deleting a row from the collection. - * + * * @param PersistentCollection $coll */ abstract protected function _getDeleteRowSQL(PersistentCollection $coll); @@ -194,4 +204,4 @@ abstract class AbstractCollectionPersister * @param mixed $element */ abstract protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element); -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php b/main/inc/lib/symfony/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php index 670cf11e72..191c077989 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php @@ -26,7 +26,7 @@ use Doctrine\ORM\Mapping\ClassMetadata, * 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 @@ -39,18 +39,18 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister 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(); @@ -62,18 +62,22 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister { $columnName = $class->columnNames[$field]; $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform); - $columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++); + $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 = $joinColumnName . $this->_sqlAliasCounter++; - $resultColumnName = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addMetaResult('r', $resultColumnName, $joinColumnName); - + $columnAlias = $this->getSQLColumnAlias($joinColumnName); + $this->_rsm->addMetaResult('r', $columnAlias, $joinColumnName); + return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias; } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Persisters/BasicEntityPersister.php b/main/inc/lib/symfony/Doctrine/ORM/Persisters/BasicEntityPersister.php index efa55ceb04..9c6898383c 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Persisters/BasicEntityPersister.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -26,6 +26,7 @@ use PDO, Doctrine\ORM\ORMException, Doctrine\ORM\OptimisticLockException, Doctrine\ORM\EntityManager, + Doctrine\ORM\UnitOfWork, Doctrine\ORM\Query, Doctrine\ORM\PersistentCollection, Doctrine\ORM\Mapping\MappingException, @@ -71,6 +72,7 @@ use PDO, * @author Roman Borschel * @author Giorgio Sironi * @author Benjamin Eberlei + * @author Alexander * @since 2.0 */ class BasicEntityPersister @@ -221,14 +223,14 @@ class BasicEntityPersister $isPostInsertId = $idGen->isPostInsertGenerator(); $stmt = $this->_conn->prepare($this->_getInsertSQL()); - $tableName = $this->_class->table['name']; + $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]); } @@ -278,11 +280,14 @@ class BasicEntityPersister protected function fetchVersionValue($versionedClass, $id) { $versionField = $versionedClass->versionField; - $identifier = $versionedClass->getIdentifierColumnNames(); - $versionFieldColumnName = $versionedClass->getColumnName($versionField); + $identifier = $versionedClass->getIdentifierColumnNames(); + + $versionFieldColumnName = $versionedClass->getQuotedColumnName($versionField, $this->_platform); + //FIXME: Order with composite keys might not be correct - $sql = "SELECT " . $versionFieldColumnName . " FROM " . $versionedClass->getQuotedTableName($this->_platform) - . " WHERE " . implode(' = ? AND ', $identifier) . " = ?"; + $sql = 'SELECT ' . $versionFieldColumnName + . ' FROM ' . $versionedClass->getQuotedTableName($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); @@ -305,7 +310,8 @@ class BasicEntityPersister public function update($entity) { $updateData = $this->_prepareUpdateData($entity); - $tableName = $this->_class->table['name']; + $tableName = $this->_class->getTableName(); + if (isset($updateData[$tableName]) && $updateData[$tableName]) { $this->_updateTable( $entity, $this->_class->getQuotedTableName($this->_platform), @@ -333,17 +339,26 @@ class BasicEntityPersister $set = $params = $types = array(); foreach ($updateData as $columnName => $value) { + $column = $columnName; + $placeholder = '?'; + if (isset($this->_class->fieldNames[$columnName])) { - $set[] = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform) . ' = ?'; - } else { - $set[] = $columnName . ' = ?'; + $column = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform); + + if (isset($this->_class->fieldMappings[$this->_class->fieldNames[$columnName]]['requireSQLConversion'])) { + $type = Type::getType($this->_columnTypes[$columnName]); + $placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform); + } } + + $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']); @@ -361,18 +376,21 @@ class BasicEntityPersister $versionField = $this->_class->versionField; $versionFieldType = $this->_class->fieldMappings[$versionField]['type']; $versionColumn = $this->_class->getQuotedColumnName($versionField, $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) . ' = ?'; + $sql = 'UPDATE ' . $quotedTableName + . ' SET ' . implode(', ', $set) + . ' WHERE ' . implode(' = ? AND ', $where) . ' = ?'; $result = $this->_conn->executeUpdate($sql, $params, $types); @@ -398,21 +416,29 @@ class BasicEntityPersister $relatedClass = $this->_em->getClassMetadata($mapping['targetEntity']); $mapping = $relatedClass->associationMappings[$mapping['mappedBy']]; $keys = array_keys($mapping['relationToTargetKeyColumns']); + if ($selfReferential) { $otherKeys = array_keys($mapping['relationToSourceKeyColumns']); } } else { $keys = array_keys($mapping['relationToSourceKeyColumns']); + if ($selfReferential) { $otherKeys = array_keys($mapping['relationToTargetKeyColumns']); } } if ( ! isset($mapping['isOnDeleteCascade'])) { - $this->_conn->delete($mapping['joinTable']['name'], array_combine($keys, $identifier)); + $this->_conn->delete( + $this->_class->getQuotedJoinTableName($mapping, $this->_platform), + array_combine($keys, $identifier) + ); if ($selfReferential) { - $this->_conn->delete($mapping['joinTable']['name'], array_combine($otherKeys, $identifier)); + $this->_conn->delete( + $this->_class->getQuotedJoinTableName($mapping, $this->_platform), + array_combine($otherKeys, $identifier) + ); } } } @@ -463,7 +489,7 @@ class BasicEntityPersister $result = array(); $uow = $this->_em->getUnitOfWork(); - if ($versioned = $this->_class->isVersioned) { + if (($versioned = $this->_class->isVersioned) != false) { $versionField = $this->_class->versionField; } @@ -477,6 +503,7 @@ class BasicEntityPersister 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; @@ -484,6 +511,7 @@ class BasicEntityPersister 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 @@ -510,6 +538,7 @@ class BasicEntityPersister } else { $result[$owningTable][$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]]; } + $this->_columnTypes[$sourceColumn] = $targetClass->getTypeOfColumn($targetColumn); } } else { @@ -518,6 +547,7 @@ class BasicEntityPersister $result[$this->getOwningTable($field)][$columnName] = $newVal; } } + return $result; } @@ -548,7 +578,7 @@ class BasicEntityPersister */ public function getOwningTable($fieldName) { - return $this->_class->table['name']; + return $this->_class->getTableName(); } /** @@ -560,12 +590,13 @@ class BasicEntityPersister * @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) + public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = 0, $limit = null) { - $sql = $this->_getSelectEntitiesSQL($criteria, $assoc, $lockMode); + $sql = $this->_getSelectEntitiesSQL($criteria, $assoc, $lockMode, $limit); list($params, $types) = $this->expandParameters($criteria); $stmt = $this->_conn->executeQuery($sql, $params, $types); @@ -574,12 +605,9 @@ class BasicEntityPersister $hints[Query::HINT_REFRESH_ENTITY] = $entity; } - if ($this->_selectJoinSql) { - $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); - } else { - $hydrator = $this->_em->newHydrator(Query::HYDRATE_SIMPLEOBJECT); - } + $hydrator = $this->_em->newHydrator($this->_selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); $entities = $hydrator->hydrateAll($stmt, $this->_rsm, $hints); + return $entities ? $entities[0] : null; } @@ -596,7 +624,7 @@ class BasicEntityPersister */ public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = array()) { - if ($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) { + if (($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) != false) { return $foundEntity; } @@ -608,14 +636,11 @@ class BasicEntityPersister // 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'][$targetClass->name][$assoc['inversedBy']] = true; - if ($targetClass->subClasses) { - foreach ($targetClass->subClasses as $targetSubclassName) { - $hints['fetched'][$targetSubclassName][$assoc['inversedBy']] = true; - } - } + $hints['fetched']["r"][$assoc['inversedBy']] = true; } + /* cascade read-only status if ($this->_em->getUnitOfWork()->isReadOnly($sourceEntity)) { $hints[Query::HINT_READ_ONLY] = true; @@ -631,19 +656,21 @@ class BasicEntityPersister } 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])) { - // 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]); - } else { + 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); @@ -671,14 +698,6 @@ class BasicEntityPersister $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); $hydrator->hydrateAll($stmt, $this->_rsm, array(Query::HINT_REFRESH => true)); - - if (isset($this->_class->lifecycleCallbacks[Events::postLoad])) { - $this->_class->invokeLifecycleCallbacks(Events::postLoad, $entity); - } - $evm = $this->_em->getEventManager(); - if ($evm->hasListeners(Events::postLoad)) { - $evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em)); - } } /** @@ -697,11 +716,8 @@ class BasicEntityPersister list($params, $types) = $this->expandParameters($criteria); $stmt = $this->_conn->executeQuery($sql, $params, $types); - if ($this->_selectJoinSql) { - $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); - } else { - $hydrator = $this->_em->newHydrator(Query::HYDRATE_SIMPLEOBJECT); - } + $hydrator = $this->_em->newHydrator(($this->_selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + return $hydrator->hydrateAll($stmt, $this->_rsm, array('deferEagerLoads' => true)); } @@ -717,6 +733,7 @@ class BasicEntityPersister public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null) { $stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit); + return $this->loadArrayFromStatement($assoc, $stmt); } @@ -725,6 +742,7 @@ class BasicEntityPersister * * @param array $assoc * @param \Doctrine\DBAL\Statement $stmt + * * @return array */ private function loadArrayFromStatement($assoc, $stmt) @@ -739,6 +757,7 @@ class BasicEntityPersister } $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); + return $hydrator->hydrateAll($stmt, $rsm, $hints); } @@ -748,6 +767,8 @@ class BasicEntityPersister * @param array $assoc * @param \Doctrine\DBAL\Statement $stmt * @param PersistentCollection $coll + * + * @return array */ private function loadCollectionFromStatement($assoc, $stmt, $coll) { @@ -761,7 +782,8 @@ class BasicEntityPersister } $hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT); - $hydrator->hydrateAll($stmt, $rsm, $hints); + + return $hydrator->hydrateAll($stmt, $rsm, $hints); } /** @@ -777,6 +799,7 @@ class BasicEntityPersister public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll) { $stmt = $this->getManyToManyStatement($assoc, $sourceEntity); + return $this->loadCollectionFromStatement($assoc, $stmt, $coll); } @@ -784,12 +807,15 @@ class BasicEntityPersister { $criteria = array(); $sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']); + if ($assoc['isOwningSide']) { $quotedJoinTable = $sourceClass->getQuotedJoinTableName($assoc, $this->_platform); + foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) { 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]]; @@ -807,15 +833,18 @@ class BasicEntityPersister } else { $owningAssoc = $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']]; $quotedJoinTable = $sourceClass->getQuotedJoinTableName($owningAssoc, $this->_platform); + // TRICKY: since the association is inverted source and target are flipped foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) { 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 . "." . $relationKeyColumn] = $value; } else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) { $criteria[$quotedJoinTable . "." . $relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity); @@ -829,6 +858,7 @@ class BasicEntityPersister $sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset); list($params, $types) = $this->expandParameters($criteria); + return $this->_conn->executeQuery($sql, $params, $types); } @@ -847,24 +877,33 @@ class BasicEntityPersister */ protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0, $limit = null, $offset = null, array $orderBy = null) { - $joinSql = $assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY ? - $this->_getSelectManyToManyJoinSQL($assoc) : ''; - + $joinSql = ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) ? $this->_getSelectManyToManyJoinSQL($assoc) : ''; $conditionSql = $this->_getSelectConditionSQL($criteria, $assoc); - $orderBy = ($assoc !== null && isset($assoc['orderBy'])) ? $assoc['orderBy'] : $orderBy; + $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->_class->getQuotedTableName($this->_platform) . ' ' - . $this->_getSQLTableAlias($this->_class->name), $lockMode) + . $alias, $lockMode) . $this->_selectJoinSql . $joinSql . ($conditionSql ? ' WHERE ' . $conditionSql : '') . $orderBySql, $limit, $offset) @@ -881,6 +920,7 @@ class BasicEntityPersister protected final function _getOrderBySQL(array $orderBy, $baseTableAlias) { $orderBySql = ''; + foreach ($orderBy as $fieldName => $orientation) { if ( ! isset($this->_class->fieldMappings[$fieldName])) { throw ORMException::unrecognizedField($fieldName); @@ -896,6 +936,7 @@ class BasicEntityPersister : $baseTableAlias; $columnName = $this->_class->getQuotedColumnName($fieldName, $this->_platform); + $orderBySql .= $orderBySql ? ', ' : ' ORDER BY '; $orderBySql .= $tableAlias . '.' . $columnName . ' ' . $orientation; } @@ -928,20 +969,25 @@ class BasicEntityPersister // 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 } @@ -951,41 +997,53 @@ class BasicEntityPersister 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; } } - $this->_selectJoinSql .= ' LEFT JOIN'; // TODO: Inner join when all join columns are NOT nullable. $first = true; + if ($assoc['isOwningSide']) { - $this->_selectJoinSql .= ' ' . $eagerEntity->table['name'] . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON '; + $this->_selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($assoc['joinColumns']); + $this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON '; + $tableAlias = $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias); foreach ($assoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) { - if (!$first) { + if ( ! $first) { $this->_selectJoinSql .= ' AND '; } - $this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.'.$sourceCol.' = ' . - $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.'.$targetCol.' '; + $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 .= ' ' . $eagerEntity->table['name'] . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON '; + $this->_selectJoinSql .= ' LEFT JOIN'; + $this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' + . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) . ' ON '; foreach ($owningAssoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) { - if (!$first) { + if ( ! $first) { $this->_selectJoinSql .= ' AND '; } - $this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.'.$sourceCol.' = ' . - $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol . ' '; + + $this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = ' + . $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol; $first = false; } } @@ -997,20 +1055,31 @@ class BasicEntityPersister 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 = ''; + if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) { foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { if ($columnList) $columnList .= ', '; - $columnAlias = $srcColumn . $this->_sqlAliasCounter++; - $resultColumnName = $this->_platform->getSQLResultCasing($columnAlias); + $resultColumnName = $this->getSQLColumnAlias($srcColumn); $columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) ) . '.' . $srcColumn . ' AS ' . $resultColumnName; $this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true); } } + return $columnList; } @@ -1032,23 +1101,22 @@ class BasicEntityPersister } $joinTableName = $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform); - $joinSql = ''; + foreach ($joinClauses as $joinTableColumn => $sourceColumn) { if ($joinSql != '') $joinSql .= ' AND '; - if ($this->_class->containsForeignIdentifier && !isset($this->_class->fieldNames[$sourceColumn])) { + if ($this->_class->containsForeignIdentifier && ! isset($this->_class->fieldNames[$sourceColumn])) { $quotedColumn = $sourceColumn; // join columns cannot be quoted } else { $quotedColumn = $this->_class->getQuotedColumnName($this->_class->fieldNames[$sourceColumn], $this->_platform); } - $joinSql .= $this->_getSQLTableAlias($this->_class->name) . - '.' . $quotedColumn . ' = ' - . $joinTableName . '.' . $joinTableColumn; + $joinSql .= $this->_getSQLTableAlias($this->_class->name) . '.' . $quotedColumn . ' = ' + . $joinTableName . '.' . $joinTableColumn; } - return " INNER JOIN $joinTableName ON $joinSql"; + return ' INNER JOIN ' . $joinTableName . ' ON ' . $joinSql; } /** @@ -1061,21 +1129,36 @@ class BasicEntityPersister if ($this->_insertSql === null) { $insertSql = ''; $columns = $this->_getInsertColumnList(); + if (empty($columns)) { $insertSql = $this->_platform->getEmptyIdentityInsertSQL( - $this->_class->getQuotedTableName($this->_platform), - $this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform) + $this->_class->getQuotedTableName($this->_platform), + $this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform) ); } else { $columns = array_unique($columns); - $values = array_fill(0, count($columns), '?'); + + $values = array(); + foreach ($columns AS $column) { + $placeholder = '?'; + + if (isset($this->_columnTypes[$column]) && + isset($this->_class->fieldNames[$column]) && + isset($this->_class->fieldMappings[$this->_class->fieldNames[$column]]['requireSQLConversion'])) { + $type = Type::getType($this->_columnTypes[$column]); + $placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform); + } + + $values[] = $placeholder; + } $insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform) - . ' (' . implode(', ', $columns) . ') ' - . 'VALUES (' . implode(', ', $values) . ')'; + . ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $values) . ')'; } + $this->_insertSql = $insertSql; } + return $this->_insertSql; } @@ -1090,20 +1173,23 @@ class BasicEntityPersister 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['targetToSourceKeyColumns'] as $sourceCol) { $columns[] = $sourceCol; } } - } else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || - $this->_class->identifier[0] != $name) { + } else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->_class->identifier[0] != $name) { $columns[] = $this->_class->getQuotedColumnName($name, $this->_platform); + $this->_columnTypes[$name] = $this->_class->fieldMappings[$name]['type']; } } @@ -1120,12 +1206,18 @@ class BasicEntityPersister */ protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r') { - $columnName = $class->columnNames[$field]; - $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform); - $columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++); + $sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) + . '.' . $class->getQuotedColumnName($field, $this->_platform); + $columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]); + $this->_rsm->addFieldResult($alias, $columnAlias, $field); - return "$sql AS $columnAlias"; + if (isset($class->fieldMappings[$field]['requireSQLConversion'])) { + $type = Type::getType($class->getTypeOfField($field)); + $sql = $type->convertToPHPValueSQL($sql, $this->_platform); + } + + return $sql . ' AS ' . $columnAlias; } /** @@ -1138,15 +1230,17 @@ class BasicEntityPersister protected function _getSQLTableAlias($className, $assocName = '') { if ($assocName) { - $className .= '#'.$assocName; + $className .= '#' . $assocName; } if (isset($this->_sqlTableAliases[$className])) { return $this->_sqlTableAliases[$className]; } + $tableAlias = 't' . $this->_sqlAliasCounter++; $this->_sqlTableAliases[$className] = $tableAlias; + return $tableAlias; } @@ -1170,7 +1264,9 @@ class BasicEntityPersister $sql = 'SELECT 1 ' . $this->_platform->appendLockHint($this->getLockTablesSql(), $lockMode) . ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' ' . $lockSql; + list($params, $types) = $this->expandParameters($criteria); + $stmt = $this->_conn->executeQuery($sql, $params, $types); } @@ -1182,7 +1278,7 @@ class BasicEntityPersister protected function getLockTablesSql() { return 'FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' - . $this->_getSQLTableAlias($this->_class->name); + . $this->_getSQLTableAlias($this->_class->name); } /** @@ -1199,28 +1295,33 @@ class BasicEntityPersister protected function _getSelectConditionSQL(array $criteria, $assoc = null) { $conditionSql = ''; + foreach ($criteria as $field => $value) { $conditionSql .= $conditionSql ? ' AND ' : ''; + $placeholder = '?'; + if (isset($this->_class->columnNames[$field])) { - if (isset($this->_class->fieldMappings[$field]['inherited'])) { - $conditionSql .= $this->_getSQLTableAlias($this->_class->fieldMappings[$field]['inherited']) . '.'; - } else { - $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.'; + $className = (isset($this->_class->fieldMappings[$field]['inherited'])) + ? $this->_class->fieldMappings[$field]['inherited'] + : $this->_class->name; + + $conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->getQuotedColumnName($field, $this->_platform); + + if (isset($this->_class->fieldMappings[$field]['requireSQLConversion'])) { + $type = Type::getType($this->_class->getTypeOfField($field)); + $placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->_platform); } - $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform); } else if (isset($this->_class->associationMappings[$field])) { - if (!$this->_class->associationMappings[$field]['isOwningSide']) { + if ( ! $this->_class->associationMappings[$field]['isOwningSide']) { throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field); } - if (isset($this->_class->associationMappings[$field]['inherited'])) { - $conditionSql .= $this->_getSQLTableAlias($this->_class->associationMappings[$field]['inherited']) . '.'; - } else { - $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.'; - } + $className = (isset($this->_class->associationMappings[$field]['inherited'])) + ? $this->_class->associationMappings[$field]['inherited'] + : $this->_class->name; - $conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name']; + $conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->associationMappings[$field]['joinColumns'][0]['name']; } else if ($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. @@ -1230,7 +1331,8 @@ class BasicEntityPersister } else { throw ORMException::unrecognizedField($field); } - $conditionSql .= (is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ?'); + + $conditionSql .= (is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ' . $placeholder); } return $conditionSql; } @@ -1247,6 +1349,7 @@ class BasicEntityPersister public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null) { $stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit); + return $this->loadArrayFromStatement($assoc, $stmt); } @@ -1262,7 +1365,8 @@ class BasicEntityPersister public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll) { $stmt = $this->getOneToManyStatement($assoc, $sourceEntity); - $this->loadCollectionFromStatement($assoc, $stmt, $coll); + + return $this->loadCollectionFromStatement($assoc, $stmt, $coll); } /** @@ -1280,18 +1384,18 @@ class BasicEntityPersister $owningAssoc = $this->_class->associationMappings[$assoc['mappedBy']]; $sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']); - $tableAlias = isset($owningAssoc['inherited']) ? - $this->_getSQLTableAlias($owningAssoc['inherited']) - : $this->_getSQLTableAlias($this->_class->name); + $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); @@ -1319,17 +1423,96 @@ class BasicEntityPersister continue; // skip null values. } - $type = null; - if (is_array($value)) { - $type = Type::getType( $this->_class->fieldMappings[$field]['type'] )->getBindingType(); - $type += Connection::ARRAY_PARAM_OFFSET; - } else if (isset($this->_class->fieldMappings[$field])) { + $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); } - $params[] = $value; - $types[] = $type; + + return $newValue; } - return array($params, $types); + + 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(get_class($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; } /** @@ -1341,13 +1524,78 @@ class BasicEntityPersister public function exists($entity, array $extraConditions = array()) { $criteria = $this->_class->getIdentifierValues($entity); + if ($extraConditions) { $criteria = array_merge($criteria, $extraConditions); } - $sql = 'SELECT 1 ' . $this->getLockTablesSql() - . ' WHERE ' . $this->_getSelectConditionSQL($criteria); + $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, $types) = $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) + { + // 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. + return $this->_platform->getSQLResultCasing( + substr($columnName . $this->_sqlAliasCounter++, -$this->_platform->getMaxIdentifierLength()) + ); + } + + /** + * 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 . ')'; + } + } - return (bool) $this->_conn->fetchColumn($sql, array_values($criteria)); + $sql = implode(' AND ', $filterClauses); + return $sql ? "(" . $sql . ")" : ""; // Wrap again to avoid "X or Y and FilterConditionSQL" } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Persisters/JoinedSubclassPersister.php b/main/inc/lib/symfony/Doctrine/ORM/Persisters/JoinedSubclassPersister.php index 2410906b41..350ced98bf 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Persisters/JoinedSubclassPersister.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Persisters/JoinedSubclassPersister.php @@ -31,6 +31,7 @@ use Doctrine\ORM\ORMException, * * @author Roman Borschel * @author Benjamin Eberlei + * @author Alexander * @since 2.0 * @see http://martinfowler.com/eaaCatalog/classTableInheritance.html */ @@ -46,7 +47,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister /** * Map of table to quoted table names. - * + * * @var array */ private $_quotedTableMap = array(); @@ -56,11 +57,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister */ protected function _getDiscriminatorColumnTableName() { - if ($this->_class->name == $this->_class->rootEntityName) { - return $this->_class->table['name']; - } else { - return $this->_em->getClassMetadata($this->_class->rootEntityName)->table['name']; - } + $class = ($this->_class->name !== $this->_class->rootEntityName) + ? $this->_em->getClassMetadata($this->_class->rootEntityName) + : $this->_class; + + return $class->getTableName(); } /** @@ -73,8 +74,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister { 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; } @@ -87,19 +90,24 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister */ public function getOwningTable($fieldName) { - if (!isset($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; - } - $this->_owningTableMap[$fieldName] = $cm->table['name']; - $this->_quotedTableMap[$cm->table['name']] = $cm->getQuotedTableName($this->_platform); + if (isset($this->_owningTableMap[$fieldName])) { + return $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] = $cm->getQuotedTableName($this->_platform); + + return $tableName; } /** @@ -116,20 +124,22 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister $isPostInsertId = $idGen->isPostInsertGenerator(); // Prepare statement for the root table - $rootClass = $this->_class->name == $this->_class->rootEntityName ? - $this->_class : $this->_em->getClassMetadata($this->_class->rootEntityName); + $rootClass = ($this->_class->name !== $this->_class->rootEntityName) ? $this->_em->getClassMetadata($this->_class->rootEntityName) : $this->_class; $rootPersister = $this->_em->getUnitOfWork()->getEntityPersister($rootClass->name); - $rootTableName = $rootClass->table['name']; + $rootTableName = $rootClass->getTableName(); $rootTableStmt = $this->_conn->prepare($rootPersister->_getInsertSQL()); // Prepare statements for sub tables. $subTableStmts = array(); + if ($rootClass !== $this->_class) { - $subTableStmts[$this->_class->table['name']] = $this->_conn->prepare($this->_getInsertSQL()); + $subTableStmts[$this->_class->getTableName()] = $this->_conn->prepare($this->_getInsertSQL()); } + foreach ($this->_class->parentClasses as $parentClassName) { $parentClass = $this->_em->getClassMetadata($parentClassName); - $parentTableName = $parentClass->table['name']; + $parentTableName = $parentClass->getTableName(); + if ($parentClass !== $rootClass) { $parentPersister = $this->_em->getUnitOfWork()->getEntityPersister($parentClassName); $subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->_getInsertSQL()); @@ -144,11 +154,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister // Execute insert on root table $paramIndex = 1; - + foreach ($insertData[$rootTableName] as $columnName => $value) { $rootTableStmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]); } - + $rootTableStmt->execute(); if ($isPostInsertId) { @@ -163,22 +173,23 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister 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(); } @@ -201,14 +212,16 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister if (($isVersioned = $this->_class->isVersioned) != false) { $versionedClass = $this->_getVersionedClassMetadata(); - $versionedTable = $versionedClass->table['name']; + $versionedTable = $versionedClass->getTableName(); } if ($updateData) { foreach ($updateData as $tableName => $data) { - $this->_updateTable($entity, $this->_quotedTableMap[$tableName], $data, $isVersioned && $versionedTable == $tableName); + $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])) { @@ -233,14 +246,17 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister // 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->_em->getClassMetadata($this->_class->rootEntityName) - ->getQuotedTableName($this->_platform), $id); + $this->_conn->delete( + $this->_em->getClassMetadata($this->_class->rootEntityName)->getQuotedTableName($this->_platform), $id + ); } else { // Delete from all tables individually, starting from this class' table up to the root table. $this->_conn->delete($this->_class->getQuotedTableName($this->_platform), $id); - + foreach ($this->_class->parentClasses as $parentClass) { - $this->_conn->delete($this->_em->getClassMetadata($parentClass)->getQuotedTableName($this->_platform), $id); + $this->_conn->delete( + $this->_em->getClassMetadata($parentClass)->getQuotedTableName($this->_platform), $id + ); } } } @@ -255,29 +271,33 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister // 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); + + $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; + $tableAlias = isset($assoc2['inherited']) ? $this->_getSQLTableAlias($assoc2['inherited']) : $baseTableAlias; + foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) { if ($columnList != '') $columnList .= ', '; - $columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn, + + $columnList .= $this->getSelectJoinColumnSQL( + $tableAlias, + $srcColumn, isset($assoc2['inherited']) ? $assoc2['inherited'] : $this->_class->name ); } @@ -286,27 +306,27 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#_processSQLResult). $discrColumn = $this->_class->discriminatorColumn['name']; - if ($this->_class->rootEntityName == $this->_class->name) { - $columnList .= ", $baseTableAlias.$discrColumn"; - } else { - $columnList .= ', ' . $this->_getSQLTableAlias($this->_class->rootEntityName) - . ".$discrColumn"; - } + $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 ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON '; $first = true; + foreach ($idColumns as $idColumn) { if ($first) $first = false; else $joinSql .= ' AND '; + $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn; } } @@ -319,19 +339,20 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister if ($this->_selectColumnListSql === null) { // Add subclass columns foreach ($subClass->fieldMappings as $fieldName => $mapping) { - if (isset($mapping['inherited'])) { - continue; - } + 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'])) { + if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE && ! isset($assoc2['inherited'])) { foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) { if ($columnList != '') $columnList .= ', '; - $columnList .= $this->getSelectJoinColumnSQL($tableAlias, $srcColumn, + + $columnList .= $this->getSelectJoinColumnSQL( + $tableAlias, + $srcColumn, isset($assoc2['inherited']) ? $assoc2['inherited'] : $subClass->name ); } @@ -342,17 +363,27 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister // Add LEFT JOIN $joinSql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($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) : ''; + $joinSql .= ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) ? $this->_getSelectManyToManyJoinSQL($assoc) : ''; $conditionSql = $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) : ''; @@ -361,6 +392,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister } $lockSql = ''; + if ($lockMode == LockMode::PESSIMISTIC_READ) { $lockSql = ' ' . $this->_platform->getReadLockSql(); } else if ($lockMode == LockMode::PESSIMISTIC_WRITE) { @@ -386,26 +418,29 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister // INNER JOIN parent tables $joinSql = ''; + foreach ($this->_class->parentClasses as $parentClassName) { $parentClass = $this->_em->getClassMetadata($parentClassName); $tableAlias = $this->_getSQLTableAlias($parentClassName); $joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($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->_class->getQuotedTableName($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() { @@ -448,4 +483,5 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister $value = $this->fetchVersionValue($this->_getVersionedClassMetadata(), $id); $this->_class->setFieldValue($entity, $this->_class->versionField, $value); } + } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Persisters/ManyToManyPersister.php b/main/inc/lib/symfony/Doctrine/ORM/Persisters/ManyToManyPersister.php index ce794781c7..daef03774a 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Persisters/ManyToManyPersister.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Persisters/ManyToManyPersister.php @@ -21,14 +21,17 @@ namespace Doctrine\ORM\Persisters; -use Doctrine\ORM\PersistentCollection, +use Doctrine\ORM\Mapping\ClassMetadata, + Doctrine\ORM\PersistentCollection, Doctrine\ORM\UnitOfWork; /** * Persister for many-to-many collections. * - * @author Roman Borschel - * @since 2.0 + * @author Roman Borschel + * @author Guilherme Blanco + * @author Alexander + * @since 2.0 */ class ManyToManyPersister extends AbstractCollectionPersister { @@ -39,11 +42,11 @@ class ManyToManyPersister extends AbstractCollectionPersister */ protected function _getDeleteRowSQL(PersistentCollection $coll) { - $mapping = $coll->getMapping(); - $joinTable = $mapping['joinTable']; - $columns = $mapping['joinTableColumns']; - - return 'DELETE FROM ' . $joinTable['name'] . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; + $mapping = $coll->getMapping(); + $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); + + return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) + . ' WHERE ' . implode(' = ? AND ', $mapping['joinTableColumns']) . ' = ?'; } /** @@ -76,10 +79,13 @@ class ManyToManyPersister extends AbstractCollectionPersister protected function _getInsertRowSQL(PersistentCollection $coll) { $mapping = $coll->getMapping(); - $joinTable = $mapping['joinTable']; $columns = $mapping['joinTableColumns']; - return 'INSERT INTO ' . $joinTable['name'] . ' (' . implode(', ', $columns) . ')' - . ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')'; + $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); + + $joinTable = $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()); + + return 'INSERT INTO ' . $joinTable . ' (' . implode(', ', $columns) . ')' + . ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')'; } /** @@ -104,8 +110,8 @@ class ManyToManyPersister extends AbstractCollectionPersister */ private function _collectJoinTableColumnParameters(PersistentCollection $coll, $element) { - $params = array(); - $mapping = $coll->getMapping(); + $params = array(); + $mapping = $coll->getMapping(); $isComposite = count($mapping['joinTableColumns']) > 2; $identifier1 = $this->_uow->getEntityIdentifier($coll->getOwner()); @@ -117,27 +123,21 @@ class ManyToManyPersister extends AbstractCollectionPersister } foreach ($mapping['joinTableColumns'] as $joinTableColumn) { - if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) { - if ($isComposite) { - if ($class1->containsForeignIdentifier) { - $params[] = $identifier1[$class1->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])]; - } else { - $params[] = $identifier1[$class1->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]]; - } - } else { - $params[] = array_pop($identifier1); - } - } else { - if ($isComposite) { - if ($class2->containsForeignIdentifier) { - $params[] = $identifier2[$class2->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]; - } else { - $params[] = $identifier2[$class2->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]]; - } - } else { - $params[] = array_pop($identifier2); - } + $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; @@ -150,14 +150,11 @@ class ManyToManyPersister extends AbstractCollectionPersister */ protected function _getDeleteSQL(PersistentCollection $coll) { + $class = $this->_em->getClassMetadata(get_class($coll->getOwner())); $mapping = $coll->getMapping(); - $joinTable = $mapping['joinTable']; - $whereClause = ''; - foreach ($mapping['relationToSourceKeyColumns'] as $relationColumn => $srcColumn) { - if ($whereClause !== '') $whereClause .= ' AND '; - $whereClause .= "$relationColumn = ?"; - } - return 'DELETE FROM ' . $joinTable['name'] . ' WHERE ' . $whereClause; + + return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) + . ' WHERE ' . implode(' = ? AND ', array_keys($mapping['relationToSourceKeyColumns'])) . ' = ?'; } /** @@ -169,16 +166,22 @@ class ManyToManyPersister extends AbstractCollectionPersister */ protected function _getDeleteSQLParameters(PersistentCollection $coll) { - $params = array(); - $mapping = $coll->getMapping(); $identifier = $this->_uow->getEntityIdentifier($coll->getOwner()); - if (count($mapping['relationToSourceKeyColumns']) > 1) { - $sourceClass = $this->_em->getClassMetadata(get_class($mapping->getOwner())); - foreach ($mapping['relationToSourceKeyColumns'] as $relColumn => $srcColumn) { - $params[] = $identifier[$sourceClass->fieldNames[$srcColumn]]; - } - } else { - $params[] = array_pop($identifier); + $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($mapping->getOwner())); + + foreach ($mapping['relationToSourceKeyColumns'] as $relColumn => $srcColumn) { + $params[] = $identifier[$sourceClass->fieldNames[$srcColumn]]; } return $params; @@ -189,36 +192,41 @@ class ManyToManyPersister extends AbstractCollectionPersister */ public function count(PersistentCollection $coll) { - $params = array(); - $mapping = $coll->getMapping(); - $class = $this->_em->getClassMetadata($mapping['sourceEntity']); - $id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner()); + $mapping = $filterMapping = $coll->getMapping(); + $class = $this->_em->getClassMetadata($mapping['sourceEntity']); + $id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner()); if ($mapping['isOwningSide']) { - $joinTable = $mapping['joinTable']; $joinColumns = $mapping['relationToSourceKeyColumns']; } else { $mapping = $this->_em->getClassMetadata($mapping['targetEntity'])->associationMappings[$mapping['mappedBy']]; - $joinTable = $mapping['joinTable']; $joinColumns = $mapping['relationToTargetKeyColumns']; } - $whereClause = ''; + $whereClauses = array(); + $params = array(); + foreach ($mapping['joinTableColumns'] as $joinTableColumn) { - if (isset($joinColumns[$joinTableColumn])) { - if ($whereClause !== '') { - $whereClause .= ' AND '; - } - $whereClause .= "$joinTableColumn = ?"; - - if ($class->containsForeignIdentifier) { - $params[] = $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])]; - } else { - $params[] = $id[$class->fieldNames[$joinColumns[$joinTableColumn]]]; - } + if ( ! isset($joinColumns[$joinTableColumn])) { + continue; } + + $whereClauses[] = $joinTableColumn . ' = ?'; + + $params[] = ($class->containsForeignIdentifier) + ? $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])] + : $id[$class->fieldNames[$joinColumns[$joinTableColumn]]]; } - $sql = 'SELECT count(*) FROM ' . $joinTable['name'] . ' WHERE ' . $whereClause; + + list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping); + if ($filterSql) { + $whereClauses[] = $filterSql; + } + + $sql = 'SELECT COUNT(*)' + . ' FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) . ' t' + . $joinTargetEntitySQL + . ' WHERE ' . implode(' AND ', $whereClauses); return $this->_conn->fetchColumn($sql, $params); } @@ -232,33 +240,84 @@ class ManyToManyPersister extends AbstractCollectionPersister public function slice(PersistentCollection $coll, $offset, $length = null) { $mapping = $coll->getMapping(); - return $this->_em->getUnitOfWork() - ->getEntityPersister($mapping['targetEntity']) - ->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length); + + 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 - if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) { + $entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW); + + if ($entityState === UnitOfWork::STATE_NEW) { return false; } - $params = array(); - $mapping = $coll->getMapping(); + // 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); - if (!$mapping['isOwningSide']) { + $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']); @@ -266,36 +325,101 @@ class ManyToManyPersister extends AbstractCollectionPersister $sourceId = $uow->getEntityIdentifier($coll->getOwner()); $targetId = $uow->getEntityIdentifier($element); } - $joinTable = $mapping['joinTable']; - $whereClause = ''; + $quotedJoinTable = $sourceClass->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()); + $whereClauses = array(); + $params = array(); + foreach ($mapping['joinTableColumns'] as $joinTableColumn) { + $whereClauses[] = $joinTableColumn . ' = ?'; + if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) { - if ($whereClause !== '') { - $whereClause .= ' AND '; - } - $whereClause .= "$joinTableColumn = ?"; - - if ($targetClass->containsForeignIdentifier) { - $params[] = $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]; - } else { - $params[] = $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]]; - } - } else if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) { - if ($whereClause !== '') { - $whereClause .= ' AND '; - } - $whereClause .= "$joinTableColumn = ?"; - - if ($sourceClass->containsForeignIdentifier) { - $params[] = $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])]; - } else { - $params[] = $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$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 ' + . $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform()) . ' 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 = 'SELECT 1 FROM ' . $joinTable['name'] . ' WHERE ' . $whereClause; - return (bool)$this->_conn->fetchColumn($sql, $params); + $sql = implode(' AND ', $filterClauses); + return $sql ? "(" . $sql . ")" : ""; } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Persisters/OneToManyPersister.php b/main/inc/lib/symfony/Doctrine/ORM/Persisters/OneToManyPersister.php index e9fcf06c5c..6f477f08f8 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Persisters/OneToManyPersister.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Persisters/OneToManyPersister.php @@ -1,7 +1,5 @@ - * @todo Remove + * @author Roman Borschel + * @author Guilherme Blanco + * @author Alexander + * @since 2.0 */ class OneToManyPersister extends AbstractCollectionPersister { @@ -48,24 +43,19 @@ class OneToManyPersister extends AbstractCollectionPersister protected function _getDeleteRowSQL(PersistentCollection $coll) { $mapping = $coll->getMapping(); - $targetClass = $this->_em->getClassMetadata($mapping->getTargetEntityName()); - $table = $targetClass->getTableName(); - - $ownerMapping = $targetClass->getAssociationMapping($mapping['mappedBy']); - - $setClause = ''; - foreach ($ownerMapping->sourceToTargetKeyColumns as $sourceCol => $targetCol) { - if ($setClause != '') $setClause .= ', '; - $setClause .= "$sourceCol = NULL"; - } + $class = $this->_em->getClassMetadata($mapping['targetEntity']); - $whereClause = ''; - foreach ($targetClass->getIdentifierColumnNames() as $idColumn) { - if ($whereClause != '') $whereClause .= ' AND '; - $whereClause .= "$idColumn = ?"; - } + return 'DELETE FROM ' . $class->getQuotedTableName($this->_conn->getDatabasePlatform()) + . ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?'; + } - return array("UPDATE $table SET $setClause WHERE $whereClause", $this->_uow->getEntityIdentifier($element)); + /** + * {@inheritdoc} + * + */ + protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element) + { + return array_values($this->_uow->getEntityIdentifier($element)); } protected function _getInsertRowSQL(PersistentCollection $coll) @@ -73,6 +63,16 @@ class OneToManyPersister extends AbstractCollectionPersister 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) { @@ -98,52 +98,38 @@ class OneToManyPersister extends AbstractCollectionPersister protected function _getDeleteSQLParameters(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 - */ - protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element) - {} - - /** - * Gets the SQL parameters for the corresponding SQL statement to delete the given - * element from the given collection. - * - * @param PersistentCollection $coll - * @param mixed $element - */ - protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element) - {} - /** * {@inheritdoc} */ public function count(PersistentCollection $coll) { - $mapping = $coll->getMapping(); + $mapping = $coll->getMapping(); $targetClass = $this->_em->getClassMetadata($mapping['targetEntity']); $sourceClass = $this->_em->getClassMetadata($mapping['sourceEntity']); + $id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner()); - $params = array(); - $id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner()); + $whereClauses = array(); + $params = array(); - $where = ''; foreach ($targetClass->associationMappings[$mapping['mappedBy']]['joinColumns'] AS $joinColumn) { - if ($where != '') { - $where .= ' AND '; - } - $where .= $joinColumn['name'] . " = ?"; - if ($targetClass->containsForeignIdentifier) { - $params[] = $id[$sourceClass->getFieldForColumn($joinColumn['referencedColumnName'])]; - } else { - $params[] = $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]]; + $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 " . $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform()) . " WHERE " . $where; + $sql = 'SELECT count(*)' + . ' FROM ' . $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform()) . ' t' + . ' WHERE ' . implode(' AND ', $whereClauses); + return $this->_conn->fetchColumn($sql, $params); } @@ -155,31 +141,72 @@ class OneToManyPersister extends AbstractCollectionPersister */ public function slice(PersistentCollection $coll, $offset, $length = null) { - $mapping = $coll->getMapping(); - return $this->_em->getUnitOfWork() - ->getEntityPersister($mapping['targetEntity']) - ->getOneToManyCollection($mapping, $coll->getOwner(), $offset, $length); + $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 - if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) { + $entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW); + + if ($entityState === UnitOfWork::STATE_NEW) { return false; } - // 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()) ); + // 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 ' . $class->getQuotedTableName($this->_conn->getDatabasePlatform()) + . ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?'; - return $uow->getEntityPersister($mapping['targetEntity']) - ->exists($element, array($mapping['mappedBy'] => $id)); + return (bool) $this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element)); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Persisters/SingleTablePersister.php b/main/inc/lib/symfony/Doctrine/ORM/Persisters/SingleTablePersister.php index 4af9903663..8644e1d6eb 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Persisters/SingleTablePersister.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Persisters/SingleTablePersister.php @@ -27,6 +27,7 @@ use Doctrine\ORM\Mapping\ClassMetadata; * * @author Roman Borschel * @author Benjamin Eberlei + * @author Alexander * @since 2.0 * @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html */ @@ -35,7 +36,7 @@ class SingleTablePersister extends AbstractEntityInheritancePersister /** {@inheritdoc} */ protected function _getDiscriminatorColumnTableName() { - return $this->_class->table['name']; + return $this->_class->getTableName(); } /** {@inheritdoc} */ @@ -47,30 +48,38 @@ class SingleTablePersister extends AbstractEntityInheritancePersister $columnList = parent::_getSelectColumnListSQL(); - // Append discriminator column - $discrColumn = $this->_class->discriminatorColumn['name']; - $columnList .= ", $discrColumn"; - $rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName); + $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, + + $columnList .= $this->getSelectJoinColumnSQL( + $tableAlias, + $srcColumn, isset($assoc['inherited']) ? $assoc['inherited'] : $this->_class->name ); } @@ -86,6 +95,7 @@ class SingleTablePersister extends AbstractEntityInheritancePersister protected function _getInsertColumnList() { $columns = parent::_getInsertColumnList(); + // Add discriminator column to the INSERT SQL $columns[] = $this->_class->discriminatorColumn['name']; @@ -105,19 +115,32 @@ class SingleTablePersister extends AbstractEntityInheritancePersister // Append discriminator condition if ($conditionSql) $conditionSql .= ' AND '; + $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]); } - $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.' - . $this->_class->discriminatorColumn['name'] - . ' IN (' . implode(', ', $values) . ')'; + + $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.' . $this->_class->discriminatorColumn['name'] + . ' IN (' . implode(', ', $values) . ')'; return $conditionSql; } -} \ No newline at end of file + + /** {@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/main/inc/lib/symfony/Doctrine/ORM/Persisters/UnionSubclassPersister.php b/main/inc/lib/symfony/Doctrine/ORM/Persisters/UnionSubclassPersister.php index b2e683a276..ef844a7067 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Persisters/UnionSubclassPersister.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Persisters/UnionSubclassPersister.php @@ -4,5 +4,5 @@ namespace Doctrine\ORM\Persisters; class UnionSubclassPersister extends BasicEntityPersister { - + } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Proxy/Autoloader.php b/main/inc/lib/symfony/Doctrine/ORM/Proxy/Autoloader.php new file mode 100644 index 0000000000..876b3f2257 --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Proxy/Proxy.php b/main/inc/lib/symfony/Doctrine/ORM/Proxy/Proxy.php index 853f9c1f04..09e2b33eff 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Proxy/Proxy.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Proxy/Proxy.php @@ -1,7 +1,5 @@ * @since 2.0 */ -interface Proxy {} \ No newline at end of file +interface Proxy extends BaseProxy {} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Proxy/ProxyException.php b/main/inc/lib/symfony/Doctrine/ORM/Proxy/ProxyException.php index 892dbebbb5..21964125b5 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Proxy/ProxyException.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Proxy/ProxyException.php @@ -40,4 +40,12 @@ class ProxyException extends \Doctrine\ORM\ORMException { return new self("You must configure a proxy namespace. See docs for details"); } -} \ No newline at end of file + 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/main/inc/lib/symfony/Doctrine/ORM/Proxy/ProxyFactory.php b/main/inc/lib/symfony/Doctrine/ORM/Proxy/ProxyFactory.php index ecade251a0..be94c1dbb1 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Proxy/ProxyFactory.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Proxy/ProxyFactory.php @@ -21,7 +21,8 @@ namespace Doctrine\ORM\Proxy; use Doctrine\ORM\EntityManager, Doctrine\ORM\Mapping\ClassMetadata, - Doctrine\ORM\Mapping\AssociationMapping; + Doctrine\ORM\Mapping\AssociationMapping, + Doctrine\Common\Util\ClassUtils; /** * This factory is used to create proxy objects for entities at runtime. @@ -41,6 +42,14 @@ class ProxyFactory /** 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. @@ -74,13 +83,12 @@ class ProxyFactory */ public function getProxy($className, $identifier) { - $proxyClassName = str_replace('\\', '', $className) . 'Proxy'; - $fqn = $this->_proxyNamespace . '\\' . $proxyClassName; + $fqn = ClassUtils::generateProxyClassName($className, $this->_proxyNamespace); if (! class_exists($fqn, false)) { - $fileName = $this->_proxyDir . DIRECTORY_SEPARATOR . $proxyClassName . '.php'; + $fileName = $this->getProxyFileName($className); if ($this->_autoGenerate) { - $this->_generateProxyClass($this->_em->getClassMetadata($className), $proxyClassName, $fileName, self::$_proxyClassTemplate); + $this->_generateProxyClass($this->_em->getClassMetadata($className), $fileName, self::$_proxyClassTemplate); } require $fileName; } @@ -94,6 +102,22 @@ class ProxyFactory 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. * @@ -101,32 +125,37 @@ class ProxyFactory * @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) . DIRECTORY_SEPARATOR; + $proxyDir = rtrim($proxyDir, DIRECTORY_SEPARATOR); + $num = 0; + foreach ($classes as $class) { /* @var $class ClassMetadata */ - if ($class->isMappedSuperclass) { + if ($class->isMappedSuperclass || $class->reflClass->isAbstract()) { continue; } - $proxyClassName = str_replace('\\', '', $class->name) . 'Proxy'; - $proxyFileName = $proxyDir . $proxyClassName . '.php'; - $this->_generateProxyClass($class, $proxyClassName, $proxyFileName, self::$_proxyClassTemplate); + $proxyFileName = $this->getProxyFileName($class->name, $proxyDir); + + $this->_generateProxyClass($class, $proxyFileName, self::$_proxyClassTemplate); + $num++; } + + return $num; } /** * Generates a proxy class file. * * @param $class - * @param $originalClassName * @param $proxyClassName * @param $file The path of the file to write to. */ - private function _generateProxyClass($class, $proxyClassName, $fileName, $file) + private function _generateProxyClass($class, $fileName, $file) { $methods = $this->_generateMethods($class); $sleepImpl = $this->_generateSleep($class); @@ -138,16 +167,19 @@ class ProxyFactory '', '', '' ); - if(substr($class->name, 0, 1) == "\\") { - $className = substr($class->name, 1); - } else { - $className = $class->name; - } + $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( - $this->_proxyNamespace, - $proxyClassName, $className, - $methods, $sleepImpl, $cloneImpl + $proxyClassNamespace, + $proxyClassName, + $className, + $methods, + $sleepImpl, + $cloneImpl ); $file = str_replace($placeholders, $replacements, $file); @@ -211,6 +243,15 @@ class ProxyFactory $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"; @@ -220,6 +261,44 @@ class ProxyFactory 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, $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. * @@ -290,7 +369,13 @@ class extends \ implements \Doctrine\ORM\Proxy\Proxy unset($this->_entityPersister, $this->_identifier); } } - + + /** @private */ + public function __isInitialized() + { + return $this->__isInitialized__; + } + public function __sleep() diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query.php b/main/inc/lib/symfony/Doctrine/ORM/Query.php index 5d585bc1f8..16c6c38039 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query.php @@ -198,30 +198,37 @@ final class Query extends AbstractQuery */ private function _parse() { - if ($this->_state === self::STATE_CLEAN) { + // 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())) { - $hash = $this->_getQueryCacheId(); - $cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash); - - if ($cached === false) { - // Cache miss. - $parser = new Parser($this); - $this->_parserResult = $parser->parse(); - $queryCache->save($hash, $this->_parserResult, $this->_queryCacheTTL); - } else { - // Cache hit. - $this->_parserResult = $cached; - } - } else { + if ( ! ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver()))) { $parser = new Parser($this); $this->_parserResult = $parser->parse(); + + return $this->_parserResult; } - $this->_state = self::STATE_CLEAN; + $hash = $this->_getQueryCacheId(); + $cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash); + + if ($cached !== false) { + // 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; } @@ -233,6 +240,10 @@ final class Query extends AbstractQuery { $executor = $this->_parse()->getSqlExecutor(); + if ($this->_queryCacheProfile) { + $executor->setQueryCacheProfile($this->_queryCacheProfile); + } + // Prepare parameters $paramMappings = $this->_parserResult->getParameterMappings(); @@ -271,7 +282,8 @@ final class Query extends AbstractQuery } $sqlPositions = $paramMappings[$key]; - $value = array_values($this->processParameterValue($value)); + // 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++) { @@ -294,38 +306,6 @@ final class Query extends AbstractQuery return array($sqlParams, $types); } - /** - * Process an individual parameter value - * - * @param mixed $value - * @return array - */ - private function processParameterValue($value) - { - if (is_array($value)) { - for ($i = 0, $l = count($value); $i < $l; $i++) { - $paramValue = $this->processParameterValue($value[$i]); - - // TODO: What about Entities that have composite primary key? - $value[$i] = is_array($paramValue) ? $paramValue[key($paramValue)] : $paramValue; - } - - return array($value); - } - - if ( ! (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value)))) { - return array($value); - } - - if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) { - return array_values($this->_em->getUnitOfWork()->getEntityIdentifier($value)); - } - - $class = $this->_em->getClassMetadata(get_class($value)); - - return array_values($class->getIdentifierValues($value)); - } - /** * Defines a cache driver to be used for caching queries. * @@ -335,6 +315,7 @@ final class Query extends AbstractQuery public function setQueryCacheDriver($queryCache) { $this->_queryCache = $queryCache; + return $this; } @@ -347,6 +328,7 @@ final class Query extends AbstractQuery public function useQueryCache($bool) { $this->_useQueryCache = $bool; + return $this; } @@ -360,9 +342,9 @@ final class Query extends AbstractQuery { if ($this->_queryCache) { return $this->_queryCache; - } else { - return $this->_em->getConfiguration()->getQueryCacheImpl(); } + + return $this->_em->getConfiguration()->getQueryCacheImpl(); } /** @@ -376,6 +358,7 @@ final class Query extends AbstractQuery if ($timeToLive !== null) { $timeToLive = (int) $timeToLive; } + $this->_queryCacheTTL = $timeToLive; return $this; @@ -420,6 +403,7 @@ final class Query extends AbstractQuery public function free() { parent::free(); + $this->_dql = null; $this->_state = self::STATE_CLEAN; } @@ -436,6 +420,7 @@ final class Query extends AbstractQuery $this->_dql = $dqlQuery; $this->_state = self::STATE_DIRTY; } + return $this; } @@ -485,6 +470,7 @@ final class Query extends AbstractQuery { $this->_firstResult = $firstResult; $this->_state = self::STATE_DIRTY; + return $this; } @@ -509,6 +495,7 @@ final class Query extends AbstractQuery { $this->_maxResults = $maxResults; $this->_state = self::STATE_DIRTY; + return $this; } @@ -529,11 +516,12 @@ final class Query extends AbstractQuery * * @param array $params The query parameters. * @param integer $hydrationMode The hydration mode to use. - * @return IterableResult + * @return \Doctrine\ORM\Internal\Hydration\IterableResult */ public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT) { $this->setHint(self::HINT_INTERNAL_ITERATION, true); + return parent::iterate($params, $hydrationMode); } @@ -543,6 +531,7 @@ final class Query extends AbstractQuery public function setHint($name, $value) { $this->_state = self::STATE_DIRTY; + return parent::setHint($name, $value); } @@ -552,6 +541,7 @@ final class Query extends AbstractQuery public function setHydrationMode($hydrationMode) { $this->_state = self::STATE_DIRTY; + return parent::setHydrationMode($hydrationMode); } @@ -564,13 +554,14 @@ final class Query extends AbstractQuery */ public function setLockMode($lockMode) { - if ($lockMode == LockMode::PESSIMISTIC_READ || $lockMode == LockMode::PESSIMISTIC_WRITE) { - if (!$this->_em->getConnection()->isTransactionActive()) { + if ($lockMode === LockMode::PESSIMISTIC_READ || $lockMode === LockMode::PESSIMISTIC_WRITE) { + if ( ! $this->_em->getConnection()->isTransactionActive()) { throw TransactionRequiredException::transactionRequired(); } } $this->setHint(self::HINT_LOCK_MODE, $lockMode); + return $this; } @@ -582,9 +573,11 @@ final class Query extends AbstractQuery public function getLockMode() { $lockMode = $this->getHint(self::HINT_LOCK_MODE); - if (!$lockMode) { + + if ( ! $lockMode) { return LockMode::NONE; } + return $lockMode; } @@ -601,6 +594,7 @@ final class Query extends AbstractQuery 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' ); @@ -614,6 +608,7 @@ final class Query extends AbstractQuery public function __clone() { parent::__clone(); + $this->_state = self::STATE_DIRTY; } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/ArithmeticFactor.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/ArithmeticFactor.php index b559e4a306..3ad6abf474 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/ArithmeticFactor.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/ArithmeticFactor.php @@ -38,7 +38,7 @@ class ArithmeticFactor extends Node * @var ArithmeticPrimary */ public $arithmeticPrimary; - + /** * @var null|boolean NULL represents no sign, TRUE means positive and FALSE means negative sign */ diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/CoalesceExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/CoalesceExpression.php index 338d49fcee..dae0742004 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/CoalesceExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/CoalesceExpression.php @@ -33,13 +33,13 @@ namespace Doctrine\ORM\Query\AST; 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/main/inc/lib/symfony/Doctrine/ORM/Query/AST/CollectionMemberExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/CollectionMemberExpression.php index ea252de080..62d756b882 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/CollectionMemberExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/CollectionMemberExpression.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ - + namespace Doctrine\ORM\Query\AST; /** diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/DeleteStatement.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/DeleteStatement.php index de807abaae..01c6acbe18 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/DeleteStatement.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/DeleteStatement.php @@ -41,7 +41,7 @@ class DeleteStatement extends Node { $this->deleteClause = $deleteClause; } - + public function dispatch($sqlWalker) { return $sqlWalker->walkDeleteStatement($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/EmptyCollectionComparisonExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/EmptyCollectionComparisonExpression.php index 271d304dc9..6bb50e87d1 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/EmptyCollectionComparisonExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/EmptyCollectionComparisonExpression.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ - + namespace Doctrine\ORM\Query\AST; /** diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/FromClause.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/FromClause.php index 83aa85ccbf..a4dc6282d5 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/FromClause.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/FromClause.php @@ -36,8 +36,8 @@ class FromClause extends Node public function __construct(array $identificationVariableDeclarations) { $this->identificationVariableDeclarations = $identificationVariableDeclarations; - } - + } + public function dispatch($sqlWalker) { return $sqlWalker->walkFromClause($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/AbsFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/AbsFunction.php index 3fafccd5b1..3ee4360356 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/AbsFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/AbsFunction.php @@ -53,9 +53,9 @@ class AbsFunction extends FunctionNode { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/BitAndFunction.php new file mode 100644 index 0000000000..1ee8233377 --- /dev/null +++ b/main/inc/lib/symfony/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 ")" + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @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); + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/BitOrFunction.php new file mode 100644 index 0000000000..ba36e97aaa --- /dev/null +++ b/main/inc/lib/symfony/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 ")" + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @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); + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php index 7bf7683ebc..66107cc007 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php @@ -16,7 +16,7 @@ * and is licensed under the LGPL. For more information, see * . */ - + namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\Lexer; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php new file mode 100644 index 0000000000..1b75929907 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php @@ -0,0 +1,68 @@ +. + */ + +namespace Doctrine\ORM\Query\AST\Functions; + +use Doctrine\ORM\Query\Lexer; + +/** + * "IDENTITY" "(" SingleValuedAssociationPathExpression ")" + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @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) + { + $platform = $sqlWalker->getConnection()->getDatabasePlatform(); + $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/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LengthFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LengthFunction.php index 36787786d5..82dd4b49dc 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LengthFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LengthFunction.php @@ -53,9 +53,9 @@ class LengthFunction extends FunctionNode { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->stringPrimary = $parser->StringPrimary(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LocateFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LocateFunction.php index a4ea716960..e630b2efe8 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LocateFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LocateFunction.php @@ -61,20 +61,20 @@ class LocateFunction extends FunctionNode { $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/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LowerFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LowerFunction.php index 775f51d9a0..7bc092dad9 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LowerFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/LowerFunction.php @@ -53,9 +53,9 @@ class LowerFunction extends FunctionNode { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->stringPrimary = $parser->StringPrimary(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/ModFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/ModFunction.php index 4d124fe851..53f064a903 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/ModFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/ModFunction.php @@ -55,13 +55,13 @@ class ModFunction extends FunctionNode { $parser->match(Lexer::T_MOD); $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/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SizeFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SizeFunction.php index c66df6a8b2..3decb918e4 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SizeFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SizeFunction.php @@ -45,7 +45,7 @@ class SizeFunction extends FunctionNode $platform = $sqlWalker->getConnection()->getDatabasePlatform(); $dqlAlias = $this->collectionPathExpression->identificationVariable; $assocField = $this->collectionPathExpression->field; - + $qComp = $sqlWalker->getQueryComponent($dqlAlias); $class = $qComp['metadata']; $assoc = $class->associationMappings[$assocField]; @@ -53,15 +53,15 @@ class SizeFunction extends FunctionNode if ($assoc['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY) { $targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']); - $targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->table['name']); - $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->table['name'], $dqlAlias); + $targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->getTableName()); + $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); $sql .= $targetClass->getQuotedTableName($platform) . ' ' . $targetTableAlias . ' WHERE '; $owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']]; $first = true; - + foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) { if ($first) $first = false; else $sql .= ' AND '; @@ -77,7 +77,7 @@ class SizeFunction extends FunctionNode // SQL table aliases $joinTableAlias = $sqlWalker->getSQLTableAlias($joinTable['name']); - $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->table['name'], $dqlAlias); + $sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); // join to target table $sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $platform) . ' ' . $joinTableAlias . ' WHERE '; @@ -100,7 +100,7 @@ class SizeFunction extends FunctionNode . $sourceTableAlias . '.' . $sourceColumnName; } } - + return '(' . $sql . ')'; } @@ -110,12 +110,12 @@ class SizeFunction extends FunctionNode public function parse(\Doctrine\ORM\Query\Parser $parser) { $lexer = $parser->getLexer(); - + $parser->match(Lexer::T_SIZE); $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->collectionPathExpression = $parser->CollectionValuedPathExpression(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php index 02ffa26a7d..087b93be10 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php @@ -52,9 +52,9 @@ class SqrtFunction extends FunctionNode { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php index bfcbdefb30..c0e6223b26 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php @@ -64,15 +64,15 @@ class SubstringFunction extends FunctionNode $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(); } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/UpperFunction.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/UpperFunction.php index acc8dd8ebd..16a0ed8161 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/UpperFunction.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Functions/UpperFunction.php @@ -53,9 +53,9 @@ class UpperFunction extends FunctionNode { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->stringPrimary = $parser->StringPrimary(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/GeneralCaseExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/GeneralCaseExpression.php new file mode 100644 index 0000000000..facacd5fe2 --- /dev/null +++ b/main/inc/lib/symfony/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 + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @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); + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php index bf168c34b9..2f590cc80c 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php @@ -44,7 +44,7 @@ class IdentificationVariableDeclaration extends Node $this->indexBy = $indexBy; $this->joinVariableDeclarations = $joinVariableDecls; } - + public function dispatch($sqlWalker) { return $sqlWalker->walkIdentificationVariableDeclaration($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/InExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/InExpression.php index b1da40156d..15c517dc06 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/InExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/InExpression.php @@ -35,13 +35,13 @@ namespace Doctrine\ORM\Query\AST; class InExpression extends Node { public $not; - public $pathExpression; + public $expression; public $literals = array(); public $subselect; - public function __construct($pathExpression) + public function __construct($expression) { - $this->pathExpression = $pathExpression; + $this->expression = $expression; } public function dispatch($sqlWalker) diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/IndexBy.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/IndexBy.php index b657be70fc..16f2206309 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/IndexBy.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/IndexBy.php @@ -39,8 +39,8 @@ class IndexBy extends Node public function __construct($simpleStateFieldPathExpression) { $this->simpleStateFieldPathExpression = $simpleStateFieldPathExpression; - } - + } + public function dispatch($sqlWalker) { return $sqlWalker->walkIndexBy($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/InstanceOfExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/InstanceOfExpression.php index 3aefd61d92..4f254b578b 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/InstanceOfExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/InstanceOfExpression.php @@ -20,7 +20,8 @@ namespace Doctrine\ORM\Query\AST; /** - * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (AbstractSchemaName | InputParameter) + * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")") + * InstanceOfParameter ::= AbstractSchemaName | InputParameter * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org @@ -35,7 +36,7 @@ class InstanceOfExpression extends Node public $not; public $identificationVariable; public $value; - + public function __construct($identVariable) { $this->identificationVariable = $identVariable; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Join.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Join.php index 310a418a45..084f7d7376 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Join.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Join.php @@ -39,7 +39,7 @@ class Join extends Node const JOIN_TYPE_LEFTOUTER = 2; const JOIN_TYPE_INNER = 3; - public $joinType = self::JOIN_TYPE_INNER; + public $joinType = self::JOIN_TYPE_INNER; public $joinAssociationPathExpression = null; public $aliasIdentificationVariable = null; public $conditionalExpression = null; @@ -50,7 +50,7 @@ class Join extends Node $this->joinAssociationPathExpression = $joinAssocPathExpr; $this->aliasIdentificationVariable = $aliasIdentVar; } - + public function dispatch($sqlWalker) { return $sqlWalker->walkJoin($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/JoinAssociationPathExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/JoinAssociationPathExpression.php index 7f87e52f89..f9300b2ede 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/JoinAssociationPathExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/JoinAssociationPathExpression.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ - + namespace Doctrine\ORM\Query\AST; /** diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php index 687eba38d4..7fa9562223 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php @@ -42,7 +42,7 @@ class JoinVariableDeclaration extends Node $this->join = $join; $this->indexBy = $indexBy; } - + public function dispatch($sqlWalker) { return $sqlWalker->walkJoinVariableDeclaration($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Literal.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Literal.php index d3acb96255..426907f6d7 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Literal.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Literal.php @@ -7,16 +7,16 @@ 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); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Node.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Node.php index adaf06caec..8ef13c0b53 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Node.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Node.php @@ -36,16 +36,16 @@ 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 * @@ -55,36 +55,36 @@ abstract class Node { 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 . '": ' + $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) . '"' + $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)) { @@ -92,7 +92,7 @@ abstract class Node } else { $str .= var_export($obj, true); } - + return $str; } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/NullComparisonExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/NullComparisonExpression.php index aa205b7126..0e64bd2fbc 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/NullComparisonExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/NullComparisonExpression.php @@ -36,7 +36,7 @@ class NullComparisonExpression extends Node { public $not; public $expression; - + public function __construct($expression) { $this->expression = $expression; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/NullIfExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/NullIfExpression.php index c79d23a99e..12c8c140fd 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/NullIfExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/NullIfExpression.php @@ -33,15 +33,15 @@ namespace Doctrine\ORM\Query\AST; 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/main/inc/lib/symfony/Doctrine/ORM/Query/AST/OrderByItem.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/OrderByItem.php index a05bac32b0..207cbd3699 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/OrderByItem.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/OrderByItem.php @@ -36,7 +36,7 @@ class OrderByItem extends Node { public $expression; public $type; - + public function __construct($expression) { $this->expression = $expression; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/PartialObjectExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/PartialObjectExpression.php index 08fd564f2f..d1757d7909 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/PartialObjectExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/PartialObjectExpression.php @@ -6,7 +6,7 @@ class PartialObjectExpression extends Node { public $identificationVariable; public $partialFieldSet; - + public function __construct($identificationVariable, array $partialFieldSet) { $this->identificationVariable = $identificationVariable; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/PathExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/PathExpression.php index 45042c2ea2..2f78b9c26b 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/PathExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/PathExpression.php @@ -16,7 +16,7 @@ * and is licensed under the LGPL. For more information, see * . */ - + namespace Doctrine\ORM\Query\AST; /** @@ -27,7 +27,7 @@ namespace Doctrine\ORM\Query\AST; * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField * StateField ::= {EmbeddedClassStateField "."}* SimpleStateField * SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField - * + * * @since 2.0 * @author Guilherme Blanco * @author Jonathan Wage @@ -38,19 +38,19 @@ 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/main/inc/lib/symfony/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php index 7a01bdcbe8..cf8b180206 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php @@ -41,8 +41,8 @@ class RangeVariableDeclaration extends Node { $this->abstractSchemaName = $abstractSchemaName; $this->aliasIdentificationVariable = $aliasIdentificationVar; - } - + } + public function dispatch($walker) { return $walker->walkRangeVariableDeclaration($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectClause.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectClause.php index ed9fbaa348..cf8e9df301 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectClause.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectClause.php @@ -42,7 +42,7 @@ class SelectClause extends Node $this->isDistinct = $isDistinct; $this->selectExpressions = $selectExpressions; } - + public function dispatch($sqlWalker) { return $sqlWalker->walkSelectClause($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectExpression.php index f1793f0c46..fd0d49b286 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectExpression.php @@ -23,7 +23,7 @@ namespace Doctrine\ORM\Query\AST; /** * SelectExpression ::= IdentificationVariable ["." "*"] | StateFieldPathExpression | - * (AggregateExpression | "(" Subselect ")") [["AS"] FieldAliasIdentificationVariable] + * (AggregateExpression | "(" Subselect ")") [["AS"] ["HIDDEN"] FieldAliasIdentificationVariable] * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org @@ -37,13 +37,15 @@ class SelectExpression extends Node { public $expression; public $fieldIdentificationVariable; + public $hiddenAliasResultVariable; - public function __construct($expression, $fieldIdentificationVariable) + 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/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectStatement.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectStatement.php index 01eed37d02..d65a97befc 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectStatement.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SelectStatement.php @@ -44,8 +44,8 @@ class SelectStatement extends Node public function __construct($selectClause, $fromClause) { $this->selectClause = $selectClause; $this->fromClause = $fromClause; - } - + } + public function dispatch($sqlWalker) { return $sqlWalker->walkSelectStatement($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleCaseExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleCaseExpression.php new file mode 100644 index 0000000000..586928df3c --- /dev/null +++ b/main/inc/lib/symfony/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 + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @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); + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleSelectClause.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleSelectClause.php index e3b93e7f63..8a4028036c 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleSelectClause.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleSelectClause.php @@ -42,7 +42,7 @@ class SimpleSelectClause extends Node $this->simpleSelectExpression = $simpleSelectExpression; $this->isDistinct = $isDistinct; } - + public function dispatch($sqlWalker) { return $sqlWalker->walkSimpleSelectClause($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleSelectExpression.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleSelectExpression.php index e25d38bfc2..1648c4dc57 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleSelectExpression.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleSelectExpression.php @@ -41,8 +41,8 @@ class SimpleSelectExpression extends Node public function __construct($expression) { $this->expression = $expression; - } - + } + public function dispatch($sqlWalker) { return $sqlWalker->walkSimpleSelectExpression($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleWhenClause.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleWhenClause.php new file mode 100644 index 0000000000..0345328a66 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SimpleWhenClause.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression + * + * @since 2.2 + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @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); + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Subselect.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Subselect.php index fa5d3356aa..548e42ba74 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Subselect.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/Subselect.php @@ -45,8 +45,8 @@ class Subselect extends Node { $this->simpleSelectClause = $simpleSelectClause; $this->subselectFromClause = $subselectFromClause; - } - + } + public function dispatch($sqlWalker) { return $sqlWalker->walkSubselect($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SubselectFromClause.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SubselectFromClause.php index 44d2b59888..c7c2f35f8c 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SubselectFromClause.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/SubselectFromClause.php @@ -39,8 +39,8 @@ class SubselectFromClause extends Node public function __construct(array $identificationVariableDeclarations) { $this->identificationVariableDeclarations = $identificationVariableDeclarations; - } - + } + public function dispatch($sqlWalker) { return $sqlWalker->walkSubselectFromClause($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/UpdateStatement.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/UpdateStatement.php index 7bf40bbc64..d1e152ea25 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/UpdateStatement.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/UpdateStatement.php @@ -46,4 +46,4 @@ class UpdateStatement extends Node { return $sqlWalker->walkUpdateStatement($this); } -} \ No newline at end of file +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/AST/WhenClause.php b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/WhenClause.php new file mode 100644 index 0000000000..69556e5be7 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/AST/WhenClause.php @@ -0,0 +1,48 @@ +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression + * + * @since 2.2 + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @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); + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php index fdec02115e..d639223485 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php @@ -1,7 +1,5 @@ _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); + abstract public function execute(Connection $conn, array $params, array $types); } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php index 22edeca410..51f4b8c5b1 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/MultiTableDeleteExecutor.php @@ -1,7 +1,5 @@ MultiTableDeleteExecutor. * @@ -63,11 +60,11 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor $idColumnList = implode(', ', $idColumnNames); // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() - $sqlWalker->setSQLTableAlias($primaryClass->table['name'], 't0', $primaryDqlAlias); + $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); @@ -87,7 +84,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor $this->_sqlStatements[] = 'DELETE FROM ' . $tableName . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')'; } - + // 4. Store DDL for temporary identifier table. $columnDefinitions = array(); foreach ($idColumnNames as $idColumnName) { @@ -102,11 +99,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor } /** - * Executes all SQL statements. - * - * @param \Doctrine\DBAL\Connection $conn The database connection that is used to execute the queries. - * @param array $params The parameters. - * @override + * {@inheritDoc} */ public function execute(Connection $conn, array $params, array $types) { diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php index 02a9b459c7..8be24e5557 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/MultiTableUpdateExecutor.php @@ -64,7 +64,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor $idColumnList = implode(', ', $idColumnNames); // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() - $sqlWalker->setSQLTableAlias($primaryClass->table['name'], 't0', $updateClause->aliasIdentificationVariable); + $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $updateClause->aliasIdentificationVariable); $this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')' . ' SELECT t0.' . implode(', t0.', $idColumnNames); @@ -80,7 +80,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor // 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); @@ -88,27 +88,27 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor 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) { $paramKey = $newValue->name; $this->_sqlParameters[$i]['parameters'][] = $sqlWalker->getQuery()->getParameter($paramKey); $this->_sqlParameters[$i]['types'][] = $sqlWalker->getQuery()->getParameterType($paramKey); - + ++$this->_numParametersInUpdateClause; } } @@ -118,12 +118,12 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor $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(); @@ -133,19 +133,15 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor 'type' => Type::getType($rootClass->getTypeOfColumn($idColumnName)) ); } - + $this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; - + $this->_dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable); } /** - * Executes all SQL statements. - * - * @param Connection $conn The database connection that is used to execute the queries. - * @param array $params The parameters. - * @override + * {@inheritDoc} */ public function execute(Connection $conn, array $params, array $types) { @@ -156,8 +152,8 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor // Insert identifiers. Parameters from the update clause are cut off. $numUpdated = $conn->executeUpdate( - $this->_insertSql, - array_slice($params, $this->_numParametersInUpdateClause), + $this->_insertSql, + array_slice($params, $this->_numParametersInUpdateClause), array_slice($types, $this->_numParametersInUpdateClause) ); @@ -165,12 +161,12 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor 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); } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/SingleSelectExecutor.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/SingleSelectExecutor.php index 4e08e0f9cf..61c42d828e 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/SingleSelectExecutor.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/SingleSelectExecutor.php @@ -1,7 +1,5 @@ - * @version $Revision$ * @link www.doctrine-project.org * @since 2.0 */ @@ -41,8 +38,11 @@ class SingleSelectExecutor extends AbstractSqlExecutor $this->_sqlStatements = $sqlWalker->walkSelectStatement($AST); } + /** + * {@inheritDoc} + */ public function execute(Connection $conn, array $params, array $types) { - return $conn->executeQuery($this->_sqlStatements, $params, $types); + return $conn->executeQuery($this->_sqlStatements, $params, $types, $this->queryCacheProfile); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/SingleTableDeleteUpdateExecutor.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/SingleTableDeleteUpdateExecutor.php index 94db13b055..467ce54602 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/SingleTableDeleteUpdateExecutor.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Exec/SingleTableDeleteUpdateExecutor.php @@ -1,7 +1,5 @@ - * @version $Revision$ * @link www.doctrine-project.org * @since 2.0 - * @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor. + * @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor. */ class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor { @@ -45,7 +42,10 @@ class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor $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/main/inc/lib/symfony/Doctrine/ORM/Query/Expr.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr.php index b040af1659..adcd25cda6 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr.php @@ -40,10 +40,12 @@ class Expr * * [php] * // (u.type = ?1) AND (u.role = ?2) - * $expr->andX('u.type = ?1', 'u.role = ?2')); + * $expr->andX($expr->eq('u.type', ':1'), $expr->eq('u.role', ':2')); * - * @param mixed $x Optional clause. Defaults = null, but requires - * at least one defined when converting to string. + * @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) @@ -560,6 +562,8 @@ class Expr { if (is_numeric($literal) && !is_string($literal)) { return (string) $literal; + } else if (is_bool($literal)) { + return $literal ? "true" : "false"; } else { return "'" . str_replace("'", "''", $literal) . "'"; } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Andx.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Andx.php index c26055c2af..c5cf1f3ab9 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Andx.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Andx.php @@ -39,5 +39,6 @@ class Andx extends Composite 'Doctrine\ORM\Query\Expr\Comparison', 'Doctrine\ORM\Query\Expr\Func', 'Doctrine\ORM\Query\Expr\Orx', + 'Doctrine\ORM\Query\Expr\Andx', ); } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Base.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Base.php index abe7e54beb..975d450cd4 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Base.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Base.php @@ -45,17 +45,19 @@ abstract class Base { $this->addMultiple($args); } - + public function addMultiple($args = array()) { foreach ((array) $args as $arg) { $this->add($arg); } + + return $this; } public function add($arg) { - if ( $arg !== null || ($arg instanceof self && $arg->count() > 0)) { + 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); @@ -67,6 +69,8 @@ abstract class Base $this->_parts[] = $arg; } + + return $this; } public function count() @@ -79,7 +83,7 @@ abstract class Base if ($this->count() == 1) { return (string) $this->_parts[0]; } - + return $this->_preSeparator . implode($this->_separator, $this->_parts) . $this->_postSeparator; } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Comparison.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Comparison.php index 7fcd263a27..d42560eb79 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Comparison.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Comparison.php @@ -40,7 +40,7 @@ class Comparison const LTE = '<='; const GT = '>'; const GTE = '>='; - + private $_leftExpr; private $_operator; private $_rightExpr; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Composite.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Composite.php index d496c6014f..036b241a5f 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Composite.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Composite.php @@ -65,4 +65,4 @@ class Composite extends Base return $queryPart; } -} +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/From.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/From.php index 6646e1de2b..e5707cce63 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/From.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/From.php @@ -34,27 +34,55 @@ namespace Doctrine\ORM\Query\Expr; */ class From { + /** + * @var string + */ private $_from; + + /** + * @var string + */ private $_alias; - public function __construct($from, $alias) + /** + * @var string + */ + private $_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->_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 __toString() { - return $this->_from . ' ' . $this->_alias; + return $this->_from . ' ' . $this->_alias . + ($this->_indexBy ? ' INDEX BY ' . $this->_indexBy : ''); } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Join.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Join.php index 54ad6ead79..14f5b43cd8 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Join.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Join.php @@ -36,10 +36,10 @@ class Join { const INNER_JOIN = 'INNER'; const LEFT_JOIN = 'LEFT'; - + const ON = 'ON'; const WITH = 'WITH'; - + private $_joinType; private $_join; private $_alias; diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Math.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Math.php index c6135c8662..e7e8b329c8 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Math.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Math.php @@ -49,18 +49,18 @@ class Math { // 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; } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Orx.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Orx.php index 7eb66535c3..742e499f79 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Orx.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Expr/Orx.php @@ -36,8 +36,9 @@ class Orx extends Composite { protected $_separator = ' OR '; protected $_allowedClasses = array( - 'Doctrine\ORM\Query\Expr\Andx', 'Doctrine\ORM\Query\Expr\Comparison', 'Doctrine\ORM\Query\Expr\Func', + 'Doctrine\ORM\Query\Expr\Andx', + 'Doctrine\ORM\Query\Expr\Orx', ); } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Filter/SQLFilter.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Filter/SQLFilter.php new file mode 100644 index 0000000000..a87dd841eb --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Query/FilterCollection.php b/main/inc/lib/symfony/Doctrine/ORM/Query/FilterCollection.php new file mode 100644 index 0000000000..35c8d043cc --- /dev/null +++ b/main/inc/lib/symfony/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/main/inc/lib/symfony/Doctrine/ORM/Query/Lexer.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Lexer.php index 70c8b7db6a..1eef6afebd 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Lexer.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Lexer.php @@ -49,7 +49,7 @@ class Lexer extends \Doctrine\Common\Lexer 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; @@ -67,46 +67,50 @@ class Lexer extends \Doctrine\Common\Lexer const T_DELETE = 113; const T_DESC = 114; const T_DISTINCT = 115; - const T_EMPTY = 116; - const T_ESCAPE = 117; - const T_EXISTS = 118; - const T_FALSE = 119; - const T_FROM = 120; - const T_GROUP = 121; - const T_HAVING = 122; - const T_IN = 123; - const T_INDEX = 124; - const T_INNER = 125; - const T_INSTANCE = 126; - const T_IS = 127; - const T_JOIN = 128; - const T_LEADING = 129; - const T_LEFT = 130; - const T_LIKE = 131; - const T_MAX = 132; - const T_MEMBER = 133; - const T_MIN = 134; - const T_NOT = 135; - const T_NULL = 136; - const T_NULLIF = 137; - const T_OF = 138; - const T_OR = 139; - const T_ORDER = 140; - const T_OUTER = 141; - const T_SELECT = 142; - const T_SET = 143; - const T_SIZE = 144; - const T_SOME = 145; - const T_SUM = 146; - const T_TRAILING = 147; - const T_TRUE = 148; - const T_UPDATE = 149; - const T_WHEN = 150; - const T_WHERE = 151; - const T_WITH = 153; - const T_PARTIAL = 154; - const T_MOD = 155; - + 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_SIZE = 147; + const T_SOME = 148; + const T_SUM = 149; + const T_THEN = 150; + const T_TRAILING = 151; + const T_TRUE = 152; + const T_UPDATE = 153; + const T_WHEN = 154; + const T_WHERE = 155; + const T_WITH = 156; + const T_PARTIAL = 157; + const T_MOD = 158; + /** * Creates a new query scanner object. * @@ -129,7 +133,7 @@ class Lexer extends \Doctrine\Common\Lexer '\?[0-9]*|:[a-z]{1}[a-z0-9_]{0,}' ); } - + /** * @inheritdoc */ @@ -145,50 +149,58 @@ class Lexer extends \Doctrine\Common\Lexer { $type = self::T_NONE; - // Recognizing numeric values - if (is_numeric($value)) { - return (strpos($value, '.') !== false || stripos($value, 'e') !== false) - ? self::T_FLOAT : self::T_INTEGER; - } + 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)); - // Differentiate between quoted names, identifiers, input parameters and symbols - if ($value[0] === "'") { - $value = str_replace("''", "'", substr($value, 1, strlen($value) - 2)); - return self::T_STRING; - } else if (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_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; - } else if ($value[0] === '?' || $value[0] === ':') { - return self::T_INPUT_PARAMETER; - } else { - switch ($value) { - case '.': return self::T_DOT; - case ',': return self::T_COMMA; - case '(': return self::T_OPEN_PARENTHESIS; - case ')': return self::T_CLOSE_PARENTHESIS; - case '=': return self::T_EQUALS; - case '>': return self::T_GREATER_THAN; - case '<': return self::T_LOWER_THAN; - case '+': return self::T_PLUS; - case '-': return self::T_MINUS; - case '*': return self::T_MULTIPLY; - case '/': return self::T_DIVIDE; - case '!': return self::T_NEGATE; - case '{': return self::T_OPEN_CURLY_BRACE; - case '}': return self::T_CLOSE_CURLY_BRACE; - default: - // Do nothing - break; - } + + 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/main/inc/lib/symfony/Doctrine/ORM/Query/ParameterTypeInferer.php b/main/inc/lib/symfony/Doctrine/ORM/Query/ParameterTypeInferer.php index 8664f86706..39aef2974f 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/ParameterTypeInferer.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/ParameterTypeInferer.php @@ -39,9 +39,9 @@ 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) diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/Parser.php b/main/inc/lib/symfony/Doctrine/ORM/Query/Parser.php index 7304d674b7..4200836802 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/Parser.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/Parser.php @@ -2,7 +2,7 @@ /* * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHARNTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT @@ -40,7 +40,8 @@ class Parser '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' + '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. */ @@ -52,6 +53,8 @@ class Parser '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. */ @@ -140,9 +143,9 @@ class Parser */ public function __construct(Query $query) { - $this->_query = $query; - $this->_em = $query->getEntityManager(); - $this->_lexer = new Lexer($query->getDql()); + $this->_query = $query; + $this->_em = $query->getEntityManager(); + $this->_lexer = new Lexer($query->getDql()); $this->_parserResult = new ParserResult(); } @@ -225,6 +228,11 @@ class Parser $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; } @@ -240,11 +248,10 @@ class Parser */ public function match($token) { + $lookaheadType = $this->_lexer->lookahead['type']; + // short-circuit on first condition, usually types match - if ($this->_lexer->lookahead['type'] !== $token && - $token !== Lexer::T_IDENTIFIER && - $this->_lexer->lookahead['type'] <= Lexer::T_IDENTIFIER - ) { + if ($lookaheadType !== $token && $token !== Lexer::T_IDENTIFIER && $lookaheadType <= Lexer::T_IDENTIFIER) { $this->syntaxError($this->_lexer->getLiteral($token)); } @@ -280,9 +287,6 @@ class Parser { $AST = $this->getAST(); - $this->fixIdentificationVariableOrder($AST); - $this->assertSelectEntityRootAliasRequirement(); - if (($customWalkers = $this->_query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) { $this->_customTreeWalkers = $customWalkers; } @@ -299,68 +303,57 @@ class Parser $treeWalkerChain->addTreeWalker($walker); } - if ($AST instanceof AST\SelectStatement) { - $treeWalkerChain->walkSelectStatement($AST); - } else if ($AST instanceof AST\UpdateStatement) { - $treeWalkerChain->walkUpdateStatement($AST); - } else { - $treeWalkerChain->walkDeleteStatement($AST); + 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); } } - if ($this->_customOutputWalker) { - $outputWalker = new $this->_customOutputWalker( - $this->_query, $this->_parserResult, $this->_queryComponents - ); - } else { - $outputWalker = new SqlWalker( - $this->_query, $this->_parserResult, $this->_queryComponents - ); - } + $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; } - - private function assertSelectEntityRootAliasRequirement() - { - if ( count($this->_identVariableExpressions) > 0) { - $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.'); - } - } - } - + /** * 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) { - foreach ($this->_queryComponents as $dqlAlias => $qComp) { - if (isset($this->_identVariableExpressions[$dqlAlias])) { - $expr = $this->_identVariableExpressions[$dqlAlias]; - $key = array_search($expr, $AST->selectClause->selectExpressions); - unset($AST->selectClause->selectExpressions[$key]); - $AST->selectClause->selectExpressions[] = $expr; - } + 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; } } @@ -379,19 +372,10 @@ class Parser } $tokenPos = (isset($token['position'])) ? $token['position'] : '-1'; - $message = "line 0, col {$tokenPos}: Error: "; - if ($expected !== '') { - $message .= "Expected {$expected}, got "; - } else { - $message .= 'Unexpected '; - } - - if ($this->_lexer->lookahead === null) { - $message .= 'end of string.'; - } else { - $message .= "'{$token['value']}'"; - } + $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); } @@ -414,18 +398,19 @@ class Parser $distance = 12; // Find a position of a final word to display in error string - $dql = $this->_query->getDql(); + $dql = $this->_query->getDql(); $length = strlen($dql); - $pos = $token['position'] + $distance; - $pos = strpos($dql, ' ', ($length > $pos) ? $pos : $length); + $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 ' . ( - (isset($token['position']) && $token['position'] > 0) ? $token['position'] : '-1' - ) . " near '" . substr($dql, $token['position'], $length) . "': Error: " . $message; + $message = 'line 0, col ' . $tokenPos . " near '" . $tokenStr . "': Error: " . $message; - throw \Doctrine\ORM\Query\QueryException::semanticalError($message); + throw QueryException::semanticalError($message); } /** @@ -459,15 +444,22 @@ class Parser $numUnmatched = 1; while ($numUnmatched > 0 && $token !== null) { - if ($token['value'] == ')') { - --$numUnmatched; - } else if ($token['value'] == '(') { - ++$numUnmatched; + switch ($token['type']) { + case Lexer::T_OPEN_PARENTHESIS: + ++$numUnmatched; + break; + + case Lexer::T_CLOSE_PARENTHESIS: + --$numUnmatched; + break; + + default: + // Do nothing } $token = $this->_lexer->peek(); } - + $this->_lexer->resetPeek(); return $token; @@ -480,7 +472,7 @@ class Parser */ private function _isMathOperator($token) { - return in_array($token['value'], array("+", "-", "/", "*")); + return in_array($token['type'], array(Lexer::T_PLUS, Lexer::T_MINUS, Lexer::T_DIVIDE, Lexer::T_MULTIPLY)); } /** @@ -490,12 +482,13 @@ class Parser */ private function _isFunction() { - $peek = $this->_lexer->peek(); + $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['value'] === '(' && $nextpeek['type'] !== Lexer::T_SELECT); + return ($peek['type'] === Lexer::T_OPEN_PARENTHESIS && $nextpeek['type'] !== Lexer::T_SELECT); } /** @@ -505,35 +498,17 @@ class Parser */ private function _isAggregateFunction($tokenType) { - return $tokenType == Lexer::T_AVG || $tokenType == Lexer::T_MIN || - $tokenType == Lexer::T_MAX || $tokenType == Lexer::T_SUM || - $tokenType == Lexer::T_COUNT; + 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. + * 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 $this->_lexer->lookahead['type'] === Lexer::T_ALL || - $this->_lexer->lookahead['type'] === Lexer::T_ANY || - $this->_lexer->lookahead['type'] === Lexer::T_SOME; - } - - /** - * Checks whether the next 2 tokens start a subselect. - * - * @return boolean TRUE if the next 2 tokens start a subselect, FALSE otherwise. - */ - private function _isSubselect() - { - $la = $this->_lexer->lookahead; - $next = $this->_lexer->glimpse(); - - return ($la['value'] === '(' && $next['type'] === Lexer::T_SELECT); + return in_array($this->_lexer->lookahead['type'], array(Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME)); } /** @@ -585,12 +560,13 @@ class Parser $class = $this->_queryComponents[$expr->identificationVariable]['metadata']; foreach ($expr->partialFieldSet as $field) { - if ( ! isset($class->fieldMappings[$field])) { - $this->semanticalError( - "There is no mapped field named '$field' on class " . $class->name . ".", - $deferredItem['token'] - ); + 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) { @@ -661,7 +637,7 @@ class Parser 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( @@ -670,17 +646,14 @@ class Parser ); } - if (isset($class->fieldMappings[$field])) { - $fieldType = AST\PathExpression::TYPE_STATE_FIELD; - } else { + $fieldType = AST\PathExpression::TYPE_STATE_FIELD; + + if (isset($class->associationMappings[$field])) { $assoc = $class->associationMappings[$field]; - $class = $this->_em->getClassMetadata($assoc['targetEntity']); - if ($assoc['type'] & ClassMetadata::TO_ONE) { - $fieldType = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION; - } else { - $fieldType = AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION; - } + $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 @@ -706,22 +679,38 @@ class Parser } // Build the error message - $semanticalError = 'Invalid PathExpression. '; - - if (count($expectedStringTypes) == 1) { - $semanticalError .= 'Must be a ' . $expectedStringTypes[0] . '.'; - } else { - $semanticalError .= implode(' or ', $expectedStringTypes) . ' expected.'; - } + $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 * @@ -737,12 +726,15 @@ class Parser 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; @@ -765,17 +757,10 @@ class Parser { $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; + $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; } @@ -788,8 +773,8 @@ class Parser public function UpdateStatement() { $updateStatement = new AST\UpdateStatement($this->UpdateClause()); - $updateStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) - ? $this->WhereClause() : null; + + $updateStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; return $updateStatement; } @@ -802,8 +787,8 @@ class Parser public function DeleteStatement() { $deleteStatement = new AST\DeleteStatement($this->DeleteClause()); - $deleteStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) - ? $this->WhereClause() : null; + + $deleteStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null; return $deleteStatement; } @@ -841,9 +826,7 @@ class Parser $exists = isset($this->_queryComponents[$aliasIdentVariable]); if ($exists) { - $this->semanticalError( - "'$aliasIdentVariable' is already defined.", $this->_lexer->token - ); + $this->semanticalError("'$aliasIdentVariable' is already defined.", $this->_lexer->token); } return $aliasIdentVariable; @@ -862,6 +845,7 @@ class Parser if (strrpos($schemaName, ':') !== false) { list($namespaceAlias, $simpleClassName) = explode(':', $schemaName); + $schemaName = $this->_em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName; } @@ -887,9 +871,7 @@ class Parser $exists = isset($this->_queryComponents[$resultVariable]); if ($exists) { - $this->semanticalError( - "'$resultVariable' is already defined.", $this->_lexer->token - ); + $this->semanticalError("'$resultVariable' is already defined.", $this->_lexer->token); } return $resultVariable; @@ -923,11 +905,13 @@ class Parser */ public function JoinAssociationPathExpression() { - $token = $this->_lexer->lookahead; + $token = $this->_lexer->lookahead; $identVariable = $this->IdentificationVariable(); - if (!isset($this->_queryComponents[$identVariable])) { - $this->semanticalError('Identification Variable ' . $identVariable .' used in join path expression but was not defined before.'); + 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); @@ -967,7 +951,7 @@ class Parser $field = $this->_lexer->token['value']; } - + // Creating AST node $pathExpr = new AST\PathExpression($expectedTypes, $identVariable, $field); @@ -1050,6 +1034,7 @@ class Parser // Check for DISTINCT if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { $this->match(Lexer::T_DISTINCT); + $isDistinct = true; } @@ -1059,6 +1044,7 @@ class Parser while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { $this->match(Lexer::T_COMMA); + $selectExpressions[] = $this->SelectExpression(); } @@ -1077,6 +1063,7 @@ class Parser if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { $this->match(Lexer::T_DISTINCT); + $isDistinct = true; } @@ -1111,6 +1098,7 @@ class Parser 'nestingLevel' => $this->_nestingLevel, 'token' => $token, ); + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; $this->match(Lexer::T_SET); @@ -1120,6 +1108,7 @@ class Parser while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { $this->match(Lexer::T_COMMA); + $updateItems[] = $this->UpdateItem(); } @@ -1163,6 +1152,7 @@ class Parser 'nestingLevel' => $this->_nestingLevel, 'token' => $token, ); + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; return $deleteClause; @@ -1176,11 +1166,13 @@ class Parser 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(); } @@ -1195,11 +1187,13 @@ class Parser 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(); } @@ -1244,6 +1238,7 @@ class Parser while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { $this->match(Lexer::T_COMMA); + $groupByItems[] = $this->GroupByItem(); } @@ -1265,6 +1260,7 @@ class Parser while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { $this->match(Lexer::T_COMMA); + $orderByItems[] = $this->OrderByItem(); } @@ -1283,17 +1279,10 @@ class Parser $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; + $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--; @@ -1318,7 +1307,7 @@ class Parser } /** - * GroupByItem ::= IdentificationVariable | SingleValuedPathExpression + * GroupByItem ::= IdentificationVariable | ResultVariable | SingleValuedPathExpression * * @return string | \Doctrine\ORM\Query\AST\PathExpression */ @@ -1327,25 +1316,24 @@ class Parser // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression $glimpse = $this->_lexer->glimpse(); - if ($glimpse['type'] != Lexer::T_DOT) { - $token = $this->_lexer->lookahead; - $identVariable = $this->IdentificationVariable(); + if ($glimpse['type'] === Lexer::T_DOT) { + return $this->SingleValuedPathExpression(); + } - if (!isset($this->_queryComponents[$identVariable])) { - $this->semanticalError('Cannot group by undefined identification variable.'); - } + // Still need to decide between IdentificationVariable or ResultVariable + $lookaheadValue = $this->_lexer->lookahead['value']; - return $identVariable; + if ( ! isset($this->_queryComponents[$lookaheadValue])) { + $this->semanticalError('Cannot group by undefined identification or result variable.'); } - return $this->SingleValuedPathExpression(); + return (isset($this->_queryComponents[$lookaheadValue]['metadata'])) + ? $this->IdentificationVariable() + : $this->ResultVariable(); } /** - * OrderByItem ::= (ResultVariable | StateFieldPathExpression) ["ASC" | "DESC"] - * - * @todo Post 2.0 release. Support general SingleValuedPathExpression instead - * of only StateFieldPathExpression. + * OrderByItem ::= (ResultVariable | SingleValuedPathExpression) ["ASC" | "DESC"] * * @return \Doctrine\ORM\Query\AST\OrderByItem */ @@ -1355,24 +1343,26 @@ class Parser // We need to check if we are in a ResultVariable or StateFieldPathExpression $glimpse = $this->_lexer->glimpse(); - - if ($glimpse['type'] != Lexer::T_DOT) { - $token = $this->_lexer->lookahead; - $expr = $this->ResultVariable(); - } else { - $expr = $this->StateFieldPathExpression(); - } + $expr = ($glimpse['type'] != Lexer::T_DOT) ? $this->ResultVariable() : $this->SingleValuedPathExpression(); $item = new AST\OrderByItem($expr); - if ($this->_lexer->isNextToken(Lexer::T_ASC)) { - $this->match(Lexer::T_ASC); - } else if ($this->_lexer->isNextToken(Lexer::T_DESC)) { - $this->match(Lexer::T_DESC); - $type = 'DESC'; + 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; } @@ -1391,9 +1381,13 @@ class Parser { if ($this->_lexer->isNextToken(Lexer::T_NULL)) { $this->match(Lexer::T_NULL); + return null; - } else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + } + + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { $this->match(Lexer::T_INPUT_PARAMETER); + return new AST\InputParameter($this->_lexer->token['value']); } @@ -1456,9 +1450,8 @@ class Parser */ public function JoinVariableDeclaration() { - $join = $this->Join(); - $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) - ? $this->IndexBy() : null; + $join = $this->Join(); + $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null; return new AST\JoinVariableDeclaration($join, $indexBy); } @@ -1489,6 +1482,7 @@ class Parser 'nestingLevel' => $this->_nestingLevel, 'token' => $token ); + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; return new AST\RangeVariableDeclaration($abstractSchemaName, $aliasIdentificationVariable); @@ -1507,18 +1501,20 @@ class Parser $partialFieldSet = array(); $identificationVariable = $this->IdentificationVariable(); - $this->match(Lexer::T_DOT); + $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); @@ -1544,18 +1540,26 @@ class Parser // Check Join type $joinType = AST\Join::JOIN_TYPE_INNER; - if ($this->_lexer->isNextToken(Lexer::T_LEFT)) { - $this->match(Lexer::T_LEFT); + switch (true) { + case ($this->_lexer->isNextToken(Lexer::T_LEFT)): + $this->match(Lexer::T_LEFT); - // Possible LEFT OUTER join - if ($this->_lexer->isNextToken(Lexer::T_OUTER)) { - $this->match(Lexer::T_OUTER); - $joinType = AST\Join::JOIN_TYPE_LEFTOUTER; - } else { $joinType = AST\Join::JOIN_TYPE_LEFT; - } - } else if ($this->_lexer->isNextToken(Lexer::T_INNER)) { - $this->match(Lexer::T_INNER); + + // 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); @@ -1571,7 +1575,7 @@ class Parser // Verify that the association exists. $parentClass = $this->_queryComponents[$joinPathExpression->identificationVariable]['metadata']; - $assocField = $joinPathExpression->associationField; + $assocField = $joinPathExpression->associationField; if ( ! $parentClass->hasAssociation($assocField)) { $this->semanticalError( @@ -1590,6 +1594,7 @@ class Parser 'nestingLevel' => $this->_nestingLevel, 'token' => $token ); + $this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent; // Create AST node @@ -1598,6 +1603,7 @@ class Parser // Check for ad-hoc Join conditions if ($this->_lexer->isNextToken(Lexer::T_WITH)) { $this->match(Lexer::T_WITH); + $join->conditionalExpression = $this->ConditionalExpression(); } @@ -1624,207 +1630,353 @@ class Parser /** * ScalarExpression ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary | * StateFieldPathExpression | BooleanPrimary | CaseExpression | - * EntityTypeExpression + * InstanceOfExpression * * @return mixed One of the possible expressions or subexpressions. */ public function ScalarExpression() { $lookahead = $this->_lexer->lookahead['type']; - if ($lookahead === 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(); - } + 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(); - } else if ($lookahead == Lexer::T_INTEGER || $lookahead == Lexer::T_FLOAT) { - return $this->SimpleArithmeticExpression(); - } else if ($lookahead == Lexer::T_CASE || $lookahead == Lexer::T_COALESCE || $lookahead == 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(); - } else if ($this->_isFunction() || $this->_isAggregateFunction($this->_lexer->lookahead['type'])) { - // 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->StateFieldPathExpression(); + + case Lexer::T_INTEGER: + case Lexer::T_FLOAT: return $this->SimpleArithmeticExpression(); - } - if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { - return $this->AggregateExpression(); - } else { + 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(); - } - } else if ($lookahead == Lexer::T_STRING) { - return $this->StringPrimary(); - } else if ($lookahead == Lexer::T_INPUT_PARAMETER) { - return $this->InputParameter(); - } else if ($lookahead == Lexer::T_TRUE || $lookahead == Lexer::T_FALSE) { - $this->match($lookahead); - return new AST\Literal(AST\Literal::BOOLEAN, $this->_lexer->token['value']); - } else { - $this->syntaxError(); } } + /** + * 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']; - - // if "CASE" "WHEN" => GeneralCaseExpression - // else if "CASE" => SimpleCaseExpression - // [DONE] else if "COALESCE" => CoalesceExpression - // [DONE] else if "NULLIF" => NullifExpression + 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: - $this->semanticalError('CaseExpression not yet supported.'); - return null; + // 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\ExistsExpression + * + * @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); } /** - * SelectExpression ::= - * IdentificationVariable | StateFieldPathExpression | - * (AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable] + * 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; + $expression = null; $identVariable = null; - $fieldAliasIdentificationVariable = null; - $peek = $this->_lexer->glimpse(); - - $supportsAlias = true; + $peek = $this->_lexer->glimpse(); + $lookaheadType = $this->_lexer->lookahead['type']; - if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) { - if ($peek['value'] == '.') { - // ScalarExpression + switch (true) { + // ScalarExpression (u.name) + case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT): $expression = $this->ScalarExpression(); - } else { - $supportsAlias = false; + break; + + // IdentificationVariable (u) + case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS): $expression = $identVariable = $this->IdentificationVariable(); - } - } else if ($this->_lexer->lookahead['value'] == '(') { - if ($peek['type'] == Lexer::T_SELECT) { - // Subselect + 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); - } else { - // Shortcut: ScalarExpression => SimpleArithmeticExpression - $expression = $this->SimpleArithmeticExpression(); - } - } else if ($this->_isFunction()) { - $this->_lexer->peek(); // "(" - - $lookaheadType = $this->_lexer->lookahead['type']; - $beyond = $this->_peekBeyondClosingParenthesis(); - - if ($this->_isMathOperator($beyond)) { - $expression = $this->ScalarExpression(); - } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { - $expression = $this->AggregateExpression(); - } else if (in_array ($lookaheadType, array(Lexer::T_CASE, Lexer::T_COALESCE, Lexer::T_NULLIF))) { - $expression = $this->CaseExpression(); - } else { - // Shortcut: ScalarExpression => Function - $expression = $this->FunctionDeclaration(); - } - } else if ($this->_lexer->lookahead['type'] == Lexer::T_PARTIAL) { - $supportsAlias = false; - $expression = $this->PartialObjectExpression(); - $identVariable = $expression->identificationVariable; - } else if ($this->_lexer->lookahead['type'] == Lexer::T_INTEGER || - $this->_lexer->lookahead['type'] == Lexer::T_FLOAT || - $this->_lexer->lookahead['type'] == Lexer::T_STRING) { + break; + // Shortcut: ScalarExpression => SimpleArithmeticExpression - $expression = $this->SimpleArithmeticExpression(); - } else { - $this->syntaxError('IdentificationVariable | StateFieldPathExpression' - . ' | AggregateExpression | "(" Subselect ")" | ScalarExpression', - $this->_lexer->lookahead); + 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 + ); } - if ($supportsAlias) { - if ($this->_lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); - } + // [["AS"] ["HIDDEN"] AliasResultVariable] - if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { - $token = $this->_lexer->lookahead; - $fieldAliasIdentificationVariable = $this->AliasResultVariable(); + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } - // Include AliasResultVariable in query components. - $this->_queryComponents[$fieldAliasIdentificationVariable] = array( - 'resultVariable' => $expression, - 'nestingLevel' => $this->_nestingLevel, - 'token' => $token, - ); - } + $hiddenAliasResultVariable = false; + + if ($this->_lexer->isNextToken(Lexer::T_HIDDEN)) { + $this->match(Lexer::T_HIDDEN); + + $hiddenAliasResultVariable = true; } - $expr = new AST\SelectExpression($expression, $fieldAliasIdentificationVariable); - if (!$supportsAlias) { + $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; } @@ -1839,34 +1991,47 @@ class Parser { $peek = $this->_lexer->glimpse(); - if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) { - // SingleValuedPathExpression | IdentificationVariable - if ($peek['value'] == '.') { - $expression = $this->StateFieldPathExpression(); - } else { - $expression = $this->IdentificationVariable(); - } + 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); + + 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); + } - return new AST\SimpleSelectExpression($expression); - } else if ($this->_lexer->lookahead['value'] == '(') { - if ($peek['type'] == Lexer::T_SELECT) { // Subselect $this->match(Lexer::T_OPEN_PARENTHESIS); $expression = $this->Subselect(); $this->match(Lexer::T_CLOSE_PARENTHESIS); - } else { - // Shortcut: ScalarExpression => SimpleArithmeticExpression - $expression = $this->SimpleArithmeticExpression(); - } - return new AST\SimpleSelectExpression($expression); + return new AST\SimpleSelectExpression($expression); + + default: + // Do nothing } $this->_lexer->peek(); $expression = $this->ScalarExpression(); - - $expr = new AST\SimpleSelectExpression($expression); + $expr = new AST\SimpleSelectExpression($expression); if ($this->_lexer->isNextToken(Lexer::T_AS)) { $this->match(Lexer::T_AS); @@ -1900,6 +2065,7 @@ class Parser while ($this->_lexer->isNextToken(Lexer::T_OR)) { $this->match(Lexer::T_OR); + $conditionalTerms[] = $this->ConditionalTerm(); } @@ -1924,6 +2090,7 @@ class Parser while ($this->_lexer->isNextToken(Lexer::T_AND)) { $this->match(Lexer::T_AND); + $conditionalFactors[] = $this->ConditionalFactor(); } @@ -1947,9 +2114,10 @@ class Parser if ($this->_lexer->isNextToken(Lexer::T_NOT)) { $this->match(Lexer::T_NOT); + $not = true; } - + $conditionalPrimary = $this->ConditionalPrimary(); // Phase 1 AST optimization: Prevent AST\ConditionalFactor @@ -1973,27 +2141,27 @@ class Parser { $condPrimary = new AST\ConditionalPrimary; - if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { - // Peek beyond the matching closing paranthesis ')' - $peek = $this->_peekBeyondClosingParenthesis(); - - if (in_array($peek['value'], array("=", "<", "<=", "<>", ">", ">=", "!=")) || - $peek['type'] === Lexer::T_NOT || - $peek['type'] === Lexer::T_BETWEEN || - $peek['type'] === Lexer::T_LIKE || - $peek['type'] === Lexer::T_IN || - $peek['type'] === Lexer::T_IS || - $peek['type'] === Lexer::T_EXISTS) { - $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression(); - } else { - $this->match(Lexer::T_OPEN_PARENTHESIS); - $condPrimary->conditionalExpression = $this->ConditionalExpression(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); - } - } else { + 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; } @@ -2006,10 +2174,10 @@ class Parser */ public function SimpleConditionalExpression() { + $token = $this->_lexer->lookahead; + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { $token = $this->_lexer->glimpse(); - } else { - $token = $this->_lexer->lookahead; } if ($token['type'] === Lexer::T_EXISTS) { @@ -2104,13 +2272,13 @@ class Parser */ public function CollectionMemberExpression() { - $not = false; - + $not = false; $entityExpr = $this->EntityExpression(); if ($this->_lexer->isNextToken(Lexer::T_NOT)) { - $not = true; $this->match(Lexer::T_NOT); + + $not = true; } $this->match(Lexer::T_MEMBER); @@ -2275,7 +2443,7 @@ class Parser $this->match(($isPlus) ? Lexer::T_PLUS : Lexer::T_MINUS); $sign = $isPlus; } - + $primary = $this->ArithmeticPrimary(); // Phase 1 AST optimization: Prevent AST\ArithmeticFactor @@ -2290,7 +2458,7 @@ class Parser /** * ArithmeticPrimary ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")" * | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings - * | FunctionsReturningDatetime | IdentificationVariable | ResultVariable + * | FunctionsReturningDatetime | IdentificationVariable | ResultVariable | CaseExpression */ public function ArithmeticPrimary() { @@ -2304,6 +2472,11 @@ class Parser } 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(); @@ -2314,11 +2487,11 @@ class Parser 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: @@ -2333,9 +2506,9 @@ class Parser } return $this->FunctionDeclaration(); - } else { - return $this->Literal(); } + + return $this->Literal(); } } @@ -2363,32 +2536,50 @@ class Parser } /** - * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression + * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression | CaseExpression */ public function StringPrimary() { - if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { - $peek = $this->_lexer->glimpse(); + $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(); + } - if ($peek['value'] == '.') { - return $this->StateFieldPathExpression(); - } else if ($peek['value'] == '(') { - // do NOT directly go to FunctionsReturningString() because it doesnt check for custom functions. - return $this->FunctionDeclaration(); - } else { $this->syntaxError("'.' or '('"); - } - } else if ($this->_lexer->isNextToken(Lexer::T_STRING)) { - $this->match(Lexer::T_STRING); + break; - return $this->_lexer->token['value']; - } else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { - return $this->InputParameter(); - } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { - return $this->AggregateExpression(); + case Lexer::T_STRING: + $this->match(Lexer::T_STRING); + + return $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'); + $this->syntaxError( + 'StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression' + ); } /** @@ -2419,7 +2610,7 @@ class Parser return $this->InputParameter(); } - return $this->IdentificationVariable(); + return $this->StateFieldPathExpression(); } /** @@ -2431,40 +2622,28 @@ class Parser */ public function AggregateExpression() { + $lookaheadType = $this->_lexer->lookahead['type']; $isDistinct = false; - $functionName = ''; - - if ($this->_lexer->isNextToken(Lexer::T_COUNT)) { - $this->match(Lexer::T_COUNT); - $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; - } + 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'); + } - $pathExp = $this->SingleValuedPathExpression(); - $this->match(Lexer::T_CLOSE_PARENTHESIS); - } else { - if ($this->_lexer->isNextToken(Lexer::T_AVG)) { - $this->match(Lexer::T_AVG); - } else if ($this->_lexer->isNextToken(Lexer::T_MAX)) { - $this->match(Lexer::T_MAX); - } else if ($this->_lexer->isNextToken(Lexer::T_MIN)) { - $this->match(Lexer::T_MIN); - } else if ($this->_lexer->isNextToken(Lexer::T_SUM)) { - $this->match(Lexer::T_SUM); - } else { - $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT'); - } + $this->match($lookaheadType); + $functionName = $this->_lexer->token['value']; + $this->match(Lexer::T_OPEN_PARENTHESIS); - $functionName = $this->_lexer->token['value']; - $this->match(Lexer::T_OPEN_PARENTHESIS); - $pathExp = $this->SimpleArithmeticExpression(); - $this->match(Lexer::T_CLOSE_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); } @@ -2475,24 +2654,19 @@ class Parser */ public function QuantifiedExpression() { - $type = ''; - - if ($this->_lexer->isNextToken(Lexer::T_ALL)) { - $this->match(Lexer::T_ALL); - $type = 'ALL'; - } else if ($this->_lexer->isNextToken(Lexer::T_ANY)) { - $this->match(Lexer::T_ANY); - $type = 'ANY'; - } else if ($this->_lexer->isNextToken(Lexer::T_SOME)) { - $this->match(Lexer::T_SOME); - $type = 'SOME'; - } else { + $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 = $type; + $qExpr->type = $value; + $this->match(Lexer::T_CLOSE_PARENTHESIS); return $qExpr; @@ -2533,14 +2707,11 @@ class Parser { $peek = $this->_lexer->glimpse(); - $leftExpr = $this->ArithmeticExpression(); - $operator = $this->ComparisonOperator(); - - if ($this->_isNextAllAnySome()) { - $rightExpr = $this->QuantifiedExpression(); - } else { - $rightExpr = $this->ArithmeticExpression(); - } + $leftExpr = $this->ArithmeticExpression(); + $operator = $this->ComparisonOperator(); + $rightExpr = ($this->_isNextAllAnySome()) + ? $this->QuantifiedExpression() + : $this->ArithmeticExpression(); return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr); } @@ -2552,7 +2723,7 @@ class Parser */ public function InExpression() { - $inExpression = new AST\InExpression($this->SingleValuedPathExpression()); + $inExpression = new AST\InExpression($this->ArithmeticExpression()); if ($this->_lexer->isNextToken(Lexer::T_NOT)) { $this->match(Lexer::T_NOT); @@ -2582,7 +2753,7 @@ class Parser } /** - * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (AbstractSchemaName | InputParameter) + * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")") * * @return \Doctrine\ORM\Query\AST\InstanceOfExpression */ @@ -2596,21 +2767,49 @@ class Parser } $this->match(Lexer::T_INSTANCE); + $this->match(Lexer::T_OF); - if ($this->_lexer->isNextToken(Lexer::T_OF)) { - $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); - $exprValue = new AST\InputParameter($this->_lexer->token['value']); - } else { - $exprValue = $this->AliasIdentificationVariable(); + + return new AST\InputParameter($this->_lexer->token['value']); } - $instanceOfExpression->value = $exprValue; - - return $instanceOfExpression; + return $this->AliasIdentificationVariable(); } /** @@ -2695,8 +2894,10 @@ class Parser $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; @@ -2760,26 +2961,45 @@ class Parser $funcName = strtolower($token['value']); // Check for built-in functions first! - if (isset(self::$_STRING_FUNCTIONS[$funcName])) { - return $this->FunctionsReturningStrings(); - } else if (isset(self::$_NUMERIC_FUNCTIONS[$funcName])) { - return $this->FunctionsReturningNumerics(); - } else if (isset(self::$_DATETIME_FUNCTIONS[$funcName])) { - return $this->FunctionsReturningDatetime(); + 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(); - if ($config->getCustomStringFunction($funcName) !== null) { - return $this->CustomFunctionsReturningStrings(); - } else if ($config->getCustomNumericFunction($funcName) !== null) { - return $this->CustomFunctionsReturningNumerics(); - } else if ($config->getCustomDatetimeFunction($funcName) !== null) { - return $this->CustomFunctionsReturningDatetime(); - } + switch (true) { + case ($config->getCustomStringFunction($funcName) !== null): + return $this->CustomFunctionsReturningStrings(); - $this->syntaxError('known function', $token); + case ($config->getCustomNumericFunction($funcName) !== null): + return $this->CustomFunctionsReturningNumerics(); + + case ($config->getCustomDatetimeFunction($funcName) !== null): + return $this->CustomFunctionsReturningDatetime(); + + default: + $this->syntaxError('known function', $token); + } } /** @@ -2794,7 +3014,8 @@ class Parser public function FunctionsReturningNumerics() { $funcNameLower = strtolower($this->_lexer->lookahead['value']); - $funcClass = self::$_NUMERIC_FUNCTIONS[$funcNameLower]; + $funcClass = self::$_NUMERIC_FUNCTIONS[$funcNameLower]; + $function = new $funcClass($funcNameLower); $function->parse($this); @@ -2803,9 +3024,10 @@ class Parser public function CustomFunctionsReturningNumerics() { - $funcName = strtolower($this->_lexer->lookahead['value']); // getCustomNumericFunction is case-insensitive + $funcName = strtolower($this->_lexer->lookahead['value']); $funcClass = $this->_em->getConfiguration()->getCustomNumericFunction($funcName); + $function = new $funcClass($funcName); $function->parse($this); @@ -2818,7 +3040,8 @@ class Parser public function FunctionsReturningDatetime() { $funcNameLower = strtolower($this->_lexer->lookahead['value']); - $funcClass = self::$_DATETIME_FUNCTIONS[$funcNameLower]; + $funcClass = self::$_DATETIME_FUNCTIONS[$funcNameLower]; + $function = new $funcClass($funcNameLower); $function->parse($this); @@ -2827,9 +3050,10 @@ class Parser public function CustomFunctionsReturningDatetime() { - $funcName = $this->_lexer->lookahead['value']; // getCustomDatetimeFunction is case-insensitive + $funcName = $this->_lexer->lookahead['value']; $funcClass = $this->_em->getConfiguration()->getCustomDatetimeFunction($funcName); + $function = new $funcClass($funcName); $function->parse($this); @@ -2847,7 +3071,8 @@ class Parser public function FunctionsReturningStrings() { $funcNameLower = strtolower($this->_lexer->lookahead['value']); - $funcClass = self::$_STRING_FUNCTIONS[$funcNameLower]; + $funcClass = self::$_STRING_FUNCTIONS[$funcNameLower]; + $function = new $funcClass($funcNameLower); $function->parse($this); @@ -2856,9 +3081,10 @@ class Parser public function CustomFunctionsReturningStrings() { - $funcName = $this->_lexer->lookahead['value']; // getCustomStringFunction is case-insensitive + $funcName = $this->_lexer->lookahead['value']; $funcClass = $this->_em->getConfiguration()->getCustomStringFunction($funcName); + $function = new $funcClass($funcName); $function->parse($this); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/ParserResult.php b/main/inc/lib/symfony/Doctrine/ORM/Query/ParserResult.php index 42aecc1844..3e938a9c3d 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/ParserResult.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/ParserResult.php @@ -37,14 +37,14 @@ 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; @@ -55,7 +55,7 @@ class ParserResult * @var array */ private $_parameterMappings = array(); - + /** * Initializes a new instance of the ParserResult class. * The new instance is initialized with an empty ResultSetMapping. @@ -67,7 +67,7 @@ class ParserResult /** * 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. */ @@ -88,7 +88,7 @@ class ParserResult /** * Sets the SQL executor that should be used for this ParserResult. - * + * * @param \Doctrine\ORM\Query\Exec\AbstractSqlExecutor $executor */ public function setSqlExecutor($executor) @@ -98,14 +98,14 @@ class ParserResult /** * 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. @@ -117,17 +117,17 @@ class ParserResult { $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. * diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/QueryException.php b/main/inc/lib/symfony/Doctrine/ORM/Query/QueryException.php index eeecc18c61..cd74f3567c 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/QueryException.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/QueryException.php @@ -47,6 +47,11 @@ class QueryException extends \Doctrine\ORM\ORMException return new self('[Semantical Error] ' . $message); } + 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.'); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/ResultSetMapping.php b/main/inc/lib/symfony/Doctrine/ORM/Query/ResultSetMapping.php index 3a086e2cd9..32aa298f1f 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/ResultSetMapping.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/ResultSetMapping.php @@ -26,7 +26,7 @@ namespace Doctrine\ORM\Query; * 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 @@ -36,87 +36,85 @@ namespace Doctrine\ORM\Query; class ResultSetMapping { /** - * Whether the result is mixed (contains scalar values together with field values). - * * @ignore - * @var boolean + * @var boolean Whether the result is mixed (contains scalar values together with field values). */ public $isMixed = false; + /** - * Maps alias names to class names. - * * @ignore - * @var array + * @var array Maps alias names to class names. */ public $aliasMap = array(); + /** - * Maps alias names to related association field names. - * * @ignore - * @var array + * @var array Maps alias names to related association field names. */ public $relationMap = array(); + /** - * Maps alias names to parent alias names. - * * @ignore - * @var array + * @var array Maps alias names to parent alias names. */ public $parentAliasMap = array(); + /** - * Maps column names in the result set to field names for each class. - * * @ignore - * @var array + * @var array Maps column names in the result set to field names for each class. */ public $fieldMappings = array(); + /** - * Maps column names in the result set to the alias/field name to use in the mapped result. - * * @ignore - * @var array + * @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(); + /** - * Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names. - * * @ignore - * @var array + * @var array Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names. */ public $metaMappings = array(); + /** - * Maps column names in the result set to the alias they belong to. - * * @ignore - * @var array + * @var array Maps column names in the result set to the alias they belong to. */ public $columnOwnerMap = array(); + /** - * List of columns in the result set that are used as discriminator columns. - * * @ignore - * @var array + * @var array List of columns in the result set that are used as discriminator columns. */ public $discriminatorColumns = array(); + /** - * Maps alias names to field names that should be used for indexing. - * * @ignore - * @var array + * @var array Maps alias names to field names that should be used for indexing. */ public $indexByMap = array(); + /** - * Map from column names to class names that declare the field the column is mapped to. - * * @ignore - * @var array + * @var array Map from column names to class names that declare the field the column is mapped to. */ public $declaringClasses = array(); - + /** - * This is necessary to hydrate derivate foreign keys correctly. - * - * @var array + * @var array This is necessary to hydrate derivate foreign keys correctly. */ public $isIdentifierColumn = array(); @@ -126,11 +124,21 @@ class 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) + public function addEntityResult($class, $alias, $resultAlias = null) { $this->aliasMap[$alias] = $class; + $this->entityMappings[$alias] = $resultAlias; + + if ($resultAlias !== null) { + $this->isMixed = true; + } + + return $this; } /** @@ -141,12 +149,15 @@ class ResultSetMapping * @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; } /** @@ -154,10 +165,61 @@ class ResultSetMapping * * @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) { - $this->indexByMap[$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; } /** @@ -197,6 +259,7 @@ class ResultSetMapping * 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) @@ -207,9 +270,12 @@ class ResultSetMapping $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; } /** @@ -219,33 +285,44 @@ class ResultSetMapping * @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->aliasMap[$alias] = $class; $this->parentAliasMap[$alias] = $parentAlias; - $this->relationMap[$alias] = $relation; + $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) + public function addScalarResult($columnName, $alias, $type = null) { $this->scalarMappings[$columnName] = $alias; + $this->typeMappings[$columnName] = $type ?: 'string'; + 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 @@ -384,21 +461,25 @@ class ResultSetMapping { 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; } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/ResultSetMappingBuilder.php b/main/inc/lib/symfony/Doctrine/ORM/Query/ResultSetMappingBuilder.php index d1690b72c0..f84686ad2c 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/ResultSetMappingBuilder.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/ResultSetMappingBuilder.php @@ -86,20 +86,22 @@ class ResultSetMappingBuilder extends ResultSetMapping 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, $platform->getSQLResultCasing($columnName), $propertyName); + $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, $platform->getSQLResultCasing($renamedColumnName), $platform->getSQLResultCasing($columnName)); + $this->addMetaResult($alias, $renamedColumnName, $columnName); } } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/SqlWalker.php b/main/inc/lib/symfony/Doctrine/ORM/Query/SqlWalker.php index 8f92fb9c43..d883aea7dc 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/SqlWalker.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/SqlWalker.php @@ -20,17 +20,21 @@ 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\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 - * @since 2.0 + * @author Alexander + * @since 2.0 * @todo Rename: SQLWalker */ class SqlWalker implements TreeWalker @@ -76,6 +80,13 @@ class SqlWalker implements TreeWalker /** Map from result variable names to their SQL column alias names. */ 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. */ private $_queryComponents; @@ -165,18 +176,18 @@ class SqlWalker implements TreeWalker 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()) + + return ($primaryClass->isInheritanceTypeJoined()) ? new Exec\MultiTableUpdateExecutor($AST, $this) : new Exec\SingleTableDeleteUpdateExecutor($AST, $this); - + default: return new Exec\SingleSelectExecutor($AST, $this); } @@ -226,7 +237,11 @@ class SqlWalker implements TreeWalker */ public function getSQLColumnAlias($columnName) { - return $columnName . $this->_aliasCounter++; + // 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. + return $this->_platform->getSQLResultCasing( + substr($columnName . $this->_aliasCounter++, -$this->_platform->getMaxIdentifierLength()) + ); } /** @@ -241,39 +256,50 @@ class SqlWalker implements TreeWalker { $sql = ''; - $baseTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias); + $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->table['name'], $dqlAlias); + $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 ' . $parentClass->getQuotedTableName($this->_platform) - . ' ' . $tableAlias . ' ON '; - $first = true; + $sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON '; + + $sqlParts = array(); + foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) { - if ($first) $first = false; else $sql .= ' AND '; + $sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; + } - $sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; + // Add filters on the root class + if ($filterSql = $this->generateFilterConditionSQL($parentClass, $tableAlias)) { + $sqlParts[] = $filterSql; } + + $sql .= implode(' AND ', $sqlParts); } - // LEFT JOIN subclass tables, if partial objects disallowed. - if ( ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) { - foreach ($class->subClasses as $subClassName) { - $subClass = $this->_em->getClassMetadata($subClassName); - $tableAlias = $this->getSQLTableAlias($subClass->table['name'], $dqlAlias); - $sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) - . ' ' . $tableAlias . ' ON '; - $first = true; - - foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) { - if ($first) $first = false; else $sql .= ' AND '; - - $sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; - } + // 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 ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON '; + + $sqlParts = array(); + + foreach ($subClass->getQuotedIdentifierColumnNames($this->_platform) as $columnName) { + $sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName; } + + $sql .= implode(' AND ', $sqlParts); } return $sql; @@ -281,26 +307,25 @@ class SqlWalker implements TreeWalker private function _generateOrderedCollectionOrderByItems() { - $sql = ''; - foreach ($this->_selectedClasses AS $dqlAlias => $class) { - $qComp = $this->_queryComponents[$dqlAlias]; - if (isset($qComp['relation']['orderBy'])) { - foreach ($qComp['relation']['orderBy'] AS $fieldName => $orientation) { - if ($qComp['metadata']->isInheritanceTypeJoined()) { - $tableName = $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName); - } else { - $tableName = $qComp['metadata']->table['name']; - } + $sqlParts = array(); - if ($sql != '') { - $sql .= ', '; - } - $sql .= $this->getSQLTableAlias($tableName, $dqlAlias) . '.' . - $qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform) . " $orientation"; - } + 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 = $qComp['metadata']->getQuotedColumnName($fieldName, $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 $sql; + + return implode(', ', $sqlParts); } /** @@ -311,37 +336,77 @@ class SqlWalker implements TreeWalker */ private function _generateDiscriminatorColumnConditionSQL(array $dqlAliases) { - $encapsulate = false; - $sql = ''; + $sqlParts = array(); foreach ($dqlAliases as $dqlAlias) { $class = $this->_queryComponents[$dqlAlias]['metadata']; - if ($class->isInheritanceTypeSingleTable()) { - $conn = $this->_em->getConnection(); - $values = array(); - if ($class->discriminatorValue !== null) { // discrimnators can be 0 - $values[] = $conn->quote($class->discriminatorValue); - } + if ( ! $class->isInheritanceTypeSingleTable()) continue; - foreach ($class->subClasses as $subclassName) { - $values[] = $conn->quote($this->_em->getClassMetadata($subclassName)->discriminatorValue); - } + $conn = $this->_em->getConnection(); + $values = array(); - if ($sql != '') { - $sql .= ' AND '; - $encapsulate = true; - } + if ($class->discriminatorValue !== null) { // discrimnators can be 0 + $values[] = $conn->quote($class->discriminatorValue); + } - $sql .= ($sql != '' ? ' AND ' : '') - . (($this->_useSqlTableAliases) ? $this->getSQLTableAlias($class->table['name'], $dqlAlias) . '.' : '') - . $class->discriminatorColumn['name'] . ' IN (' . implode(', ', $values) . ')'; + 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) . ')'; } - return ($encapsulate) ? '(' . $sql . ')' : $sql; + $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. * @@ -349,40 +414,44 @@ class SqlWalker implements TreeWalker */ public function walkSelectStatement(AST\SelectStatement $AST) { - $sql = $this->walkSelectClause($AST->selectClause); + $sql = $this->walkSelectClause($AST->selectClause); $sql .= $this->walkFromClause($AST->fromClause); - - if (($whereClause = $AST->whereClause) !== null) { - $sql .= $this->walkWhereClause($whereClause); - } else if (($discSql = $this->_generateDiscriminatorColumnConditionSQL($this->_rootAliases)) !== '') { - $sql .= ' WHERE ' . $discSql; - } - + $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 .= ' ORDER BY ' . $orderBySql; } - $sql = $this->_platform->modifyLimitQuery( $sql, $this->_query->getMaxResults(), $this->_query->getFirstResult() ); if (($lockMode = $this->_query->getHint(Query::HINT_LOCK_MODE)) !== false) { - if ($lockMode == LockMode::PESSIMISTIC_READ) { - $sql .= " " . $this->_platform->getReadLockSQL(); - } else if ($lockMode == LockMode::PESSIMISTIC_WRITE) { - $sql .= " " . $this->_platform->getWriteLockSQL(); - } else if ($lockMode == LockMode::OPTIMISTIC) { - foreach ($this->_selectedClasses AS $class) { - if ( ! $class->isVersioned) { - throw \Doctrine\ORM\OptimisticLockException::lockFailed(); + 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(); } } @@ -398,15 +467,9 @@ class SqlWalker implements TreeWalker public function walkUpdateStatement(AST\UpdateStatement $AST) { $this->_useSqlTableAliases = false; - $sql = $this->walkUpdateClause($AST->updateClause); - - if (($whereClause = $AST->whereClause) !== null) { - $sql .= $this->walkWhereClause($whereClause); - } else if (($discSql = $this->_generateDiscriminatorColumnConditionSQL($this->_rootAliases)) !== '') { - $sql .= ' WHERE ' . $discSql; - } - return $sql; + return $this->walkUpdateClause($AST->updateClause) + . $this->walkWhereClause($AST->whereClause); } /** @@ -418,18 +481,31 @@ class SqlWalker implements TreeWalker public function walkDeleteStatement(AST\DeleteStatement $AST) { $this->_useSqlTableAliases = false; - $sql = $this->walkDeleteClause($AST->deleteClause); - if (($whereClause = $AST->whereClause) !== null) { - $sql .= $this->walkWhereClause($whereClause); - } else if (($discSql = $this->_generateDiscriminatorColumnConditionSQL($this->_rootAliases)) !== '') { - $sql .= ' WHERE ' . $discSql; + 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 ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) { + $sqlParts[] = $tableAlias . '.' . $columnName; } - return $sql; + return implode(', ', $sqlParts); } - /** * Walks down an IdentificationVariable (no AST node associated), thereby generating the SQL. * @@ -448,7 +524,7 @@ class SqlWalker implements TreeWalker $class = $this->_em->getClassMetadata($class->fieldMappings[$fieldName]['inherited']); } - return $this->getSQLTableAlias($class->table['name'], $identificationVariable); + return $this->getSQLTableAlias($class->getTableName(), $identificationVariable); } /** @@ -487,22 +563,22 @@ class SqlWalker implements TreeWalker $assoc = $class->associationMappings[$fieldName]; - if ($assoc['isOwningSide']) { - // COMPOSITE KEYS NOT (YET?) SUPPORTED - if (count($assoc['sourceToTargetKeyColumns']) > 1) { - throw QueryException::associationPathCompositeKeyNotSupported(); - } + if ( ! $assoc['isOwningSide']) { + throw QueryException::associationPathInverseSideNotSupported(); + } - if ($this->_useSqlTableAliases) { - $sql .= $this->getSQLTableAlias($class->table['name'], $dqlAlias) . '.'; - } + // COMPOSITE KEYS NOT (YET?) SUPPORTED + if (count($assoc['sourceToTargetKeyColumns']) > 1) { + throw QueryException::associationPathCompositeKeyNotSupported(); + } - $sql .= reset($assoc['targetToSourceKeyColumns']); - } else { - throw QueryException::associationPathInverseSideNotSupported(); + if ($this->_useSqlTableAliases) { + $sql .= $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.'; } + + $sql .= reset($assoc['targetToSourceKeyColumns']); break; - + default: throw QueryException::invalidPathExpression($pathExpr); } @@ -531,13 +607,18 @@ class SqlWalker implements TreeWalker $this->_query->getHydrationMode() != Query::HYDRATE_OBJECT && $this->_query->getHint(Query::HINT_INCLUDE_META_COLUMNS); - foreach ($this->_selectedClasses as $dqlAlias => $class) { + 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); + $this->_rsm->addEntityResult($class->name, $dqlAlias, $resultAlias); } else { $this->_rsm->addJoinedEntityResult( - $class->name, $dqlAlias, + $class->name, + $dqlAlias, $this->_queryComponents[$dqlAlias]['parent'], $this->_queryComponents[$dqlAlias]['relation']['fieldName'] ); @@ -545,60 +626,69 @@ class SqlWalker implements TreeWalker if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) { // Add discriminator columns to SQL - $rootClass = $this->_em->getClassMetadata($class->rootEntityName); - $tblAlias = $this->getSQLTableAlias($rootClass->table['name'], $dqlAlias); + $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; - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); $this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias); $this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']); + } - // Add foreign key columns to SQL, if necessary - if ($addMetaColumns) { - //FIXME: Include foreign key columns of child classes also!!?? - foreach ($class->associationMappings as $assoc) { - if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) { - if (isset($assoc['inherited'])) { - $owningClass = $this->_em->getClassMetadata($assoc['inherited']); - $sqlTableAlias = $this->getSQLTableAlias($owningClass->table['name'], $dqlAlias); - } else { - $sqlTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias); - } - - foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { - $columnAlias = $this->getSQLColumnAlias($srcColumn); - - $sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias; - - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addMetaResult($dqlAlias, $this->_platform->getSQLResultCasing($columnAlias), $srcColumn, (isset($assoc['id']) && $assoc['id'] === true)); - } - } - } + // 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; } - } else { - // Add foreign key columns to SQL, if necessary - if ($addMetaColumns) { - $sqlTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias); - foreach ($class->associationMappings as $assoc) { - if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) { - foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { - $columnAlias = $this->getSQLColumnAlias($srcColumn); - - $sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias; - - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addMetaResult($dqlAlias, $this->_platform->getSQLResultCasing($columnAlias), $srcColumn, (isset($assoc['id']) && $assoc['id'] === true)); - } - } + + $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; @@ -619,12 +709,12 @@ class SqlWalker implements TreeWalker $rangeDecl = $identificationVariableDecl->rangeVariableDeclaration; $dqlAlias = $rangeDecl->aliasIdentificationVariable; - + $this->_rootAliases[] = $dqlAlias; $class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName); $sql .= $class->getQuotedTableName($this->_platform) . ' ' - . $this->getSQLTableAlias($class->table['name'], $dqlAlias); + . $this->getSQLTableAlias($class->getTableName(), $dqlAlias); if ($class->isInheritanceTypeJoined()) { $sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias); @@ -635,10 +725,17 @@ class SqlWalker implements TreeWalker } if ($identificationVariableDecl->indexBy) { - $this->_rsm->addIndexBy( - $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->identificationVariable, - $identificationVariableDecl->indexBy->simpleStateFieldPathExpression->field - ); + $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)); @@ -665,15 +762,13 @@ class SqlWalker implements TreeWalker */ public function walkOrderByClause($orderByClause) { - $colSql = $this->_generateOrderedCollectionOrderByItems(); - if ($colSql != '') { - $colSql = ", ".$colSql; + $orderByItems = array_map(array($this, 'walkOrderByItem'), $orderByClause->orderByItems); + + if (($collectionOrderByItems = $this->_generateOrderedCollectionOrderByItems()) !== '') { + $orderByItems = array_merge($orderByItems, (array) $collectionOrderByItems); } - // OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}* - return ' ORDER BY ' . implode( - ', ', array_map(array($this, 'walkOrderByItem'), $orderByClause->orderByItems) - ) . $colSql; + return ' ORDER BY ' . implode(', ', $orderByItems); } /** @@ -684,16 +779,10 @@ class SqlWalker implements TreeWalker */ public function walkOrderByItem($orderByItem) { - $sql = ''; $expr = $orderByItem->expression; - - if ($expr instanceof AST\PathExpression) { - $sql = $this->walkPathExpression($expr); - } else { - $columnName = $this->_queryComponents[$expr]['token']['value']; - - $sql = $this->_scalarResultAliasMap[$columnName]; - } + $sql = ($expr instanceof AST\PathExpression) + ? $this->walkPathExpression($expr) + : $this->walkResultVariable($this->_queryComponents[$expr]['token']['value']); return $sql . ' ' . strtoupper($orderByItem->type); } @@ -717,8 +806,11 @@ class SqlWalker implements TreeWalker */ public function walkJoinVariableDeclaration($joinVarDecl) { - $join = $joinVarDecl->join; + $join = $joinVarDecl->join; $joinType = $join->joinType; + $sql = ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) + ? ' LEFT JOIN ' + : ' INNER JOIN '; if ($joinVarDecl->indexBy) { // For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently. @@ -728,20 +820,16 @@ class SqlWalker implements TreeWalker ); } - if ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) { - $sql = ' LEFT JOIN '; - } else { - $sql = ' INNER JOIN '; - } - $joinAssocPathExpr = $join->joinAssociationPathExpression; - $joinedDqlAlias = $join->aliasIdentificationVariable; - $relation = $this->_queryComponents[$joinedDqlAlias]['relation']; - $targetClass = $this->_em->getClassMetadata($relation['targetEntity']); - $sourceClass = $this->_em->getClassMetadata($relation['sourceEntity']); + $joinedDqlAlias = $join->aliasIdentificationVariable; + + $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->table['name'], $joinedDqlAlias); - $sourceTableAlias = $this->getSQLTableAlias($sourceClass->table['name'], $joinAssocPathExpr->identificationVariable); + + $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName(), $joinedDqlAlias); + $sourceTableAlias = $this->getSQLTableAlias($sourceClass->getTableName(), $joinAssocPathExpr->identificationVariable); // Ensure we got the owning side, since it has all mapping info $assoc = ( ! $relation['isOwningSide']) ? $targetClass->associationMappings[$relation['mappedBy']] : $relation; @@ -765,7 +853,6 @@ class SqlWalker implements TreeWalker // 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. if ($assoc['type'] & ClassMetadata::TO_ONE) { - $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON '; $first = true; @@ -788,6 +875,7 @@ class SqlWalker implements TreeWalker $sql .= $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn; } } + } else if ($assoc['type'] == ClassMetadata::MANY_TO_MANY) { // Join relation table $joinTable = $assoc['joinTable']; @@ -822,8 +910,7 @@ class SqlWalker implements TreeWalker } // Join target table - $sql .= ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) - ? ' LEFT JOIN ' : ' INNER JOIN '; + $sql .= ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) ? ' LEFT JOIN ' : ' INNER JOIN '; $sql .= $targetTableName . ' ' . $targetTableAlias . ' ON '; $first = true; @@ -854,6 +941,11 @@ class SqlWalker implements TreeWalker } } + // Apply the filters + if ($filterExpr = $this->generateFilterConditionSQL($targetClass, $targetTableAlias)) { + $sql .= ' AND ' . $filterExpr; + } + // Handle WITH clause if (($condExpr = $join->conditionalExpression) !== null) { // Phase 2 AST optimization: Skip processment of ConditionalExpression @@ -874,7 +966,33 @@ class SqlWalker implements TreeWalker 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. * @@ -884,32 +1002,18 @@ class SqlWalker implements TreeWalker public function walkCoalesceExpression($coalesceExpression) { $sql = 'COALESCE('; - + $scalarExpressions = array(); - + foreach ($coalesceExpression->scalarExpressions as $scalarExpression) { $scalarExpressions[] = $this->walkSimpleArithmeticExpression($scalarExpression); } - + $sql .= implode(', ', $scalarExpressions) . ')'; - + return $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); - - default: - return ''; - } - } - + /** * Walks down a NullIfExpression AST node and generates the corresponding SQL. * @@ -918,17 +1022,57 @@ class SqlWalker implements TreeWalker */ public function walkNullIfExpression($nullIfExpression) { - $firstExpression = is_string($nullIfExpression->firstExpression) + $firstExpression = is_string($nullIfExpression->firstExpression) ? $this->_conn->quote($nullIfExpression->firstExpression) : $this->walkSimpleArithmeticExpression($nullIfExpression->firstExpression); - - $secondExpression = is_string($nullIfExpression->secondExpression) + + $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. * @@ -937,202 +1081,173 @@ class SqlWalker implements TreeWalker */ public function walkSelectExpression($selectExpression) { - $sql = ''; - $expr = $selectExpression->expression; - - if ($expr instanceof AST\PathExpression) { - if ($expr->type == AST\PathExpression::TYPE_STATE_FIELD) { - $fieldName = $expr->field; - $dqlAlias = $expr->identificationVariable; - $qComp = $this->_queryComponents[$dqlAlias]; - $class = $qComp['metadata']; + $sql = ''; + $expr = $selectExpression->expression; + $hidden = $selectExpression->hiddenAliasResultVariable; - if ( ! $selectExpression->fieldIdentificationVariable) { - $resultAlias = $fieldName; - } else { - $resultAlias = $selectExpression->fieldIdentificationVariable; + switch (true) { + case ($expr instanceof AST\PathExpression): + if ($expr->type !== AST\PathExpression::TYPE_STATE_FIELD) { + throw QueryException::invalidPathExpression($expr->type); } - if ($class->isInheritanceTypeJoined()) { - $tableName = $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName); - } else { - $tableName = $class->getTableName(); - } + $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 = $class->getQuotedColumnName($fieldName, $this->_platform); + $columnName = $class->getQuotedColumnName($fieldName, $this->_platform); + $columnAlias = $this->getSQLColumnAlias($class->fieldMappings[$fieldName]['columnName']); - $columnAlias = $this->getSQLColumnAlias($columnName); - $sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias; - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addScalarResult($columnAlias, $resultAlias); - } else { - throw QueryException::invalidPathExpression($expr->type); - } - } - else if ($expr instanceof AST\AggregateExpression) { - if ( ! $selectExpression->fieldIdentificationVariable) { - $resultAlias = $this->_scalarResultCounter++; - } else { - $resultAlias = $selectExpression->fieldIdentificationVariable; - } + $col = $sqlTableAlias . '.' . $columnName; - $columnAlias = 'sclr' . $this->_aliasCounter++; - $sql .= $this->walkAggregateExpression($expr) . ' AS ' . $columnAlias; - $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; + $fieldType = $class->getTypeOfField($fieldName); - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addScalarResult($columnAlias, $resultAlias); - } - else if ($expr instanceof AST\Subselect) { - if ( ! $selectExpression->fieldIdentificationVariable) { - $resultAlias = $this->_scalarResultCounter++; - } else { - $resultAlias = $selectExpression->fieldIdentificationVariable; - } + if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { + $type = Type::getType($fieldType); + $col = $type->convertToPHPValueSQL($col, $this->_conn->getDatabasePlatform()); + } - $columnAlias = 'sclr' . $this->_aliasCounter++; - $sql .= '(' . $this->walkSubselect($expr) . ') AS '.$columnAlias; - $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; + $sql .= $col . ' AS ' . $columnAlias; - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addScalarResult($columnAlias, $resultAlias); - } - else if ($expr instanceof AST\Functions\FunctionNode) { - if ( ! $selectExpression->fieldIdentificationVariable) { - $resultAlias = $this->_scalarResultCounter++; - } else { - $resultAlias = $selectExpression->fieldIdentificationVariable; - } + $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; - $columnAlias = 'sclr' . $this->_aliasCounter++; - $sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias; - $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; - - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addScalarResult($columnAlias, $resultAlias); - } else if ( - $expr instanceof AST\SimpleArithmeticExpression || - $expr instanceof AST\ArithmeticTerm || - $expr instanceof AST\ArithmeticFactor || - $expr instanceof AST\ArithmeticPrimary || - $expr instanceof AST\Literal - ) { - if ( ! $selectExpression->fieldIdentificationVariable) { - $resultAlias = $this->_scalarResultCounter++; - } else { - $resultAlias = $selectExpression->fieldIdentificationVariable; - } + if ( ! $hidden) { + $this->_rsm->addScalarResult($columnAlias, $resultAlias, $fieldType); + $this->_scalarFields[$dqlAlias][$fieldName] = $columnAlias; + } + break; - $columnAlias = 'sclr' . $this->_aliasCounter++; - - if ($expr instanceof AST\Literal) { - $sql .= $this->walkLiteral($expr) . ' AS ' .$columnAlias; - } else { - $sql .= $this->walkSimpleArithmeticExpression($expr) . ' AS ' . $columnAlias; - } - - $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; - - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addScalarResult($columnAlias, $resultAlias); - } else if ( - $expr instanceof AST\NullIfExpression || - $expr instanceof AST\CoalesceExpression || - $expr instanceof AST\CaseExpression - ) { - if ( ! $selectExpression->fieldIdentificationVariable) { - $resultAlias = $this->_scalarResultCounter++; - } else { - $resultAlias = $selectExpression->fieldIdentificationVariable; - } + 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++; - $columnAlias = 'sclr' . $this->_aliasCounter++; - - $sql .= $this->walkCaseExpression($expr) . ' AS ' . $columnAlias; - - $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; + $sql .= $expr->dispatch($this) . ' AS ' . $columnAlias; - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addScalarResult($columnAlias, $resultAlias); - } else { - // IdentificationVariable or PartialObjectExpression - if ($expr instanceof AST\PartialObjectExpression) { - $dqlAlias = $expr->identificationVariable; - $partialFieldSet = $expr->partialFieldSet; - } else { - $dqlAlias = $expr; - $partialFieldSet = array(); - } + $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; - $queryComp = $this->_queryComponents[$dqlAlias]; - $class = $queryComp['metadata']; + if ( ! $hidden) { + // We cannot resolve field type here; assume 'string'. + $this->_rsm->addScalarResult($columnAlias, $resultAlias, 'string'); + } + break; - if ( ! isset($this->_selectedClasses[$dqlAlias])) { - $this->_selectedClasses[$dqlAlias] = $class; - } + case ($expr instanceof AST\Subselect): + $columnAlias = $this->getSQLColumnAlias('sclr'); + $resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++; - $beginning = true; - // Select all fields from the queried class - foreach ($class->fieldMappings as $fieldName => $mapping) { - if ($partialFieldSet && !in_array($fieldName, $partialFieldSet)) { - continue; + $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; - if (isset($mapping['inherited'])) { - $tableName = $this->_em->getClassMetadata($mapping['inherited'])->table['name']; + default: + // IdentificationVariable or PartialObjectExpression + if ($expr instanceof AST\PartialObjectExpression) { + $dqlAlias = $expr->identificationVariable; + $partialFieldSet = $expr->partialFieldSet; } else { - $tableName = $class->table['name']; + $dqlAlias = $expr; + $partialFieldSet = array(); } - if ($beginning) $beginning = false; else $sql .= ', '; + $queryComp = $this->_queryComponents[$dqlAlias]; + $class = $queryComp['metadata']; + $resultAlias = $selectExpression->fieldIdentificationVariable ?: null; - $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); - $columnAlias = $this->getSQLColumnAlias($mapping['columnName']); - $sql .= $sqlTableAlias . '.' . $class->getQuotedColumnName($fieldName, $this->_platform) - . ' AS ' . $columnAlias; + if ( ! isset($this->_selectedClasses[$dqlAlias])) { + $this->_selectedClasses[$dqlAlias] = array( + 'class' => $class, + 'dqlAlias' => $dqlAlias, + 'resultAlias' => $resultAlias + ); + } - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name); - } + $sqlParts = array(); - // 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->table['name'], $dqlAlias); - foreach ($subClass->fieldMappings as $fieldName => $mapping) { - if (isset($mapping['inherited']) || $partialFieldSet && !in_array($fieldName, $partialFieldSet)) { - continue; - } + // 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(); - if ($beginning) $beginning = false; else $sql .= ', '; + $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); + $columnAlias = $this->getSQLColumnAlias($mapping['columnName']); + $quotedColumnName = $class->getQuotedColumnName($fieldName, $this->_platform); - $columnAlias = $this->getSQLColumnAlias($mapping['columnName']); - $sql .= $sqlTableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform) - . ' AS ' . $columnAlias; + $col = $sqlTableAlias . '.' . $quotedColumnName; - $columnAlias = $this->_platform->getSQLResultCasing($columnAlias); - $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName); + if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { + $type = Type::getType($class->getTypeOfField($fieldName)); + $col = $type->convertToPHPValueSQL($col, $this->_platform); } - // Add join columns (foreign keys) of the subclass - //TODO: Probably better do this in walkSelectClause to honor the INCLUDE_META_COLUMNS hint - foreach ($subClass->associationMappings as $fieldName => $assoc) { - if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE && ! isset($assoc['inherited'])) { - foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { - if ($beginning) $beginning = false; else $sql .= ', '; - $columnAlias = $this->getSQLColumnAlias($srcColumn); - $sql .= $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias; - $this->_rsm->addMetaResult($dqlAlias, $this->_platform->getSQLResultCasing($columnAlias), $srcColumn); + $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 = $subClass->getQuotedColumnName($fieldName, $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; @@ -1146,8 +1261,7 @@ class SqlWalker implements TreeWalker */ public function walkQuantifiedExpression($qExpr) { - return ' ' . strtoupper($qExpr->type) - . '(' . $this->walkSubselect($qExpr->subselect) . ')'; + return ' ' . strtoupper($qExpr->type) . '(' . $this->walkSubselect($qExpr->subselect) . ')'; } /** @@ -1158,16 +1272,21 @@ class SqlWalker implements TreeWalker */ public function walkSubselect($subselect) { - $useAliasesBefore = $this->_useSqlTableAliases; + $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->walkSimpleSelectClause($subselect->simpleSelectClause); $sql .= $this->walkSubselectFromClause($subselect->subselectFromClause); - $sql .= $subselect->whereClause ? $this->walkWhereClause($subselect->whereClause) : ''; + $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; @@ -1188,11 +1307,13 @@ class SqlWalker implements TreeWalker $sql = ''; $rangeDecl = $subselectIdVarDecl->rangeVariableDeclaration; - $dqlAlias = $rangeDecl->aliasIdentificationVariable; + $dqlAlias = $rangeDecl->aliasIdentificationVariable; $class = $this->_em->getClassMetadata($rangeDecl->abstractSchemaName); $sql .= $class->getQuotedTableName($this->_platform) . ' ' - . $this->getSQLTableAlias($class->table['name'], $dqlAlias); + . $this->getSQLTableAlias($class->getTableName(), $dqlAlias); + + $this->_rootAliases[] = $dqlAlias; if ($class->isInheritanceTypeJoined()) { $sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias); @@ -1230,74 +1351,50 @@ class SqlWalker implements TreeWalker { $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): - $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++; - - $columnAlias = 'sclr' . $this->_aliasCounter++; - $this->_scalarResultAliasMap[$alias] = $columnAlias; - - $sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias; - break; - 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): - $alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++; - - $columnAlias = 'sclr' . $this->_aliasCounter++; - $this->_scalarResultAliasMap[$alias] = $columnAlias; - - $sql .= $this->walkSimpleArithmeticExpression($expr) . ' AS ' . $columnAlias; - break; - 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 = 'sclr' . $this->_aliasCounter++; + + $columnAlias = $this->getSQLColumnAlias('sclr'); $this->_scalarResultAliasMap[$alias] = $columnAlias; - - $sql .= $this->walkCaseExpression($expr) . ' AS ' . $columnAlias; + + $sql .= $expr->dispatch($this) . ' AS ' . $columnAlias; break; - - default: // IdentificationVariable - $class = $this->_queryComponents[$expr]['metadata']; - $tableAlias = $this->getSQLTableAlias($class->getTableName(), $expr); - $sqlParts = array(); - foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) { - $sqlParts[] = $tableAlias . '.' . $columnName; - } - - $sql .= implode(', ', $sqlParts); + default: // IdentificationVariable + $sql .= $this->walkEntityIdentificationVariable($expr); break; } - + return $sql; } @@ -1322,22 +1419,11 @@ class SqlWalker implements TreeWalker public function walkGroupByClause($groupByClause) { $sqlParts = array(); - + foreach ($groupByClause->groupByItems AS $groupByItem) { - if ( ! is_string($groupByItem)) { - $sqlParts[] = $this->walkGroupByItem($groupByItem); - - continue; - } - - foreach ($this->_queryComponents[$groupByItem]['metadata']->identifier AS $idField) { - $groupByItem = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $idField); - $groupByItem->type = AST\PathExpression::TYPE_STATE_FIELD; - - $sqlParts[] = $this->walkGroupByItem($groupByItem); - } + $sqlParts[] = $this->walkGroupByItem($groupByItem); } - + return ' GROUP BY ' . implode(', ', $sqlParts); } @@ -1347,9 +1433,38 @@ class SqlWalker implements TreeWalker * @param GroupByItem * @return string The SQL. */ - public function walkGroupByItem(AST\PathExpression $pathExpr) + public function walkGroupByItem($groupByItem) { - return $this->walkPathExpression($pathExpr); + // 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); } /** @@ -1363,7 +1478,7 @@ class SqlWalker implements TreeWalker $class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName); $tableName = $class->getTableName(); $sql = 'DELETE FROM ' . $class->getQuotedTableName($this->_platform); - + $this->setSQLTableAlias($tableName, $tableName, $deleteClause->aliasIdentificationVariable); $this->_rootAliases[] = $deleteClause->aliasIdentificationVariable; @@ -1381,7 +1496,7 @@ class SqlWalker implements TreeWalker $class = $this->_em->getClassMetadata($updateClause->abstractSchemaName); $tableName = $class->getTableName(); $sql = 'UPDATE ' . $class->getQuotedTableName($this->_platform); - + $this->setSQLTableAlias($tableName, $tableName, $updateClause->aliasIdentificationVariable); $this->_rootAliases[] = $updateClause->aliasIdentificationVariable; @@ -1408,11 +1523,11 @@ class SqlWalker implements TreeWalker case ($newValue instanceof AST\Node): $sql .= $newValue->dispatch($this); break; - + case ($newValue === null): $sql .= 'NULL'; break; - + default: $sql .= $this->_conn->quote($newValue); break; @@ -1425,19 +1540,40 @@ class SqlWalker implements TreeWalker /** * 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); - $condSql = $this->walkConditionalExpression($whereClause->conditionalExpression); + + 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; } @@ -1458,7 +1594,7 @@ class SqlWalker implements TreeWalker if ( ! ($condExpr instanceof AST\ConditionalExpression)) { return $this->walkConditionalTerm($condExpr); } - + return implode(' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->conditionalTerms)); } @@ -1475,7 +1611,7 @@ class SqlWalker implements TreeWalker if ( ! ($condTerm instanceof AST\ConditionalTerm)) { return $this->walkConditionalFactor($condTerm); } - + return implode(' AND ', array_map(array($this, 'walkConditionalFactor'), $condTerm->conditionalFactors)); } @@ -1504,8 +1640,8 @@ class SqlWalker implements TreeWalker { if ($primary->isSimpleConditionalExpression()) { return $primary->simpleConditionalExpression->dispatch($this); - } - + } + if ($primary->isConditionalExpression()) { $condExpr = $primary->conditionalExpression; @@ -1538,115 +1674,116 @@ class SqlWalker implements TreeWalker { $sql = $collMemberExpr->not ? 'NOT ' : ''; $sql .= 'EXISTS (SELECT 1 FROM '; - $entityExpr = $collMemberExpr->entityExpression; + + $entityExpr = $collMemberExpr->entityExpression; $collPathExpr = $collMemberExpr->collectionValuedPathExpression; - + $fieldName = $collPathExpr->field; - $dqlAlias = $collPathExpr->identificationVariable; - + $dqlAlias = $collPathExpr->identificationVariable; + $class = $this->_queryComponents[$dqlAlias]['metadata']; - - if ($entityExpr instanceof AST\InputParameter) { - $dqlParamKey = $entityExpr->name; - $entity = $this->_query->getParameter($dqlParamKey); - } else { - //TODO - throw new \BadMethodCallException("Not implemented"); + + switch (true) { + // InputParameter + case ($entityExpr instanceof AST\InputParameter): + $dqlParamKey = $entityExpr->name; + $entity = $this->_query->getParameter($dqlParamKey); + $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->table['name']); - $sourceTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias); - - $sql .= $targetClass->getQuotedTableName($this->_platform) - . ' ' . $targetTableAlias . ' WHERE '; - + $targetClass = $this->_em->getClassMetadata($assoc['targetEntity']); + $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName()); + $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); + + $sql .= $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' WHERE '; + $owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']]; - - $first = true; - + $sqlParts = array(); + foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) { - if ($first) $first = false; else $sql .= ' AND '; - - $sql .= $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$targetColumn], $this->_platform) - . ' = ' - . $targetTableAlias . '.' . $sourceColumn; + $targetColumn = $class->getQuotedColumnName($class->fieldNames[$targetColumn], $this->_platform); + + $sqlParts[] = $sourceTableAlias . '.' . $targetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn; } - - $sql .= ' AND '; - $first = true; - + foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) { - if ($first) $first = false; else $sql .= ' AND '; - - $this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++); - $sql .= $targetTableAlias . '.' . $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->table['name']); - $sourceTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias); - + $joinTableAlias = $this->getSQLTableAlias($joinTable['name']); + $targetTableAlias = $this->getSQLTableAlias($targetClass->getTableName()); + $sourceTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias); + // join to target table - $sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $this->_platform) - . ' ' . $joinTableAlias . ' INNER JOIN ' - . $targetClass->getQuotedTableName($this->_platform) - . ' ' . $targetTableAlias . ' ON '; - + $sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $this->_platform) . ' ' . $joinTableAlias + . ' INNER JOIN ' . $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' ON '; + // join conditions - $joinColumns = $assoc['isOwningSide'] - ? $joinTable['inverseJoinColumns'] - : $joinTable['joinColumns']; + $joinColumns = $assoc['isOwningSide'] ? $joinTable['inverseJoinColumns'] : $joinTable['joinColumns']; + $joinSqlParts = array(); - $first = true; foreach ($joinColumns as $joinColumn) { - if ($first) $first = false; else $sql .= ' AND '; + $targetColumn = $targetClass->getQuotedColumnName( + $targetClass->fieldNames[$joinColumn['referencedColumnName']], + $this->_platform + ); - $sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = ' - . $targetTableAlias . '.' . $targetClass->getQuotedColumnName( - $targetClass->fieldNames[$joinColumn['referencedColumnName']], - $this->_platform); + $joinSqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $targetTableAlias . '.' . $targetColumn; } + $sql .= implode(' AND ', $joinSqlParts); $sql .= ' WHERE '; - $joinColumns = $assoc['isOwningSide'] - ? $joinTable['joinColumns'] - : $joinTable['inverseJoinColumns']; + $joinColumns = $assoc['isOwningSide'] ? $joinTable['joinColumns'] : $joinTable['inverseJoinColumns']; + $sqlParts = array(); - $first = true; foreach ($joinColumns as $joinColumn) { - if ($first) $first = false; else $sql .= ' AND '; + $targetColumn = $class->getQuotedColumnName( + $class->fieldNames[$joinColumn['referencedColumnName']], + $this->_platform + ); - $sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = ' - . $sourceTableAlias . '.' . $class->getQuotedColumnName( - $class->fieldNames[$joinColumn['referencedColumnName']], - $this->_platform); + $sqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $sourceTableAlias . '.' . $targetColumn; } - - $sql .= ' AND '; - $first = true; - + foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) { - if ($first) $first = false; else $sql .= ' AND '; - - $this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++); - $sql .= $targetTableAlias . '.' . $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. * @@ -1693,10 +1830,9 @@ class SqlWalker implements TreeWalker */ public function walkInExpression($inExpr) { - $sql = $this->walkPathExpression($inExpr->pathExpression) - . ($inExpr->not ? ' NOT' : '') . ' IN ('; + $sql = $this->walkArithmeticExpression($inExpr->expression) . ($inExpr->not ? ' NOT' : '') . ' IN ('; - $sql .= ($inExpr->subselect) + $sql .= ($inExpr->subselect) ? $this->walkSubselect($inExpr->subselect) : implode(', ', array_map(array($this, 'walkInParameter'), $inExpr->literals)); @@ -1724,37 +1860,44 @@ class SqlWalker implements TreeWalker } if ($this->_useSqlTableAliases) { - $sql .= $this->getSQLTableAlias($discrClass->table['name'], $dqlAlias) . '.'; + $sql .= $this->getSQLTableAlias($discrClass->getTableName(), $dqlAlias) . '.'; } - $sql .= $class->discriminatorColumn['name'] . ($instanceOfExpr->not ? ' <> ' : ' = '); + $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; + $paramValue = $this->_query->getParameter($dqlParamKey); - if ($instanceOfExpr->value instanceof AST\InputParameter) { - // We need to modify the parameter value to be its correspondent mapped value - $dqlParamKey = $instanceOfExpr->value->name; - $paramValue = $this->_query->getParameter($dqlParamKey); - - if ( ! ($paramValue instanceof \Doctrine\ORM\Mapping\ClassMetadata)) { - throw QueryException::invalidParameterType('ClassMetadata', get_class($paramValue)); + 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; } - - $entityClassName = $paramValue->name; - } else { - // Get name from ClassMetadata to resolve aliases. - $entityClassName = $this->_em->getClassMetadata($instanceOfExpr->value)->name; - } - if ($entityClassName == $class->name) { - $sql .= $this->_conn->quote($class->discriminatorValue); - } else { - $discrMap = array_flip($class->discriminatorMap); - if (!isset($discrMap[$entityClassName])) { - throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName); + 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 .= $this->_conn->quote($discrMap[$entityClassName]); } + $sql .= '(' . implode(', ', $sqlParameterList) . ')'; + return $sql; } @@ -1766,8 +1909,8 @@ class SqlWalker implements TreeWalker */ public function walkInParameter($inParam) { - return $inParam instanceof AST\InputParameter - ? $this->walkInputParameter($inParam) + return $inParam instanceof AST\InputParameter + ? $this->walkInputParameter($inParam) : $this->walkLiteral($inParam); } @@ -1782,12 +1925,16 @@ class SqlWalker implements TreeWalker 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 is_string($boolVal) ? $this->_conn->quote($boolVal) : $boolVal; + + return $boolVal; + case AST\Literal::NUMERIC: return $literal->value; + default: throw QueryException::invalidLiteral($literal); } @@ -1860,14 +2007,14 @@ class SqlWalker implements TreeWalker $leftExpr = $compExpr->leftExpression; $rightExpr = $compExpr->rightExpression; $sql = ''; - - $sql .= ($leftExpr instanceof AST\Node) + + $sql .= ($leftExpr instanceof AST\Node) ? $leftExpr->dispatch($this) : (is_numeric($leftExpr) ? $leftExpr : $this->_conn->quote($leftExpr)); $sql .= ' ' . $compExpr->operator . ' '; - $sql .= ($rightExpr instanceof AST\Node) + $sql .= ($rightExpr instanceof AST\Node) ? $rightExpr->dispatch($this) : (is_numeric($rightExpr) ? $rightExpr : $this->_conn->quote($rightExpr)); @@ -1911,7 +2058,7 @@ class SqlWalker implements TreeWalker if ( ! ($simpleArithmeticExpr instanceof AST\SimpleArithmeticExpression)) { return $this->walkArithmeticTerm($simpleArithmeticExpr); } - + return implode(' ', array_map(array($this, 'walkArithmeticTerm'), $simpleArithmeticExpr->arithmeticTerms)); } @@ -1924,13 +2071,9 @@ class SqlWalker implements TreeWalker public function walkArithmeticTerm($term) { if (is_string($term)) { - if (isset($this->_queryComponents[$term])) { - $columnName = $this->_queryComponents[$term]['token']['value']; - - return $this->_scalarResultAliasMap[$columnName]; - } - - return $term; + return (isset($this->_queryComponents[$term])) + ? $this->walkResultVariable($this->_queryComponents[$term]['token']['value']) + : $term; } // Phase 2 AST optimization: Skip processment of ArithmeticTerm @@ -1938,7 +2081,7 @@ class SqlWalker implements TreeWalker if ( ! ($term instanceof AST\ArithmeticTerm)) { return $this->walkArithmeticFactor($term); } - + return implode(' ', array_map(array($this, 'walkArithmeticFactor'), $term->arithmeticFactors)); } @@ -1953,15 +2096,15 @@ class SqlWalker implements TreeWalker 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); } @@ -1975,14 +2118,13 @@ class SqlWalker implements TreeWalker { if ($primary instanceof AST\SimpleArithmeticExpression) { return '(' . $this->walkSimpleArithmeticExpression($primary) . ')'; - } - + } + if ($primary instanceof AST\Node) { return $primary->dispatch($this); } - // TODO: We need to deal with IdentificationVariable here - return ''; + return $this->walkEntityIdentificationVariable($primary); } /** @@ -1997,4 +2139,21 @@ class SqlWalker implements TreeWalker ? $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/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalker.php b/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalker.php index 4bbe963a6a..84628981c5 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalker.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalker.php @@ -168,7 +168,7 @@ interface TreeWalker * @param GroupByItem * @return string The SQL. */ - function walkGroupByItem(AST\PathExpression $pathExpr); + function walkGroupByItem($groupByItem); /** * Walks down an UpdateStatement AST node, thereby generating the appropriate SQL. @@ -394,6 +394,14 @@ interface TreeWalker */ 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. * diff --git a/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalkerAdapter.php b/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalkerAdapter.php index 0f940ffec1..5907aa94b7 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalkerAdapter.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalkerAdapter.php @@ -24,7 +24,7 @@ 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 */ @@ -33,7 +33,7 @@ abstract class TreeWalkerAdapter implements TreeWalker private $_query; private $_parserResult; private $_queryComponents; - + /** * {@inheritdoc} */ @@ -71,7 +71,7 @@ abstract class TreeWalkerAdapter implements TreeWalker { return $this->_parserResult; } - + /** * Walks down a SelectStatement AST node, thereby generating the appropriate SQL. * @@ -202,7 +202,7 @@ abstract class TreeWalkerAdapter implements TreeWalker * @param GroupByItem * @return string The SQL. */ - public function walkGroupByItem(AST\PathExpression $pathExpr) {} + public function walkGroupByItem($groupByItem) {} /** * Walks down an UpdateStatement AST node, thereby generating the appropriate SQL. @@ -291,7 +291,7 @@ abstract class TreeWalkerAdapter implements TreeWalker * @return string The SQL. */ public function walkExistsExpression($existsExpr) {} - + /** * Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL. * @@ -427,10 +427,18 @@ abstract class TreeWalkerAdapter implements TreeWalker * @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/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalkerChain.php b/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalkerChain.php index 1fc1977835..d3891a1144 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalkerChain.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Query/TreeWalkerChain.php @@ -25,7 +25,7 @@ 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 */ @@ -39,7 +39,7 @@ class TreeWalkerChain implements TreeWalker private $_parserResult; /** The query components of the original query (the "symbol table") that was produced by the Parser. */ private $_queryComponents; - + /** * @inheritdoc */ @@ -49,17 +49,17 @@ class TreeWalkerChain implements TreeWalker $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. * @@ -270,10 +270,10 @@ class TreeWalkerChain implements TreeWalker * @param GroupByItem * @return string The SQL. */ - public function walkGroupByItem(AST\PathExpression $pathExpr) + public function walkGroupByItem($groupByItem) { foreach ($this->_walkers as $walker) { - $walker->walkGroupByItem($pathExpr); + $walker->walkGroupByItem($groupByItem); } } @@ -419,7 +419,7 @@ class TreeWalkerChain implements TreeWalker $walker->walkExistsExpression($existsExpr); } } - + /** * Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL. * @@ -640,10 +640,23 @@ class TreeWalkerChain implements TreeWalker $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/main/inc/lib/symfony/Doctrine/ORM/QueryBuilder.php b/main/inc/lib/symfony/Doctrine/ORM/QueryBuilder.php index ed2a12b1c6..521263495c 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/QueryBuilder.php +++ b/main/inc/lib/symfony/Doctrine/ORM/QueryBuilder.php @@ -75,7 +75,7 @@ class QueryBuilder * @var string The complete DQL string for this query. */ private $_dql; - + /** * @var array The query parameters. */ @@ -85,12 +85,12 @@ class QueryBuilder * @var array The parameter type map of this query. */ private $_paramTypes = array(); - + /** * @var integer The index of the first result to retrieve. */ private $_firstResult = null; - + /** * @var integer The maximum number of results to retrieve. */ @@ -98,7 +98,7 @@ class QueryBuilder /** * Initializes a new QueryBuilder that uses the given EntityManager. - * + * * @param EntityManager $em The EntityManager to use. */ public function __construct(EntityManager $em) @@ -218,7 +218,7 @@ class QueryBuilder ->setFirstResult($this->_firstResult) ->setMaxResults($this->_maxResults); } - + /** * Gets the FIRST root alias of the query. This is the first entity alias involved * in the construction of the query. @@ -257,7 +257,7 @@ class QueryBuilder public function getRootAliases() { $aliases = array(); - + foreach ($this->_dqlParts['from'] as &$fromClause) { if (is_string($fromClause)) { $spacePos = strrpos($fromClause, ' '); @@ -266,10 +266,10 @@ class QueryBuilder $fromClause = new Query\Expr\From($from, $alias); } - + $aliases[] = $fromClause->getAlias(); } - + return $aliases; } @@ -290,7 +290,7 @@ class QueryBuilder public function getRootEntities() { $entities = array(); - + foreach ($this->_dqlParts['from'] as &$fromClause) { if (is_string($fromClause)) { $spacePos = strrpos($fromClause, ' '); @@ -299,10 +299,10 @@ class QueryBuilder $fromClause = new Query\Expr\From($from, $alias); } - + $entities[] = $fromClause->getFrom(); } - + return $entities; } @@ -314,7 +314,7 @@ class QueryBuilder * ->select('u') * ->from('User', 'u') * ->where('u.id = :user_id') - * ->setParameter(':user_id', 1); + * ->setParameter('user_id', 1); * * * @param string|integer $key The parameter position or name. @@ -324,16 +324,18 @@ class QueryBuilder */ public function setParameter($key, $value, $type = null) { + $key = trim($key, ':'); + if ($type === null) { $type = Query\ParameterTypeInferer::inferType($value); } - + $this->_paramTypes[$key] = $type; $this->_params[$key] = $value; - + return $this; } - + /** * Sets a collection of query parameters for the query being constructed. * @@ -345,7 +347,7 @@ class QueryBuilder * ->setParameters(array( * 'user_id1' => 1, * 'user_id2' => 2 - * )); + )); * * * @param array $params The query parameters to set. @@ -354,12 +356,9 @@ class QueryBuilder public function setParameters(array $params, array $types = array()) { foreach ($params as $key => $value) { - if (isset($types[$key])) { - $this->setParameter($key, $value, $types[$key]); - } else { - $this->setParameter($key, $value); - } + $this->setParameter($key, $value, isset($types[$key]) ? $types[$key] : null); } + return $this; } @@ -375,7 +374,7 @@ class QueryBuilder /** * 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. */ @@ -393,36 +392,38 @@ class QueryBuilder 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() @@ -436,15 +437,15 @@ class QueryBuilder * The available parts are: 'select', 'from', 'join', 'set', 'where', * 'groupBy', 'having' and 'orderBy'. * - * @param string $dqlPartName - * @param string $dqlPart - * @param string $append + * @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') { @@ -458,11 +459,11 @@ class QueryBuilder } $dqlPart = $newDqlPart; } - + if ($append && $isMultiple) { if (is_array($dqlPart)) { $key = key($dqlPart); - + $this->_dqlParts[$dqlPartName][$key][] = $dqlPart[$key]; } else { $this->_dqlParts[$dqlPartName][] = $dqlPart; @@ -493,11 +494,11 @@ class QueryBuilder 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); @@ -539,11 +540,11 @@ class QueryBuilder 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); @@ -557,7 +558,7 @@ class QueryBuilder * $qb = $em->createQueryBuilder() * ->delete('User', 'u') * ->where('u.id = :user_id'); - * ->setParameter(':user_id', 1); + * ->setParameter('user_id', 1); * * * @param string $delete The class/type whose instances are subject to the deletion. @@ -613,11 +614,12 @@ class QueryBuilder * * @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) + public function from($from, $alias, $indexBy = null) { - return $this->add('from', new Expr\From($from, $alias), true); + return $this->add('from', new Expr\From($from, $alias, $indexBy), true); } /** @@ -648,7 +650,7 @@ class QueryBuilder /** * 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. @@ -669,13 +671,16 @@ class QueryBuilder public function innerJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null) { $rootAlias = substr($join, 0, strpos($join, '.')); - if (!in_array($rootAlias, $this->getRootAliases())) { + + if ( ! in_array($rootAlias, $this->getRootAliases())) { $rootAlias = $this->getRootAlias(); } - - return $this->add('join', array( - $rootAlias => new Expr\Join(Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy) - ), true); + + $join = new Expr\Join( + Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy + ); + + return $this->add('join', array($rootAlias => $join), true); } /** @@ -702,13 +707,16 @@ class QueryBuilder public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null) { $rootAlias = substr($join, 0, strpos($join, '.')); - if (!in_array($rootAlias, $this->getRootAliases())) { + + if ( ! in_array($rootAlias, $this->getRootAliases())) { $rootAlias = $this->getRootAlias(); } - - return $this->add('join', array( - $rootAlias => new Expr\Join(Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy) - ), true); + + $join = new Expr\Join( + Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy + ); + + return $this->add('join', array($rootAlias => $join), true); } /** @@ -760,7 +768,7 @@ class QueryBuilder if ( ! (func_num_args() == 1 && $predicates instanceof Expr\Composite)) { $predicates = new Expr\Andx(func_get_args()); } - + return $this->add('where', $predicates); } @@ -784,14 +792,14 @@ class QueryBuilder { $where = $this->getDQLPart('where'); $args = func_get_args(); - + if ($where instanceof Expr\Andx) { $where->addMultiple($args); - } else { + } else { array_unshift($args, $where); $where = new Expr\Andx($args); } - + return $this->add('where', $where, true); } @@ -815,14 +823,14 @@ class QueryBuilder { $where = $this->getDqlPart('where'); $args = func_get_args(); - + if ($where instanceof Expr\Orx) { $where->addMultiple($args); - } else { + } else { array_unshift($args, $where); $where = new Expr\Orx($args); } - + return $this->add('where', $where, true); } @@ -877,7 +885,7 @@ class QueryBuilder 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); } @@ -892,14 +900,14 @@ class QueryBuilder { $having = $this->getDqlPart('having'); $args = func_get_args(); - + if ($having instanceof Expr\Andx) { $having->addMultiple($args); - } else { + } else { array_unshift($args, $having); $having = new Expr\Andx($args); } - + return $this->add('having', $having); } @@ -914,10 +922,10 @@ class QueryBuilder { $having = $this->getDqlPart('having'); $args = func_get_args(); - + if ($having instanceof Expr\Orx) { $having->addMultiple($args); - } else { + } else { array_unshift($args, $having); $having = new Expr\Orx($args); } @@ -1000,11 +1008,11 @@ class QueryBuilder $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; @@ -1017,24 +1025,24 @@ class QueryBuilder $fromClauses[] = $fromClause; } } - - $dql .= implode(', ', $fromClauses) + + $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'] : ''); diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php index 0bb3189952..afff8db638 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/MetadataCommand.php @@ -1,7 +1,5 @@ * @author Guilherme Blanco * @author Jonathan Wage @@ -47,9 +45,30 @@ class MetadataCommand extends Console\Command\Command $this ->setName('orm:clear-cache:metadata') ->setDescription('Clear all metadata cache of the various cache drivers.') - ->setDefinition(array()) - ->setHelp(<<setDefinition(array( + new InputOption( + 'flush', null, InputOption::VALUE_NONE, + 'If defined, cache entries will be flushed instead of deleted/invalidated.' + ) + )); + + $fullName = $this->getName(); + $this->setHelp(<<$fullName 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: + +$fullName + +Alternatively, if you want to flush the cache provider using this command: + +$fullName --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 ); } @@ -66,20 +85,20 @@ EOT throw new \InvalidArgumentException('No Metadata cache driver is configured on given EntityManager.'); } - if ($cacheDriver instanceof \Doctrine\Common\Cache\ApcCache) { + 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); - $cacheIds = $cacheDriver->deleteAll(); + $result = $cacheDriver->deleteAll(); + $message = ($result) ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.'; - if ($cacheIds) { - foreach ($cacheIds as $cacheId) { - $output->write(' - ' . $cacheId . PHP_EOL); - } - } else { - $output->write('No entries to be deleted.' . PHP_EOL); + if (true === $input->getOption('flush')) { + $result = $cacheDriver->flushAll(); + $message = ($result) ? 'Successfully flushed cache entries.' : $message; } + + $output->write($message . PHP_EOL); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php index 9b71292085..6ad75cdcb3 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/QueryCommand.php @@ -1,7 +1,5 @@ * @author Guilherme Blanco * @author Jonathan Wage @@ -47,9 +45,30 @@ class QueryCommand extends Console\Command\Command $this ->setName('orm:clear-cache:query') ->setDescription('Clear all query cache of the various cache drivers.') - ->setDefinition(array()) - ->setHelp(<<setDefinition(array( + new InputOption( + 'flush', null, InputOption::VALUE_NONE, + 'If defined, cache entries will be flushed instead of deleted/invalidated.' + ) + )); + + $fullName = $this->getName(); + $this->setHelp(<<$fullName 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: + +$fullName + +Alternatively, if you want to flush the cache provider using this command: + +$fullName --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 ); } @@ -66,20 +85,20 @@ EOT throw new \InvalidArgumentException('No Query cache driver is configured on given EntityManager.'); } - if ($cacheDriver instanceof \Doctrine\Common\Cache\ApcCache) { + 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); - $cacheIds = $cacheDriver->deleteAll(); + $result = $cacheDriver->deleteAll(); + $message = ($result) ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.'; - if ($cacheIds) { - foreach ($cacheIds as $cacheId) { - $output->write(' - ' . $cacheId . PHP_EOL); - } - } else { - $output->write('No entries to be deleted.' . PHP_EOL); + if (true === $input->getOption('flush')) { + $result = $cacheDriver->flushAll(); + $message = ($result) ? 'Successfully flushed cache entries.' : $message; } + + $output->write($message . PHP_EOL); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php index f1506809bf..5bb000c721 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php @@ -1,7 +1,5 @@ * @author Guilherme Blanco * @author Jonathan Wage @@ -46,28 +44,31 @@ class ResultCommand extends Console\Command\Command { $this ->setName('orm:clear-cache:result') - ->setDescription('Clear result cache of the various cache drivers.') + ->setDescription('Clear all result cache of the various cache drivers.') ->setDefinition(array( new InputOption( - 'id', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'ID(s) of the cache entry to delete (accepts * wildcards).', array() - ), - new InputOption( - 'regex', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'Delete cache entries that match the given regular expression(s).', array() - ), - new InputOption( - 'prefix', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'Delete cache entries that have the given prefix(es).', array() - ), - new InputOption( - 'suffix', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'Delete cache entries that have the given suffix(es).', array() - ), - )) - ->setHelp(<<getName(); + $this->setHelp(<<$fullName 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: + +$fullName + +Alternatively, if you want to flush the cache provider using this command: + +$fullName --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 ); } @@ -84,85 +85,20 @@ EOT throw new \InvalidArgumentException('No Result cache driver is configured on given EntityManager.'); } - if ($cacheDriver instanceof \Doctrine\Common\Cache\ApcCache) { + 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."); } - $outputed = false; - - // Removing based on --id - if (($ids = $input->getOption('id')) !== null && $ids) { - foreach ($ids as $id) { - $output->write($outputed ? PHP_EOL : ''); - $output->write(sprintf('Clearing Result cache entries that match the id "%s"', $id) . PHP_EOL); - - $deleted = $cacheDriver->delete($id); - - if (is_array($deleted)) { - $this->_printDeleted($output, $deleted); - } else if (is_bool($deleted) && $deleted) { - $this->_printDeleted($output, array($id)); - } - - $outputed = true; - } - } - - // Removing based on --regex - if (($regexps = $input->getOption('regex')) !== null && $regexps) { - foreach($regexps as $regex) { - $output->write($outputed ? PHP_EOL : ''); - $output->write(sprintf('Clearing Result cache entries that match the regular expression "%s"', $regex) . PHP_EOL); + $output->write('Clearing ALL Result cache entries' . PHP_EOL); - $this->_printDeleted($output, $cacheDriver->deleteByRegex('/' . $regex. '/')); + $result = $cacheDriver->deleteAll(); + $message = ($result) ? 'Successfully deleted cache entries.' : 'No cache entries were deleted.'; - $outputed = true; - } + if (true === $input->getOption('flush')) { + $result = $cacheDriver->flushAll(); + $message = ($result) ? 'Successfully flushed cache entries.' : $message; } - // Removing based on --prefix - if (($prefixes = $input->getOption('prefix')) !== null & $prefixes) { - foreach ($prefixes as $prefix) { - $output->write($outputed ? PHP_EOL : ''); - $output->write(sprintf('Clearing Result cache entries that have the prefix "%s"', $prefix) . PHP_EOL); - - $this->_printDeleted($output, $cacheDriver->deleteByPrefix($prefix)); - - $outputed = true; - } - } - - // Removing based on --suffix - if (($suffixes = $input->getOption('suffix')) !== null && $suffixes) { - foreach ($suffixes as $suffix) { - $output->write($outputed ? PHP_EOL : ''); - $output->write(sprintf('Clearing Result cache entries that have the suffix "%s"', $suffix) . PHP_EOL); - - $this->_printDeleted($output, $cacheDriver->deleteBySuffix($suffix)); - - $outputed = true; - } - } - - // Removing ALL entries - if ( ! $ids && ! $regexps && ! $prefixes && ! $suffixes) { - $output->write($outputed ? PHP_EOL : ''); - $output->write('Clearing ALL Result cache entries' . PHP_EOL); - - $this->_printDeleted($output, $cacheDriver->deleteAll()); - - $outputed = true; - } - } - - private function _printDeleted(Console\Output\OutputInterface $output, array $items) - { - if ($items) { - foreach ($items as $item) { - $output->write(' - ' . $item . PHP_EOL); - } - } else { - $output->write('No entries to be deleted.' . PHP_EOL); - } + $output->write($message . PHP_EOL); } -} +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php index 1a1328aac0..c78920bcc3 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php @@ -80,7 +80,7 @@ class ConvertDoctrine1SchemaCommand extends Console\Command\Command if ($this->metadataExporter == null) { $this->metadataExporter = new ClassMetadataExporter(); } - + return $this->metadataExporter; } @@ -91,7 +91,7 @@ class ConvertDoctrine1SchemaCommand extends Console\Command\Command { $this->metadataExporter = $metadataExporter; } - + /** * @see Console\Command\Command */ diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php index 9a79031279..03af43ac44 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php @@ -137,7 +137,7 @@ EOT if ( ! file_exists($destPath)) { throw new \InvalidArgumentException( - sprintf("Mapping destination directory '%s' does not exist.", $destPath) + sprintf("Mapping destination directory '%s' does not exist.", $input->getArgument('dest-path')) ); } else if ( ! is_writable($destPath)) { throw new \InvalidArgumentException( diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php index 198db0d6cc..f00e6d2c4a 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateEntitiesCommand.php @@ -112,18 +112,18 @@ EOT 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.", $destPath) + sprintf("Entities destination directory '%s' does not exist.", $input->getArgument('dest-path')) ); } else if ( ! is_writable($destPath)) { throw new \InvalidArgumentException( diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php index 9876289563..7028d99e27 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateProxiesCommand.php @@ -70,7 +70,7 @@ EOT protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output) { $em = $this->getHelper('em')->getEntityManager(); - + $metadatas = $em->getMetadataFactory()->getAllMetadata(); $metadatas = MetadataFilter::filter($metadatas, $input->getOption('filter')); @@ -87,7 +87,7 @@ EOT if ( ! file_exists($destPath)) { throw new \InvalidArgumentException( - sprintf("Proxies destination directory '%s' does not exist.", $destPath) + sprintf("Proxies destination directory '%s' does not exist.", $em->getConfiguration()->getProxyDir()) ); } else if ( ! is_writable($destPath)) { throw new \InvalidArgumentException( diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php index 30d36eb448..bb6fc9d8b2 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/GenerateRepositoriesCommand.php @@ -70,7 +70,7 @@ EOT protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output) { $em = $this->getHelper('em')->getEntityManager(); - + $metadatas = $em->getMetadataFactory()->getAllMetadata(); $metadatas = MetadataFilter::filter($metadatas, $input->getOption('filter')); @@ -79,7 +79,7 @@ EOT if ( ! file_exists($destPath)) { throw new \InvalidArgumentException( - sprintf("Entities destination directory '%s' does not exist.", $destPath) + sprintf("Entities destination directory '%s' does not exist.", $input->getArgument('dest-path')) ); } else if ( ! is_writable($destPath)) { throw new \InvalidArgumentException( diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php index a39995e0fe..2b0fc0dd02 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php @@ -127,7 +127,7 @@ EOT $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/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php index 994b89578b..fc8f55638c 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Console/Command/ValidateSchemaCommand.php @@ -46,7 +46,7 @@ class ValidateSchemaCommand extends Console\Command\Command { $this ->setName('orm:validate-schema') - ->setDescription('Validate that the mapping files.') + ->setDescription('Validate the mapping files.') ->setHelp(<< 1) { $metadata->table['schema'] = $e[0]; $metadata->table['name'] = $e[1]; @@ -248,7 +249,6 @@ class ConvertDoctrine1Schema 'name' => $relation['local'], 'referencedColumnName' => $relation['foreign'], 'onDelete' => isset($relation['onDelete']) ? $relation['onDelete'] : null, - 'onUpdate' => isset($relation['onUpdate']) ? $relation['onUpdate'] : null, ) ); } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/DebugUnitOfWorkListener.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/DebugUnitOfWorkListener.php new file mode 100644 index 0000000000..0548b96447 --- /dev/null +++ b/main/inc/lib/symfony/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 $idHash => $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; + } +} \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/DisconnectedClassMetadataFactory.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/DisconnectedClassMetadataFactory.php index 7a7715231e..2603c22f97 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/DisconnectedClassMetadataFactory.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/DisconnectedClassMetadataFactory.php @@ -24,7 +24,7 @@ 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 + * 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. * @@ -38,36 +38,8 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo; */ class DisconnectedClassMetadataFactory extends ClassMetadataFactory { - /** - * @override - */ - protected function newClassMetadataInstance($className) + public function getReflectionService() { - $metadata = new ClassMetadataInfo($className); - if (strpos($className, "\\") !== false) { - $metadata->namespace = strrev(substr( strrev($className), strpos(strrev($className), "\\")+1 )); - } else { - $metadata->namespace = ""; - } - return $metadata; + return new \Doctrine\Common\Persistence\Mapping\StaticReflectionService; } - - /** - * Validate runtime metadata is correctly defined. - * - * @param ClassMetadata $class - * @param ClassMetadata $parent - */ - protected function validateRuntimeMetadata($class, $parent) - { - // validate nothing - } - - /** - * @override - */ - protected function getParentClasses($name) - { - return array(); - } -} \ No newline at end of file +} diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/EntityGenerator.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/EntityGenerator.php index 495be60e93..5bf1bdf6c4 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/EntityGenerator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/EntityGenerator.php @@ -115,10 +115,12 @@ public function () * * * @param $ + * @return */ -public function ($) +public function ($) { $this-> = $; +return $this; }'; private static $_addMethodTemplate = @@ -126,10 +128,12 @@ public function ($) * * * @param $ + * @return */ public function ($) { $this->[] = $; +return $this; }'; private static $_lifecycleCallbackMethodTemplate = @@ -150,7 +154,7 @@ public function () public function __construct() { - if (version_compare(\Doctrine\Common\Version::VERSION, '3.0.0-DEV', '>=')) { + if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) { $this->_annotationsPrefix = 'ORM\\'; } } @@ -196,7 +200,7 @@ public function () if ($this->_backupExisting && file_exists($path)) { $backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~"; if (!copy($path, $backupPath)) { - throw new \RuntimeException("Attempt to backup overwritten entitiy file but copy operation failed."); + throw new \RuntimeException("Attempt to backup overwritten entity file but copy operation failed."); } } @@ -304,9 +308,6 @@ public function () */ public function setAnnotationPrefix($prefix) { - if (version_compare(\Doctrine\Common\Version::VERSION, '3.0.0-DEV', '>=')) { - return; - } $this->_annotationsPrefix = $prefix; } @@ -401,14 +402,17 @@ public function () } $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", $collections), self::$_constructorMethodTemplate)); + return $this->_prefixCodeWithSpaces(str_replace("", implode("\n".$this->_spaces, $collections), self::$_constructorMethodTemplate)); } + return ''; } @@ -572,13 +576,41 @@ public function () private function _generateTableAnnotation($metadata) { $table = array(); - if ($metadata->table['name']) { + + 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) { @@ -629,7 +661,8 @@ public function () foreach ($metadata->associationMappings as $associationMapping) { if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) { - if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'])) { + $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'])) { @@ -648,6 +681,25 @@ public function () 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) { @@ -702,7 +754,7 @@ public function () return implode("\n", $lines); } - private function _generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null) + private function _generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null) { if ($type == "add") { $addMethod = explode("\\", $typeHint); @@ -731,7 +783,9 @@ public function () '' => $variableType, '' => Inflector::camelize($fieldName), '' => $methodName, - '' => $fieldName + '' => $fieldName, + '' => ($defaultValue !== null ) ? (' = '.$defaultValue) : '', + '' => $this->_getClassName($metadata) ); $method = str_replace( @@ -788,10 +842,6 @@ public function () $joinColumnAnnot[] = 'onDelete="' . ($joinColumn['onDelete'] . '"'); } - if (isset($joinColumn['onUpdate'])) { - $joinColumnAnnot[] = 'onUpdate=' . ($joinColumn['onUpdate'] ? 'true' : 'false'); - } - if (isset($joinColumn['columnDefinition'])) { $joinColumnAnnot[] = 'columnDefinition="' . $joinColumn['columnDefinition'] . '"'; } @@ -803,10 +853,23 @@ public function () { $lines = array(); $lines[] = $this->_spaces . '/**'; - $lines[] = $this->_spaces . ' * @var ' . $associationMapping['targetEntity']; + + 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']) { diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php index 75302717e2..41ec6fdf6e 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php @@ -56,7 +56,7 @@ abstract class AbstractExporter * Converts a single ClassMetadata instance to the exported format * and returns it * - * @param ClassMetadataInfo $metadata + * @param ClassMetadataInfo $metadata * @return mixed $exported */ abstract public function exportClassMetadata(ClassMetadataInfo $metadata); @@ -64,7 +64,7 @@ abstract class AbstractExporter /** * Set the array of ClassMetadataInfo instances to export * - * @param array $metadata + * @param array $metadata * @return void */ public function setMetadata(array $metadata) @@ -90,7 +90,7 @@ abstract class AbstractExporter * $exporter->setOutputDir(__DIR__ . '/yaml'); * $exporter->export(); * - * @param string $dir + * @param string $dir * @return void */ public function setOutputDir($dir) @@ -111,23 +111,25 @@ abstract class AbstractExporter } foreach ($this->_metadata as $metadata) { - $output = $this->exportClassMetadata($metadata); - $path = $this->_generateOutputPath($metadata); - $dir = dirname($path); - if ( ! is_dir($dir)) { - mkdir($dir, 0777, true); + //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); } - 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 + * @param ClassMetadataInfo $metadata * @return string $path */ protected function _generateOutputPath(ClassMetadataInfo $metadata) @@ -162,11 +164,11 @@ abstract class AbstractExporter 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; @@ -180,11 +182,11 @@ abstract class AbstractExporter 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; @@ -198,15 +200,15 @@ abstract class AbstractExporter 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/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php index 254905eec9..5053290d8b 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php @@ -44,7 +44,7 @@ class AnnotationExporter extends AbstractExporter * Converts a single ClassMetadata instance to the exported format * and returns it * - * @param ClassMetadataInfo $metadata + * @param ClassMetadataInfo $metadata * @return string $exported */ public function exportClassMetadata(ClassMetadataInfo $metadata) diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php index 900fb5bda8..fc561c9082 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php @@ -41,7 +41,7 @@ class PhpExporter extends AbstractExporter * Converts a single ClassMetadata instance to the exported format * and returns it * - * @param ClassMetadataInfo $metadata + * @param ClassMetadataInfo $metadata * @return mixed $exported */ public function exportClassMetadata(ClassMetadataInfo $metadata) @@ -108,7 +108,7 @@ class PhpExporter extends AbstractExporter 'targetEntity' => $associationMapping['targetEntity'], 'cascade' => $cascade, ); - + if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) { $method = 'mapOneToOne'; $oneToOneMappingArray = array( @@ -117,10 +117,10 @@ class PhpExporter extends AbstractExporter 'joinColumns' => $associationMapping['joinColumns'], 'orphanRemoval' => $associationMapping['orphanRemoval'], ); - + $associationMappingArray = array_merge($associationMappingArray, $oneToOneMappingArray); } else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) { - $method = 'mapOneToMany'; + $method = 'mapOneToMany'; $potentialAssociationMappingIndexes = array( 'mappedBy', 'orphanRemoval', @@ -133,7 +133,7 @@ class PhpExporter extends AbstractExporter } $associationMappingArray = array_merge($associationMappingArray, $oneToManyMappingArray); } else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_MANY) { - $method = 'mapManyToMany'; + $method = 'mapManyToMany'; $potentialAssociationMappingIndexes = array( 'mappedBy', 'joinTable', @@ -146,7 +146,7 @@ class PhpExporter extends AbstractExporter } $associationMappingArray = array_merge($associationMappingArray, $manyToManyMappingArray); } - + $lines[] = '$metadata->' . $method . '(' . $this->_varExport($associationMappingArray) . ');'; } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php index fc27ea911b..bda29810fd 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php @@ -41,7 +41,7 @@ class XmlExporter extends AbstractExporter * Converts a single ClassMetadata instance to the exported format * and returns it * - * @param ClassMetadataInfo $metadata + * @param ClassMetadataInfo $metadata * @return mixed $exported */ public function exportClassMetadata(ClassMetadataInfo $metadata) @@ -99,7 +99,7 @@ class XmlExporter extends AbstractExporter if (isset($metadata->table['indexes'])) { $indexesXml = $root->addChild('indexes'); - + foreach ($metadata->table['indexes'] as $name => $index) { $indexXml = $indexesXml->addChild('index'); $indexXml->addAttribute('name', $name); @@ -109,7 +109,7 @@ class XmlExporter extends AbstractExporter 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']); @@ -118,7 +118,7 @@ class XmlExporter extends AbstractExporter } $fields = $metadata->fieldMappings; - + $id = array(); foreach ($fields as $name => $field) { if (isset($field['id']) && $field['id']) { @@ -139,6 +139,9 @@ class XmlExporter extends AbstractExporter 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); @@ -215,9 +218,6 @@ class XmlExporter extends AbstractExporter if (isset($joinColumn['onDelete'])) { $joinColumnXml->addAttribute('on-delete', $joinColumn['onDelete']); } - if (isset($joinColumn['onUpdate'])) { - $joinColumnXml->addAttribute('on-update', $joinColumn['onUpdate']); - } } $inverseJoinColumnsXml = $joinTableXml->addChild('inverse-join-columns'); foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) { @@ -227,9 +227,6 @@ class XmlExporter extends AbstractExporter if (isset($inverseJoinColumn['onDelete'])) { $inverseJoinColumnXml->addAttribute('on-delete', $inverseJoinColumn['onDelete']); } - if (isset($inverseJoinColumn['onUpdate'])) { - $inverseJoinColumnXml->addAttribute('on-update', $inverseJoinColumn['onUpdate']); - } if (isset($inverseJoinColumn['columnDefinition'])) { $inverseJoinColumnXml->addAttribute('column-definition', $inverseJoinColumn['columnDefinition']); } @@ -250,9 +247,6 @@ class XmlExporter extends AbstractExporter if (isset($joinColumn['onDelete'])) { $joinColumnXml->addAttribute('on-delete', $joinColumn['onDelete']); } - if (isset($joinColumn['onUpdate'])) { - $joinColumnXml->addAttribute('on-update', $joinColumn['onUpdate']); - } if (isset($joinColumn['columnDefinition'])) { $joinColumnXml->addAttribute('column-definition', $joinColumn['columnDefinition']); } @@ -285,6 +279,9 @@ class XmlExporter extends AbstractExporter if ($associationMapping['isCascadeDetach']) { $cascade[] = 'cascade-detach'; } + if (count($cascade) === 5) { + $cascade = array('cascade-all'); + } if ($cascade) { $cascadeXml = $associationMappingXml->addChild('cascade'); foreach ($cascade as $type) { diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php index 669e76ce47..2d16792b1d 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php @@ -49,11 +49,13 @@ class YamlExporter extends AbstractExporter 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'])) { @@ -81,6 +83,10 @@ class YamlExporter extends AbstractExporter $array['indexes'] = $metadata->table['indexes']; } + if ($metadata->customRepositoryClassName) { + $array['repositoryClass'] = $metadata->customRepositoryClassName; + } + if (isset($metadata->table['uniqueConstraints'])) { $array['uniqueConstraints'] = $metadata->table['uniqueConstraints']; } @@ -141,6 +147,9 @@ class YamlExporter extends AbstractExporter if ($associationMapping['isCascadeDetach']) { $cascade[] = 'detach'; } + if (count($cascade) === 5) { + $cascade = array('all'); + } $associationMappingArray = array( 'targetEntity' => $associationMapping['targetEntity'], 'cascade' => $cascade, @@ -154,9 +163,6 @@ class YamlExporter extends AbstractExporter if (isset($joinColumn['onDelete'])) { $newJoinColumns[$joinColumn['name']]['onDelete'] = $joinColumn['onDelete']; } - if (isset($joinColumn['onUpdate'])) { - $newJoinColumns[$joinColumn['name']]['onUpdate'] = $joinColumn['onUpdate']; - } } $oneToOneMappingArray = array( 'mappedBy' => $associationMapping['mappedBy'], diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/CountWalker.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/CountWalker.php new file mode 100644 index 0000000000..10df1c3e14 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/CountWalker.php @@ -0,0 +1,80 @@ + + * @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) + { + $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); + + $pathExpression = new PathExpression( + PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName, + $parent['metadata']->getSingleIdentifierFieldName() + ); + $pathExpression->type = PathExpression::TYPE_STATE_FIELD; + + $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/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php new file mode 100644 index 0000000000..97ed5ba814 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php @@ -0,0 +1,115 @@ + + * @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(); + $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/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/Paginator.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/Paginator.php new file mode 100644 index 0000000000..760d7de131 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/Paginator.php @@ -0,0 +1,180 @@ +. + */ + +namespace Doctrine\ORM\Tools\Pagination; + +use Doctrine\ORM\QueryBuilder; +use Doctrine\ORM\Query; +use Doctrine\ORM\NoResultException; +use Doctrine\ORM\Tools\Pagination\WhereInWalker; +use Doctrine\ORM\Tools\Pagination\CountWalker; +use Countable; +use IteratorAggregate; +use ArrayIterator; + +/** + * 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 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; + } + + /** + * {@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); + } + + $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); + $subQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker')) + ->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) { + $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($query->getParameters()); + foreach ($query->getHints() as $name => $value) { + $cloneQuery->setHint($name, $value); + } + + return $cloneQuery; + } +} + diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/WhereInWalker.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/WhereInWalker.php new file mode 100644 index 0000000000..5400ef2472 --- /dev/null +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Pagination/WhereInWalker.php @@ -0,0 +1,142 @@ + + * @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); + + $pathExpression = new PathExpression( + PathExpression::TYPE_STATE_FIELD, $parentName, $parent['metadata']->getSingleIdentifierFieldName() + ); + $pathExpression->type = PathExpression::TYPE_STATE_FIELD; + + $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) { + $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/main/inc/lib/symfony/Doctrine/ORM/Tools/ResolveTargetEntityListener.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/ResolveTargetEntityListener.php new file mode 100644 index 0000000000..621214fddf --- /dev/null +++ b/main/inc/lib/symfony/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 $assocName => $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/main/inc/lib/symfony/Doctrine/ORM/Tools/SchemaTool.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/SchemaTool.php index a0f7f0174f..efe7f7b7cc 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/SchemaTool.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/SchemaTool.php @@ -21,6 +21,8 @@ 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, @@ -67,7 +69,9 @@ class SchemaTool /** * Creates the database schema for the given array of ClassMetadata instances. * + * @throws ToolsException * @param array $classes + * @return void */ public function createSchema(array $classes) { @@ -75,7 +79,11 @@ class SchemaTool $conn = $this->_em->getConnection(); foreach ($createSchemaSql as $sql) { - $conn->executeQuery($sql); + try { + $conn->executeQuery($sql); + } catch(\Exception $e) { + throw ToolsException::schemaToolFailure($sql, $e); + } } } @@ -94,7 +102,7 @@ class SchemaTool /** * 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 @@ -121,7 +129,7 @@ class SchemaTool $sm = $this->_em->getConnection()->getSchemaManager(); $metadataSchemaConfig = $sm->createSchemaConfig(); $metadataSchemaConfig->setExplicitForeignKeyIndexes(false); - $schema = new \Doctrine\DBAL\Schema\Schema(array(), array(), $metadataSchemaConfig); + $schema = new Schema(array(), array(), $metadataSchemaConfig); $evm = $this->_em->getEventManager(); @@ -139,7 +147,7 @@ class SchemaTool $this->_gatherRelationsSql($class, $table, $schema); // Add the discriminator column - $discrColumnDef = $this->_getDiscriminatorColumnDefinition($class, $table); + $this->addDiscriminatorColumnDefinition($class, $table); // Aggregate all the information from all classes in the hierarchy foreach ($class->parentClasses as $parentClassName) { @@ -171,7 +179,7 @@ class SchemaTool // Add the discriminator column only to the root table if ($class->name == $class->rootEntityName) { - $discrColumnDef = $this->_getDiscriminatorColumnDefinition($class, $table); + $this->addDiscriminatorColumnDefinition($class, $table); } else { // Add an ID FK column to child tables /* @var \Doctrine\ORM\Mapping\ClassMetadata $class */ @@ -246,6 +254,10 @@ class SchemaTool } } + if ( ! $this->_platform->supportsSchemas() && ! $this->_platform->canEmulateSchemas() ) { + $schema->visit(new RemoveNamespacedAssets()); + } + if ($evm->hasListeners(ToolEvents::postGenerateSchema)) { $evm->dispatchEvent(ToolEvents::postGenerateSchema, new GenerateSchemaEventArgs($this->_em, $schema)); } @@ -261,7 +273,7 @@ class SchemaTool * @return array The portable column definition of the discriminator column as required by * the DBAL. */ - private function _getDiscriminatorColumnDefinition($class, $table) + private function addDiscriminatorColumnDefinition($class, $table) { $discrColumn = $class->discriminatorColumn; @@ -354,6 +366,10 @@ class SchemaTool $options['columnDefinition'] = $mapping['columnDefinition']; } + if (isset($mapping['options'])) { + $options['customSchemaOptions'] = $mapping['options']; + } + if ($class->isIdGeneratorIdentity() && $class->getIdentifierFieldNames() == array($mapping['fieldName'])) { $options['autoincrement'] = true; } @@ -523,10 +539,6 @@ class SchemaTool $uniqueConstraints[] = array('columns' => array($columnName)); } - if (isset($joinColumn['onUpdate'])) { - $fkOptions['onUpdate'] = $joinColumn['onUpdate']; - } - if (isset($joinColumn['onDelete'])) { $fkOptions['onDelete'] = $joinColumn['onDelete']; } @@ -555,7 +567,7 @@ class SchemaTool try { $conn->executeQuery($sql); } catch(\Exception $e) { - + } } } @@ -593,7 +605,7 @@ class SchemaTool /** * Get SQL to drop the tables defined by the passed classes. - * + * * @param array $classes * @return array */ @@ -619,7 +631,7 @@ class SchemaTool } } } - + if ($this->_platform->supportsSequences()) { foreach ($schema->getSequences() AS $sequence) { $visitor->acceptSequence($sequence); @@ -663,7 +675,7 @@ class SchemaTool /** * 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, + * If $saveMode is set to true the command is executed in the Database, * else SQL is returned. * * @param array $classes The classes to consider. diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/SchemaValidator.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/SchemaValidator.php index c16127223e..453679df15 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/SchemaValidator.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/SchemaValidator.php @@ -21,6 +21,7 @@ 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 @@ -28,7 +29,6 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo; * @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 @@ -50,7 +50,7 @@ class SchemaValidator } /** - * Checks the internal consistency of mapping files. + * 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: @@ -69,139 +69,185 @@ class SchemaValidator $classes = $cmf->getAllMetadata(); foreach ($classes AS $class) { - $ce = array(); - /* @var $class ClassMetadata */ - foreach ($class->associationMappings AS $fieldName => $assoc) { - if (!$cmf->hasMetadataFor($assoc['targetEntity'])) { - $ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.'; + 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['mappedBy'] && $assoc['inversedBy']) { - $ce[] = "The association " . $class . "#" . $fieldName . " cannot be defined as both inverse and owning."; + 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."; } - $targetMetadata = $cmf->getMetadataFor($assoc['targetEntity']); + // Verify inverse side/owning side match each other + $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."; + } + } - /* @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 ($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; + } } - 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' 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."; + + $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 ($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 (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 (!$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."; + + 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."; } - } - if ($assoc['isOwningSide']) { - if ($assoc['type'] == ClassMetadataInfo::MANY_TO_MANY) { - foreach ($assoc['joinTable']['joinColumns'] AS $joinColumn) { - if (!isset($class->fieldNames[$joinColumn['referencedColumnName']])) { - $ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " . - "have a corresponding field with this column name on the class '" . $class->name . "'."; - break; - } - - $fieldName = $class->fieldNames[$joinColumn['referencedColumnName']]; - if (!in_array($fieldName, $class->identifier)) { - $ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " . - "has to be a primary key column."; - } - } - foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) { - $targetClass = $cmf->getMetadataFor($assoc['targetEntity']); - if (!isset($targetClass->fieldNames[$inverseJoinColumn['referencedColumnName']])) { - $ce[] = "The inverse referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' does not " . - "have a corresponding field with this column name on the class '" . $targetClass->name . "'."; - break; - } - - $fieldName = $targetClass->fieldNames[$inverseJoinColumn['referencedColumnName']]; - if (!in_array($fieldName, $targetClass->identifier)) { - $ce[] = "The referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' " . - "has to be a primary key column."; - } - } - } else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) { - foreach ($assoc['joinColumns'] AS $joinColumn) { - $targetClass = $cmf->getMetadataFor($assoc['targetEntity']); - if (!isset($targetClass->fieldNames[$joinColumn['referencedColumnName']])) { - $ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " . - "have a corresponding field with this column name on the class '" . $targetClass->name . "'."; - break; - } - - $fieldName = $targetClass->fieldNames[$joinColumn['referencedColumnName']]; - if (!in_array($fieldName, $targetClass->identifier)) { - $ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " . - "has to be a primary key column."; - } + } 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 (isset($assoc['orderBy']) && $assoc['orderBy'] !== null) { - $targetClass = $cmf->getMetadataFor($assoc['targetEntity']); - foreach ($assoc['orderBy'] AS $orderField => $orientation) { - if (!$targetClass->hasField($orderField)) { - $ce[] = "The association " . $class->name."#".$fieldName." is ordered by a foreign field " . - $orderField . " that is not a field on the target entity " . $targetClass->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."; } } } - foreach ($class->reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $publicAttr) { - if ($publicAttr->isStatic()) { - continue; + 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; + } } - $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."; - } + 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."; + } - if ($ce) { - $errors[$class->name] = $ce; + 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 $errors; + return $ce; } /** diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/Setup.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/Setup.php index 6f4ea1b779..c2550e2c78 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/Setup.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/Setup.php @@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping\Driver\YamlDriver; /** * Convenience class for setting up Doctrine from different installations and configurations. - * + * * @author Benjamin Eberlei */ class Setup @@ -36,8 +36,8 @@ 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 + * + * @param string $gitCheckoutRootPath * @return void */ static public function registerAutoloadGit($gitCheckoutRootPath) @@ -45,24 +45,24 @@ class Setup 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() @@ -70,12 +70,12 @@ class Setup 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"); @@ -84,29 +84,29 @@ class Setup } } } - + /** * Use this method to register all autoloads for a downloaded Doctrine library. * Pick the directory the library was uncompressed into. - * - * @param string $directory + * + * @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 @@ -119,10 +119,10 @@ class Setup $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver($paths)); return $config; } - + /** - * Create a configuration with an annotation metadata driver. - * + * Create a configuration with a xml metadata driver. + * * @param array $paths * @param boolean $isDevMode * @param string $proxyDir @@ -135,10 +135,10 @@ class Setup $config->setMetadataDriverImpl(new XmlDriver($paths)); return $config; } - + /** - * Create a configuration with an annotation metadata driver. - * + * Create a configuration with a yaml metadata driver. + * * @param array $paths * @param boolean $isDevMode * @param string $proxyDir @@ -151,14 +151,14 @@ class Setup $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 + * @return Configuration */ static public function createConfiguration($isDevMode = false, $proxyDir = null, Cache $cache = null) { @@ -180,7 +180,7 @@ class Setup $cache = new ArrayCache; } $cache->setNamespace("dc2_" . md5($proxyDir) . "_"); // to avoid collisions - + $config = new Configuration(); $config->setMetadataCacheImpl($cache); $config->setQueryCacheImpl($cache); @@ -188,7 +188,7 @@ class Setup $config->setProxyDir( $proxyDir ); $config->setProxyNamespace('DoctrineProxies'); $config->setAutoGenerateProxyClasses($isDevMode); - + return $config; } } \ No newline at end of file diff --git a/main/inc/lib/symfony/Doctrine/ORM/Tools/ToolsException.php b/main/inc/lib/symfony/Doctrine/ORM/Tools/ToolsException.php index f7ed87105b..4551d87da5 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Tools/ToolsException.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Tools/ToolsException.php @@ -1,11 +1,38 @@ . + */ 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/main/inc/lib/symfony/Doctrine/ORM/UnitOfWork.php b/main/inc/lib/symfony/Doctrine/ORM/UnitOfWork.php index 6ec4f21c62..965c7d52e6 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/UnitOfWork.php +++ b/main/inc/lib/symfony/Doctrine/ORM/UnitOfWork.php @@ -24,6 +24,7 @@ use Exception, InvalidArgumentException, UnexpectedValueException, 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; @@ -254,11 +255,22 @@ class UnitOfWork implements PropertyChangedListener * 4) All collection updates * 5) All entity deletions * + * @param object $entity + * @return void */ - public function commit() + 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. - $this->computeChangeSets(); + if ($entity === null) { + $this->computeChangeSets(); + } else { + $this->computeSingleEntityChangeSet($entity); + } if ( ! ($this->entityInsertions || $this->entityDeletions || @@ -284,8 +296,8 @@ class UnitOfWork implements PropertyChangedListener $commitOrder = $this->getCommitOrder(); $conn = $this->em->getConnection(); - $conn->beginTransaction(); + try { if ($this->entityInsertions) { foreach ($commitOrder as $class) { @@ -306,13 +318,11 @@ class UnitOfWork implements PropertyChangedListener // Collection deletions (deletions of complete collections) foreach ($this->collectionDeletions as $collectionToDelete) { - $this->getCollectionPersister($collectionToDelete->getMapping()) - ->delete($collectionToDelete); + $this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete); } // Collection updates (deleteRows, updateRows, insertRows) foreach ($this->collectionUpdates as $collectionToUpdate) { - $this->getCollectionPersister($collectionToUpdate->getMapping()) - ->update($collectionToUpdate); + $this->getCollectionPersister($collectionToUpdate->getMapping())->update($collectionToUpdate); } // Entity deletions come last and need to be in reverse commit order @@ -326,6 +336,7 @@ class UnitOfWork implements PropertyChangedListener } catch (Exception $e) { $this->em->close(); $conn->rollback(); + throw $e; } @@ -334,6 +345,11 @@ class UnitOfWork implements PropertyChangedListener $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 = @@ -347,6 +363,63 @@ class UnitOfWork implements PropertyChangedListener $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 + * @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. */ @@ -354,6 +427,7 @@ class UnitOfWork implements PropertyChangedListener { foreach ($this->extraUpdates as $oid => $update) { list ($entity, $changeset) = $update; + $this->entityChangeSets[$oid] = $changeset; $this->getEntityPersister(get_class($entity))->update($entity); } @@ -367,9 +441,11 @@ class UnitOfWork implements PropertyChangedListener public function getEntityChangeSet($entity) { $oid = spl_object_hash($entity); + if (isset($this->entityChangeSets[$oid])) { return $this->entityChangeSets[$oid]; } + return array(); } @@ -398,29 +474,34 @@ class UnitOfWork implements PropertyChangedListener * 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) { - if ( ! $class->isInheritanceTypeNone()) { - $class = $this->em->getClassMetadata(get_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 (isset($class->associationMappings[$name]) - && ($class->associationMappings[$name]['type'] & ClassMetadata::TO_MANY) - && $value !== null - && ! ($value instanceof PersistentCollection)) { + 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); @@ -429,17 +510,20 @@ class UnitOfWork implements PropertyChangedListener $assoc = $class->associationMappings[$name]; // Inject PersistentCollection - $coll = new PersistentCollection( - $this->em, - $this->em->getClassMetadata($assoc['targetEntity']), - $value + $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; + } - $coll->setOwner($entity, $assoc); - $coll->setDirty( ! $coll->isEmpty()); - $class->reflFields[$name]->setValue($entity, $coll); - $actualData[$name] = $coll; - } else if ( (! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) && ($name !== $class->versionField) ) { + if (( ! $class->isIdentifier($name) || ! $class->isIdGeneratorIdentity()) && ($name !== $class->versionField)) { $actualData[$name] = $value; } } @@ -449,68 +533,119 @@ class UnitOfWork implements PropertyChangedListener // These result in an INSERT. $this->originalEntityData[$oid] = $actualData; $changeSet = array(); + foreach ($actualData as $propName => $actualValue) { - if (isset($class->associationMappings[$propName])) { - $assoc = $class->associationMappings[$propName]; - if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) { - $changeSet[$propName] = array(null, $actualValue); - } - } else { + 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]; + $originalData = $this->originalEntityData[$oid]; $isChangeTrackingNotify = $class->isChangeTrackingNotify(); - $changeSet = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid])) ? $this->entityChangeSets[$oid] : array(); + $changeSet = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid])) + ? $this->entityChangeSets[$oid] + : array(); foreach ($actualData as $propName => $actualValue) { - if (isset($originalData[$propName])) { - $orgValue = $originalData[$propName]; - } else if (array_key_exists($propName, $originalData)) { - $orgValue = null; - } else { - // skip field, its a partially omitted one! + // skip field, its a partially omitted one! + if ( ! (isset($originalData[$propName]) || array_key_exists($propName, $originalData))) { continue; } - if (isset($class->associationMappings[$propName])) { - $assoc = $class->associationMappings[$propName]; - if ($assoc['type'] & ClassMetadata::TO_ONE && $orgValue !== $actualValue) { - if ($assoc['isOwningSide']) { - $changeSet[$propName] = array($orgValue, $actualValue); - } - if ($orgValue !== null && $assoc['orphanRemoval']) { - $this->scheduleOrphanRemoval($orgValue); - } - } else if ($orgValue instanceof PersistentCollection && $orgValue !== $actualValue) { - // A PersistentCollection was de-referenced, so delete it. - if ( ! in_array($orgValue, $this->collectionDeletions, true)) { - $this->collectionDeletions[] = $orgValue; - $changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored. + $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); } - } else if ($isChangeTrackingNotify) { + } + + 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; - } else if ($orgValue !== $actualValue) { - $changeSet[$propName] = array($orgValue, $actualValue); + } + + 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->entityChangeSets[$oid] = $changeSet; $this->originalEntityData[$oid] = $actualData; - $this->entityUpdates[$oid] = $entity; + $this->entityUpdates[$oid] = $entity; } } // Look for changes in associations of the entity foreach ($class->associationMappings as $field => $assoc) { - $val = $class->reflFields[$field]->getValue($entity); - if ($val !== null) { + 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; + } } } } @@ -523,10 +658,7 @@ class UnitOfWork implements PropertyChangedListener public function computeChangeSets() { // Compute changes for INSERTed entities first. This must always happen. - foreach ($this->entityInsertions as $entity) { - $class = $this->em->getClassMetadata(get_class($entity)); - $this->computeChangeSet($class, $entity); - } + $this->computeScheduleInsertsChangeSets(); // Compute changes for other MANAGED entities. Change tracking policies take effect here. foreach ($this->identityMap as $className => $entities) { @@ -539,18 +671,29 @@ class UnitOfWork implements PropertyChangedListener // If change tracking is explicit or happens through notification, then only compute // changes on entities of that type that are explicitly marked for synchronization. - $entitiesToProcess = ! $class->isChangeTrackingDeferredImplicit() ? - (isset($this->scheduledForDirtyCheck[$className]) ? - $this->scheduledForDirtyCheck[$className] : array()) - : $entities; + 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); } @@ -566,74 +709,96 @@ class UnitOfWork implements PropertyChangedListener */ 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[] = $value; + $this->collectionUpdates[$coid] = $value; } - $this->visitedCollections[] = $value; - } - // Look through the entities, and in any of their associations, for transient (new) - // enities, recursively. ("Persistence by reachability") - if ($assoc['type'] & ClassMetadata::TO_ONE) { - if ($value instanceof Proxy && ! $value->__isInitialized__) { - return; // Ignore uninitialized proxy objects - } - $value = array($value); - } else if ($value instanceof PersistentCollection) { - // Unwrap. Uninitialized collections will simply be empty. - $value = $value->unwrap(); + $this->visitedCollections[$coid] = $value; } - $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); - foreach ($value as $entry) { + // 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); - $oid = spl_object_hash($entry); - if ($state == self::STATE_NEW) { - if ( ! $assoc['isCascadePersist']) { - throw new InvalidArgumentException("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) . "." - . " Explicitly persist the new entity or configure cascading persist operations" - . " on the relationship. If you cannot find out which entity causes the problem" - . " implement '" . $assoc['targetEntity'] . "#__toString()' to get a clue."); - } - $this->persistNew($targetClass, $entry); - $this->computeChangeSet($targetClass, $entry); - } else if ($state == self::STATE_REMOVED) { - return new InvalidArgumentException("Removed entity detected during flush: " - . self::objToStr($entry).". Remove deleted entities from associations."); - } else if ($state == 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 new InvalidArgumentException("A detached entity was found through a " - . "relationship during cascading a persist operation."); + $oid = spl_object_hash($entry); + + 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. } - // MANAGED associated entities are already taken into account - // during changeset calculation anyway, since they are in the identity map. } } 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) { - $this->entityIdentifiers[$oid] = array($class->identifier[0] => $idValue); - $class->setIdentifierValues($entity, $this->entityIdentifiers[$oid]); - } else { - $this->entityIdentifiers[$oid] = $idValue; + $idValue = array($class->identifier[0] => $idValue); + + $class->setIdentifierValues($entity, $idValue); } + + $this->entityIdentifiers[$oid] = $idValue; } + $this->entityStates[$oid] = self::STATE_MANAGED; $this->scheduleForInsert($entity); @@ -653,24 +818,25 @@ class UnitOfWork implements PropertyChangedListener * @param object $entity The entity for which to (re)calculate the change set. * @throws InvalidArgumentException If the passed entity is not MANAGED. */ - public function recomputeSingleEntityChangeSet($class, $entity) + public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity) { $oid = spl_object_hash($entity); if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) { - throw new InvalidArgumentException('Entity must be managed.'); + throw ORMInvalidArgumentException::entityNotManaged($entity); } - /* TODO: Just return if changetracking policy is NOTIFY? + // 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); @@ -682,6 +848,7 @@ class UnitOfWork implements PropertyChangedListener 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)) { @@ -693,6 +860,7 @@ class UnitOfWork implements PropertyChangedListener if (isset($this->entityChangeSets[$oid])) { $this->entityChangeSets[$oid] = array_merge($this->entityChangeSets[$oid], $changeSet); } + $this->originalEntityData[$oid] = $actualData; } } @@ -706,20 +874,22 @@ class UnitOfWork implements PropertyChangedListener { $className = $class->name; $persister = $this->getEntityPersister($className); + $entities = array(); $hasLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::postPersist]); - $hasListeners = $this->evm->hasListeners(Events::postPersist); - if ($hasLifecycleCallbacks || $hasListeners) { - $entities = array(); - } + $hasListeners = $this->evm->hasListeners(Events::postPersist); foreach ($this->entityInsertions as $oid => $entity) { - if (get_class($entity) === $className) { - $persister->addInsert($entity); - unset($this->entityInsertions[$oid]); - if ($hasLifecycleCallbacks || $hasListeners) { - $entities[] = $entity; - } + if (get_class($entity) !== $className) { + continue; + } + + $persister->addInsert($entity); + + unset($this->entityInsertions[$oid]); + + if ($hasLifecycleCallbacks || $hasListeners) { + $entities[] = $entity; } } @@ -728,24 +898,26 @@ class UnitOfWork implements PropertyChangedListener if ($postInsertIds) { // Persister returned post-insert IDs foreach ($postInsertIds as $id => $entity) { - $oid = spl_object_hash($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); } } - if ($hasLifecycleCallbacks || $hasListeners) { - foreach ($entities as $entity) { - if ($hasLifecycleCallbacks) { - $class->invokeLifecycleCallbacks(Events::postPersist, $entity); - } - if ($hasListeners) { - $this->evm->dispatchEvent(Events::postPersist, new LifecycleEventArgs($entity, $this->em)); - } + foreach ($entities as $entity) { + if ($hasLifecycleCallbacks) { + $class->invokeLifecycleCallbacks(Events::postPersist, $entity); + } + + if ($hasListeners) { + $this->evm->dispatchEvent(Events::postPersist, new LifecycleEventArgs($entity, $this->em)); } } } @@ -761,35 +933,41 @@ class UnitOfWork implements PropertyChangedListener $persister = $this->getEntityPersister($className); $hasPreUpdateLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::preUpdate]); - $hasPreUpdateListeners = $this->evm->hasListeners(Events::preUpdate); + $hasPreUpdateListeners = $this->evm->hasListeners(Events::preUpdate); + $hasPostUpdateLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::postUpdate]); - $hasPostUpdateListeners = $this->evm->hasListeners(Events::postUpdate); + $hasPostUpdateListeners = $this->evm->hasListeners(Events::postUpdate); foreach ($this->entityUpdates as $oid => $entity) { - if (get_class($entity) == $className || $entity instanceof Proxy && get_parent_class($entity) == $className) { + if ( ! (get_class($entity) === $className || $entity instanceof Proxy && get_parent_class($entity) === $className)) { + continue; + } - if ($hasPreUpdateLifecycleCallbacks) { - $class->invokeLifecycleCallbacks(Events::preUpdate, $entity); - $this->recomputeSingleEntityChangeSet($class, $entity); - } + if ($hasPreUpdateLifecycleCallbacks) { + $class->invokeLifecycleCallbacks(Events::preUpdate, $entity); - if ($hasPreUpdateListeners) { - $this->evm->dispatchEvent(Events::preUpdate, new Event\PreUpdateEventArgs( - $entity, $this->em, $this->entityChangeSets[$oid]) - ); - } + $this->recomputeSingleEntityChangeSet($class, $entity); + } - if ($this->entityChangeSets[$oid]) { - $persister->update($entity); - } - unset($this->entityUpdates[$oid]); + if ($hasPreUpdateListeners) { + $this->evm->dispatchEvent( + Events::preUpdate, + new Event\PreUpdateEventArgs($entity, $this->em, $this->entityChangeSets[$oid]) + ); + } - if ($hasPostUpdateLifecycleCallbacks) { - $class->invokeLifecycleCallbacks(Events::postUpdate, $entity); - } - if ($hasPostUpdateListeners) { - $this->evm->dispatchEvent(Events::postUpdate, new LifecycleEventArgs($entity, $this->em)); - } + 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)); } } } @@ -808,27 +986,32 @@ class UnitOfWork implements PropertyChangedListener $hasListeners = $this->evm->hasListeners(Events::postRemove); foreach ($this->entityDeletions as $oid => $entity) { - if (get_class($entity) == $className || $entity instanceof Proxy && get_parent_class($entity) == $className) { - $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 ( ! (get_class($entity) == $className || $entity instanceof Proxy && get_parent_class($entity) == $className)) { + continue; + } - if ($hasLifecycleCallbacks) { - $class->invokeLifecycleCallbacks(Events::postRemove, $entity); - } - if ($hasListeners) { - $this->evm->dispatchEvent(Events::postRemove, new LifecycleEventArgs($entity, $this->em)); - } + $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)); } } } @@ -841,51 +1024,63 @@ class UnitOfWork implements PropertyChangedListener private function getCommitOrder(array $entityChangeSet = null) { if ($entityChangeSet === null) { - $entityChangeSet = array_merge( - $this->entityInsertions, - $this->entityUpdates, - $this->entityDeletions - ); + $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). - - // TODO: Can we know the know the possible $newNodes based on something more efficient? IdentityMap? + // 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 $oid => $entity) { $className = get_class($entity); - if ( ! $calc->hasClass($className)) { - $class = $this->em->getClassMetadata($className); - $calc->addClass($class); - $newNodes[] = $class; + + 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) { - $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) { - foreach ($targetClass->subClasses as $subClassName) { - $targetSubClass = $this->em->getClassMetadata($subClassName); - if ( ! $calc->hasClass($subClassName)) { - $calc->addClass($targetSubClass); - $newNodes[] = $targetSubClass; - } - $calc->addDependency($targetSubClass, $class); - } + 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); } } } @@ -906,11 +1101,16 @@ class UnitOfWork implements PropertyChangedListener if (isset($this->entityUpdates[$oid])) { throw new InvalidArgumentException("Dirty entity can not be scheduled for insertion."); } + if (isset($this->entityDeletions[$oid])) { - throw new InvalidArgumentException("Removed entity can not be scheduled for insertion."); + throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity); + } + if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) { + throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity); } + if (isset($this->entityInsertions[$oid])) { - throw new InvalidArgumentException("Entity can not be scheduled for insertion twice."); + throw ORMInvalidArgumentException::scheduleInsertTwice($entity); } $this->entityInsertions[$oid] = $entity; @@ -939,11 +1139,13 @@ class UnitOfWork implements PropertyChangedListener public function scheduleForUpdate($entity) { $oid = spl_object_hash($entity); + if ( ! isset($this->entityIdentifiers[$oid])) { - throw new InvalidArgumentException("Entity has no identity."); + throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "scheduling for update"); } + if (isset($this->entityDeletions[$oid])) { - throw new InvalidArgumentException("Entity is removed."); + throw ORMInvalidArgumentException::entityIsRemoved($entity, "schedule for update"); } if ( ! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid])) { @@ -964,13 +1166,16 @@ class UnitOfWork implements PropertyChangedListener */ public function scheduleExtraUpdate($entity, array $changeset) { - $oid = spl_object_hash($entity); + $oid = spl_object_hash($entity); + $extraUpdate = array($entity, $changeset); + if (isset($this->extraUpdates[$oid])) { list($ignored, $changeset2) = $this->extraUpdates[$oid]; - $this->extraUpdates[$oid] = array($entity, $changeset + $changeset2); - } else { - $this->extraUpdates[$oid] = array($entity, $changeset); + + $extraUpdate = array($entity, $changeset + $changeset2); } + + $this->extraUpdates[$oid] = $extraUpdate; } /** @@ -986,9 +1191,17 @@ class UnitOfWork implements PropertyChangedListener 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)]); } @@ -1006,12 +1219,14 @@ class UnitOfWork implements PropertyChangedListener 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; // ignore + return; } $this->removeFromIdentityMap($entity); @@ -1019,9 +1234,10 @@ class UnitOfWork implements PropertyChangedListener if (isset($this->entityUpdates[$oid])) { unset($this->entityUpdates[$oid]); } + if ( ! isset($this->entityDeletions[$oid])) { $this->entityDeletions[$oid] = $entity; - $this->entityStates[$oid] = self::STATE_REMOVED; + $this->entityStates[$oid] = self::STATE_REMOVED; } } @@ -1046,9 +1262,10 @@ class UnitOfWork implements PropertyChangedListener public function isEntityScheduled($entity) { $oid = spl_object_hash($entity); - return isset($this->entityInsertions[$oid]) || - isset($this->entityUpdates[$oid]) || - isset($this->entityDeletions[$oid]); + + return isset($this->entityInsertions[$oid]) + || isset($this->entityUpdates[$oid]) + || isset($this->entityDeletions[$oid]); } /** @@ -1065,18 +1282,24 @@ class UnitOfWork implements PropertyChangedListener public function addToIdentityMap($entity) { $classMetadata = $this->em->getClassMetadata(get_class($entity)); - $idHash = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]); + $idHash = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]); + if ($idHash === '') { - throw new InvalidArgumentException("The given entity has no identity."); + throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity); } + $className = $classMetadata->rootEntityName; + if (isset($this->identityMap[$className][$idHash])) { return false; } + $this->identityMap[$className][$idHash] = $entity; + if ($entity instanceof NotifyPropertyChanged) { $entity->addPropertyChangedListener($this); } + return true; } @@ -1093,61 +1316,67 @@ class UnitOfWork implements PropertyChangedListener public function getEntityState($entity, $assume = null) { $oid = spl_object_hash($entity); - if ( ! isset($this->entityStates[$oid])) { - // 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. - if ($assume === null) { - $class = $this->em->getClassMetadata(get_class($entity)); - $id = $class->getIdentifierValues($entity); - if ( ! $id) { - return self::STATE_NEW; - } else if ($class->isIdentifierNatural()) { - // Check for a version field, if available, to avoid a db lookup. - if ($class->isVersioned) { - if ($class->getFieldValue($entity, $class->versionField)) { - return self::STATE_DETACHED; - } else { - return self::STATE_NEW; - } - } else { - // Last try before db lookup: check the identity map. - if ($this->tryGetById($id, $class->rootEntityName)) { - return self::STATE_DETACHED; - } else { - // db lookup - if ($this->getEntityPersister(get_class($entity))->exists($entity)) { - return self::STATE_DETACHED; - } else { - return self::STATE_NEW; - } - } - } - } else if (!$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; - } else { - // db lookup - if ($this->getEntityPersister(get_class($entity))->exists($entity)) { - return self::STATE_DETACHED; - } else { - return self::STATE_NEW; - } - } - } else { + + 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; } - } else { - return $assume; - } + + // db lookup + if ($this->getEntityPersister(get_class($entity))->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(get_class($entity))->exists($entity)) { + return self::STATE_DETACHED; + } + + return self::STATE_NEW; + + default: + return self::STATE_DETACHED; } - return $this->entityStates[$oid]; } /** @@ -1161,16 +1390,22 @@ class UnitOfWork implements PropertyChangedListener */ public function removeFromIdentityMap($entity) { - $oid = spl_object_hash($entity); + $oid = spl_object_hash($entity); $classMetadata = $this->em->getClassMetadata(get_class($entity)); - $idHash = implode(' ', $this->entityIdentifiers[$oid]); + $idHash = implode(' ', $this->entityIdentifiers[$oid]); + if ($idHash === '') { - throw new InvalidArgumentException("The given entity has no identity."); + 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; } @@ -1203,8 +1438,11 @@ class UnitOfWork implements PropertyChangedListener */ public function tryGetByIdHash($idHash, $rootClassName) { - return isset($this->identityMap[$rootClassName][$idHash]) ? - $this->identityMap[$rootClassName][$idHash] : false; + if (isset($this->identityMap[$rootClassName][$idHash])) { + return $this->identityMap[$rootClassName][$idHash]; + } + + return false; } /** @@ -1216,11 +1454,14 @@ class UnitOfWork implements PropertyChangedListener 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]); + $idHash = implode(' ', $this->entityIdentifiers[$oid]); + if ($idHash === '') { return false; } @@ -1250,6 +1491,7 @@ class UnitOfWork implements PropertyChangedListener public function persist($entity) { $visited = array(); + $this->doPersist($entity, $visited); } @@ -1265,6 +1507,7 @@ class UnitOfWork implements PropertyChangedListener private function doPersist($entity, array &$visited) { $oid = spl_object_hash($entity); + if (isset($visited[$oid])) { return; // Prevent infinite recursion } @@ -1286,19 +1529,24 @@ class UnitOfWork implements PropertyChangedListener $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 new InvalidArgumentException("Detached entity passed to persist()."); + throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted"); + default: - throw new UnexpectedValueException("Unexpected entity state: $entityState."); + throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity)); } $this->cascadePersist($entity, $visited); @@ -1312,6 +1560,7 @@ class UnitOfWork implements PropertyChangedListener public function remove($entity) { $visited = array(); + $this->doRemove($entity, $visited); } @@ -1328,6 +1577,7 @@ class UnitOfWork implements PropertyChangedListener private function doRemove($entity, array &$visited) { $oid = spl_object_hash($entity); + if (isset($visited[$oid])) { return; // Prevent infinite recursion } @@ -1338,26 +1588,31 @@ class UnitOfWork implements PropertyChangedListener // 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)); + $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 new InvalidArgumentException("A detached entity can not be removed."); + throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed"); default: - throw new UnexpectedValueException("Unexpected entity state: $entityState."); + throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity)); } } @@ -1375,6 +1630,7 @@ class UnitOfWork implements PropertyChangedListener public function merge($entity) { $visited = array(); + return $this->doMerge($entity, $visited); } @@ -1391,6 +1647,7 @@ class UnitOfWork implements PropertyChangedListener private function doMerge($entity, array &$visited, $prevManagedCopy = null, $assoc = null) { $oid = spl_object_hash($entity); + if (isset($visited[$oid])) { return; // Prevent infinite recursion } @@ -1403,9 +1660,9 @@ class UnitOfWork implements PropertyChangedListener // 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. - if ($this->getEntityState($entity, self::STATE_DETACHED) == self::STATE_MANAGED) { - $managedCopy = $entity; - } else { + $managedCopy = $entity; + + if ($this->getEntityState($entity, self::STATE_DETACHED) !== self::STATE_MANAGED) { if ($entity instanceof Proxy && ! $entity->__isInitialized__) { $entity->__load(); } @@ -1415,7 +1672,8 @@ class UnitOfWork implements PropertyChangedListener // If there is no ID, it is actually NEW. if ( ! $id) { - $managedCopy = $class->newInstance(); + $managedCopy = $this->newInstance($class); + $this->persistNew($class, $managedCopy); } else { $flatId = $id; @@ -1432,11 +1690,11 @@ class UnitOfWork implements PropertyChangedListener } $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 new InvalidArgumentException('Removed entity detected during merge.' - . ' Can not merge with a removed entity.'); + throw ORMInvalidArgumentException::entityIsRemoved($managedCopy, "merge"); } } else { // We need to fetch the managed copy in order to merge. @@ -1446,11 +1704,7 @@ class UnitOfWork implements PropertyChangedListener if ($managedCopy === null) { // If the identifier is ASSIGNED, it is NEW, otherwise an error // since the managed entity was not found. - if ($class->isIdentifierNatural()) { - $managedCopy = $class->newInstance(); - $class->setIdentifierValues($managedCopy, $id); - $this->persistNew($class, $managedCopy); - } else { + if ( ! $class->isIdentifierNatural()) { throw new EntityNotFoundException; } @@ -1468,6 +1722,7 @@ class UnitOfWork implements PropertyChangedListener 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); @@ -1523,10 +1778,12 @@ class UnitOfWork implements PropertyChangedListener } 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) { + 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); } @@ -1534,11 +1791,13 @@ class UnitOfWork implements PropertyChangedListener } } } + 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); } @@ -1547,10 +1806,12 @@ class UnitOfWork implements PropertyChangedListener 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); } @@ -1574,6 +1835,7 @@ class UnitOfWork implements PropertyChangedListener public function detach($entity) { $visited = array(); + $this->doDetach($entity, $visited); } @@ -1582,10 +1844,12 @@ class UnitOfWork implements PropertyChangedListener * * @param object $entity * @param array $visited + * @param boolean $noCascade if true, don't cascade detach operation */ - private function doDetach($entity, array &$visited) + private function doDetach($entity, array &$visited, $noCascade = false) { $oid = spl_object_hash($entity); + if (isset($visited[$oid])) { return; // Prevent infinite recursion } @@ -1597,16 +1861,24 @@ class UnitOfWork implements PropertyChangedListener 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]); + + 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; } - $this->cascadeDetach($entity, $visited); + if ( ! $noCascade) { + $this->cascadeDetach($entity, $visited); + } } /** @@ -1619,6 +1891,7 @@ class UnitOfWork implements PropertyChangedListener public function refresh($entity) { $visited = array(); + $this->doRefresh($entity, $visited); } @@ -1632,6 +1905,7 @@ class UnitOfWork implements PropertyChangedListener private function doRefresh($entity, array &$visited) { $oid = spl_object_hash($entity); + if (isset($visited[$oid])) { return; // Prevent infinite recursion } @@ -1639,15 +1913,16 @@ class UnitOfWork implements PropertyChangedListener $visited[$oid] = $entity; // mark visited $class = $this->em->getClassMetadata(get_class($entity)); - if ($this->getEntityState($entity) == self::STATE_MANAGED) { - $this->getEntityPersister($class->name)->refresh( - array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]), - $entity - ); - } else { - throw new InvalidArgumentException("Entity is not MANAGED."); + + 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); } @@ -1660,21 +1935,34 @@ class UnitOfWork implements PropertyChangedListener private function cascadeRefresh($entity, array &$visited) { $class = $this->em->getClassMetadata(get_class($entity)); - foreach ($class->associationMappings as $assoc) { - if ( ! $assoc['isCascadeRefresh']) { - continue; - } + + $associationMappings = array_filter( + $class->associationMappings, + function ($assoc) { return $assoc['isCascadeRefresh']; } + ); + + foreach ($associationMappings as $assoc) { $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); - if ($relatedEntities instanceof Collection) { - if ($relatedEntities instanceof PersistentCollection) { + + switch (true) { + case ($relatedEntities instanceof PersistentCollection): // Unwrap so that foreach() does not initialize $relatedEntities = $relatedEntities->unwrap(); - } - foreach ($relatedEntities as $relatedEntity) { - $this->doRefresh($relatedEntity, $visited); - } - } else if ($relatedEntities !== null) { - $this->doRefresh($relatedEntities, $visited); + // 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 } } } @@ -1688,21 +1976,34 @@ class UnitOfWork implements PropertyChangedListener private function cascadeDetach($entity, array &$visited) { $class = $this->em->getClassMetadata(get_class($entity)); - foreach ($class->associationMappings as $assoc) { - if ( ! $assoc['isCascadeDetach']) { - continue; - } + + $associationMappings = array_filter( + $class->associationMappings, + function ($assoc) { return $assoc['isCascadeDetach']; } + ); + + foreach ($associationMappings as $assoc) { $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); - if ($relatedEntities instanceof Collection) { - if ($relatedEntities instanceof PersistentCollection) { + + switch (true) { + case ($relatedEntities instanceof PersistentCollection): // Unwrap so that foreach() does not initialize $relatedEntities = $relatedEntities->unwrap(); - } - foreach ($relatedEntities as $relatedEntity) { - $this->doDetach($relatedEntity, $visited); - } - } else if ($relatedEntities !== null) { - $this->doDetach($relatedEntities, $visited); + // 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 } } } @@ -1717,11 +2018,15 @@ class UnitOfWork implements PropertyChangedListener private function cascadeMerge($entity, $managedCopy, array &$visited) { $class = $this->em->getClassMetadata(get_class($entity)); - foreach ($class->associationMappings as $assoc) { - if ( ! $assoc['isCascadeMerge']) { - continue; - } + + $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; @@ -1731,6 +2036,7 @@ class UnitOfWork implements PropertyChangedListener // Unwrap so that foreach() does not initialize $relatedEntities = $relatedEntities->unwrap(); } + foreach ($relatedEntities as $relatedEntity) { $this->doMerge($relatedEntity, $visited, $managedCopy, $assoc); } @@ -1750,22 +2056,34 @@ class UnitOfWork implements PropertyChangedListener private function cascadePersist($entity, array &$visited) { $class = $this->em->getClassMetadata(get_class($entity)); - foreach ($class->associationMappings as $assoc) { - if ( ! $assoc['isCascadePersist']) { - continue; - } + $associationMappings = array_filter( + $class->associationMappings, + function ($assoc) { return $assoc['isCascadePersist']; } + ); + + foreach ($associationMappings as $assoc) { $relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); - if (($relatedEntities instanceof Collection || is_array($relatedEntities))) { - if ($relatedEntities instanceof PersistentCollection) { + + switch (true) { + case ($relatedEntities instanceof PersistentCollection): // Unwrap so that foreach() does not initialize $relatedEntities = $relatedEntities->unwrap(); - } - foreach ($relatedEntities as $relatedEntity) { - $this->doPersist($relatedEntity, $visited); - } - } else if ($relatedEntities !== null) { - $this->doPersist($relatedEntities, $visited); + // 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 } } } @@ -1779,23 +2097,34 @@ class UnitOfWork implements PropertyChangedListener private function cascadeRemove($entity, array &$visited) { $class = $this->em->getClassMetadata(get_class($entity)); - foreach ($class->associationMappings as $assoc) { - if ( ! $assoc['isCascadeRemove']) { - continue; - } + $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); - if ($relatedEntities instanceof Collection || is_array($relatedEntities)) { - // If its a PersistentCollection initialization is intended! No unwrap! - foreach ($relatedEntities as $relatedEntity) { - $this->doRemove($relatedEntity, $visited); - } - } else if ($relatedEntities !== null) { - $this->doRemove($relatedEntities, $visited); + + 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 } } } @@ -1810,35 +2139,46 @@ class UnitOfWork implements PropertyChangedListener public function lock($entity, $lockMode, $lockVersion = null) { if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) { - throw new InvalidArgumentException("Entity is not MANAGED."); + throw ORMInvalidArgumentException::entityNotManaged($entity); } $entityName = get_class($entity); $class = $this->em->getClassMetadata($entityName); - if ($lockMode == \Doctrine\DBAL\LockMode::OPTIMISTIC) { - if (!$class->isVersioned) { - throw OptimisticLockException::notVersioned($entityName); - } + switch ($lockMode) { + case \Doctrine\DBAL\LockMode::OPTIMISTIC; + if ( ! $class->isVersioned) { + throw OptimisticLockException::notVersioned($entityName); + } + + if ($lockVersion === null) { + return; + } - if ($lockVersion != null) { $entityVersion = $class->reflFields[$class->versionField]->getValue($entity); + if ($entityVersion != $lockVersion) { throw OptimisticLockException::lockFailedVersionMissmatch($entity, $lockVersion, $entityVersion); } - } - } else if (in_array($lockMode, array(\Doctrine\DBAL\LockMode::PESSIMISTIC_READ, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE))) { - if (!$this->em->getConnection()->isTransactionActive()) { - throw TransactionRequiredException::transactionRequired(); - } + break; - $oid = spl_object_hash($entity); + case \Doctrine\DBAL\LockMode::PESSIMISTIC_READ: + case \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE: + if (!$this->em->getConnection()->isTransactionActive()) { + throw TransactionRequiredException::transactionRequired(); + } - $this->getEntityPersister($class->name)->lock( - array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]), - $lockMode - ); + $oid = spl_object_hash($entity); + + $this->getEntityPersister($class->name)->lock( + array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]), + $lockMode + ); + break; + + default: + // Do nothing } } @@ -1852,33 +2192,49 @@ class UnitOfWork implements PropertyChangedListener if ($this->commitOrderCalculator === null) { $this->commitOrderCalculator = new Internal\CommitOrderCalculator; } + return $this->commitOrderCalculator; } /** * Clears the UnitOfWork. - */ - public function clear() - { - $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->orphanRemovals = array(); - if ($this->commitOrderCalculator !== null) { - $this->commitOrderCalculator->clear(); + * + * @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)); + $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName)); } } @@ -1904,14 +2260,34 @@ class UnitOfWork implements PropertyChangedListener */ 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? - $this->collectionDeletions[] = $coll; + if (isset($this->collectionUpdates[$coid])) { + unset($this->collectionUpdates[$coid]); + } + + $this->collectionDeletions[$coid] = $coll; } public function isCollectionScheduledForDeletion(PersistentCollection $coll) { - return in_array($coll, $this->collectionsDeletions, true); + return isset($this->collectionsDeletions[spl_object_hash($coll)]); + } + + /** + * @param ClassMetadata $class + */ + private function newInstance($class) + { + $entity = $class->newInstance(); + + if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) { + $entity->injectObjectManager($this->em, $class); + } + + return $entity; } /** @@ -1934,29 +2310,30 @@ class UnitOfWork implements PropertyChangedListener 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]; - } + $id[$fieldName] = isset($class->associationMappings[$fieldName]) + ? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']] + : $data[$fieldName]; } + $idHash = implode(' ', $id); } else { - if (isset($class->associationMappings[$class->identifier[0]])) { - $idHash = $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']]; - } else { - $idHash = $data[$class->identifier[0]]; - } + $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); } @@ -1966,6 +2343,11 @@ class UnitOfWork implements PropertyChangedListener // 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); + } } } @@ -1973,150 +2355,186 @@ class UnitOfWork implements PropertyChangedListener $this->originalEntityData[$oid] = $data; } } else { - $entity = $class->newInstance(); + $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) { - foreach ($data as $field => $value) { - if (isset($class->fieldMappings[$field])) { - $class->reflFields[$field]->setValue($entity, $value); - } + 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]); + // Loading the entity right here, if its in the eager loading map get rid of it there. + unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]); - // Properly initialize any unfetched associations, if partial objects are not allowed. - if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) { - 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; + 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; } - $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); - - if ($assoc['type'] & ClassMetadata::TO_ONE) { - if ($assoc['isOwningSide']) { - $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; - } else { - if (!isset($hints['fetchMode'][$class->name][$field])) { - $hints['fetchMode'][$class->name][$field] = $assoc['fetch']; - } + $associatedId = array(); - // 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); - if (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 cann 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); - } - } else { - if ($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); - } else { - // Deferred eager load only works for single identifier classes - - if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER) { - if (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); - } else { - // TODO: This is very imperformant, ignore it? - $newValue = $this->em->find($assoc['targetEntity'], $associatedId); - } - } else { - $newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId); - } - // 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! - } - } - $this->originalEntityData[$oid][$field] = $newValue; - $class->reflFields[$field]->setValue($entity, $newValue); + // 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 ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) { - $inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']]; - $targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($newValue, $entity); - } + if ($joinColumnValue !== null) { + if ($targetClass->containsForeignIdentifier) { + $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue; + } else { + $associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue; } - } else { - // Inverse side of x-to-one can never be lazy - $class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity']) - ->loadOneToOneEntity($assoc, $entity)); } - } else { - // Inject collection - $pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection); - $pColl->setOwner($entity, $assoc); - - $reflField = $class->reflFields[$field]; - $reflField->setValue($entity, $pColl); - - if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) { - $this->loadCollection($pColl); - $pColl->takeSnapshot(); - } else { - $pColl->setInitialized(false); - } - $this->originalEntityData[$oid][$field] = $pColl; } - } + + 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 cann 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; } } - //TODO: These should be invoked later, after hydration, because associations may not yet be loaded here. - 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)); + 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; @@ -2127,16 +2545,17 @@ class UnitOfWork implements PropertyChangedListener */ public function triggerEagerLoads() { - if (!$this->eagerLoadingEntities) { + if ( ! $this->eagerLoadingEntities) { return; } // avoid infinite recursion - $eagerLoadingEntities = $this->eagerLoadingEntities; + $eagerLoadingEntities = $this->eagerLoadingEntities; $this->eagerLoadingEntities = array(); - foreach ($eagerLoadingEntities AS $entityName => $ids) { + foreach ($eagerLoadingEntities as $entityName => $ids) { $class = $this->em->getClassMetadata($entityName); + if ($ids) { $this->getEntityPersister($entityName)->loadAll( array_combine($class->identifier, array(array_values($ids))) @@ -2153,15 +2572,16 @@ class UnitOfWork implements PropertyChangedListener */ public function loadCollection(PersistentCollection $collection) { - $assoc = $collection->getMapping(); + $assoc = $collection->getMapping(); + $persister = $this->getEntityPersister($assoc['targetEntity']); + switch ($assoc['type']) { case ClassMetadata::ONE_TO_MANY: - $this->getEntityPersister($assoc['targetEntity'])->loadOneToManyCollection( - $assoc, $collection->getOwner(), $collection); + $persister->loadOneToManyCollection($assoc, $collection->getOwner(), $collection); break; + case ClassMetadata::MANY_TO_MANY: - $this->getEntityPersister($assoc['targetEntity'])->loadManyToManyCollection( - $assoc, $collection->getOwner(), $collection); + $persister->loadManyToManyCollection($assoc, $collection->getOwner(), $collection); break; } } @@ -2186,9 +2606,11 @@ class UnitOfWork implements PropertyChangedListener public function getOriginalEntityData($entity) { $oid = spl_object_hash($entity); + if (isset($this->originalEntityData[$oid])) { return $this->originalEntityData[$oid]; } + return array(); } @@ -2240,9 +2662,11 @@ class UnitOfWork implements PropertyChangedListener public function tryGetById($id, $rootClassName) { $idHash = implode(' ', (array) $id); + if (isset($this->identityMap[$rootClassName][$idHash])) { return $this->identityMap[$rootClassName][$idHash]; } + return false; } @@ -2255,6 +2679,7 @@ class UnitOfWork implements PropertyChangedListener public function scheduleForDirtyCheck($entity) { $rootClassName = $this->em->getClassMetadata(get_class($entity))->rootEntityName; + $this->scheduledForDirtyCheck[$rootClassName][spl_object_hash($entity)] = $entity; } @@ -2276,34 +2701,45 @@ class UnitOfWork implements PropertyChangedListener */ public function size() { - $count = 0; - foreach ($this->identityMap as $entitySet) { - $count += count($entitySet); - } - return $count; + $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\AbstractEntityPersister + * + * @return \Doctrine\ORM\Persisters\BasicEntityPersister */ public function getEntityPersister($entityName) { - if ( ! isset($this->persisters[$entityName])) { - $class = $this->em->getClassMetadata($entityName); - if ($class->isInheritanceTypeNone()) { + 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); - } else if ($class->isInheritanceTypeSingleTable()) { + break; + + case ($class->isInheritanceTypeSingleTable()): $persister = new Persisters\SingleTablePersister($this->em, $class); - } else if ($class->isInheritanceTypeJoined()) { + break; + + case ($class->isInheritanceTypeJoined()): $persister = new Persisters\JoinedSubclassPersister($this->em, $class); - } else { + break; + + default: $persister = new Persisters\UnionSubclassPersister($this->em, $class); - } - $this->persisters[$entityName] = $persister; } + + $this->persisters[$entityName] = $persister; + return $this->persisters[$entityName]; } @@ -2311,19 +2747,29 @@ class UnitOfWork implements PropertyChangedListener * Gets a collection persister for a collection-valued association. * * @param AssociationMapping $association + * * @return AbstractCollectionPersister */ public function getCollectionPersister(array $association) { $type = $association['type']; - if ( ! isset($this->collectionPersisters[$type])) { - if ($type == ClassMetadata::ONE_TO_MANY) { + + if (isset($this->collectionPersisters[$type])) { + return $this->collectionPersisters[$type]; + } + + switch ($type) { + case ClassMetadata::ONE_TO_MANY: $persister = new Persisters\OneToManyPersister($this->em); - } else if ($type == ClassMetadata::MANY_TO_MANY) { + break; + + case ClassMetadata::MANY_TO_MANY: $persister = new Persisters\ManyToManyPersister($this->em); - } - $this->collectionPersisters[$type] = $persister; + break; } + + $this->collectionPersisters[$type] = $persister; + return $this->collectionPersisters[$type]; } @@ -2338,9 +2784,11 @@ class UnitOfWork implements PropertyChangedListener public function registerManaged($entity, array $id, array $data) { $oid = spl_object_hash($entity); - $this->entityIdentifiers[$oid] = $id; - $this->entityStates[$oid] = self::STATE_MANAGED; + + $this->entityIdentifiers[$oid] = $id; + $this->entityStates[$oid] = self::STATE_MANAGED; $this->originalEntityData[$oid] = $data; + $this->addToIdentityMap($entity); } @@ -2367,7 +2815,7 @@ class UnitOfWork implements PropertyChangedListener */ public function propertyChanged($entity, $propertyName, $oldValue, $newValue) { - $oid = spl_object_hash($entity); + $oid = spl_object_hash($entity); $class = $this->em->getClassMetadata(get_class($entity)); $isAssocField = isset($class->associationMappings[$propertyName]); @@ -2378,6 +2826,7 @@ class UnitOfWork implements PropertyChangedListener // Update changeset and mark entity for synchronization $this->entityChangeSets[$oid][$propertyName] = array($oldValue, $newValue); + if ( ! isset($this->scheduledForDirtyCheck[$class->rootEntityName][$oid])) { $this->scheduleForDirtyCheck($entity); } @@ -2443,7 +2892,11 @@ class UnitOfWork implements PropertyChangedListener { if ($obj instanceof Proxy) { $obj->__load(); - } else if ($obj instanceof PersistentCollection) { + + return; + } + + if ($obj instanceof PersistentCollection) { $obj->initialize(); } } @@ -2472,8 +2925,9 @@ class UnitOfWork implements PropertyChangedListener public function markReadOnly($object) { if ( ! is_object($object) || ! $this->isInIdentityMap($object)) { - throw new InvalidArgumentException("Managed entity required"); + throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object); } + $this->readOnlyObjects[spl_object_hash($object)] = true; } @@ -2487,8 +2941,9 @@ class UnitOfWork implements PropertyChangedListener public function isReadOnly($object) { if ( ! is_object($object) ) { - throw new InvalidArgumentException("Managed entity required"); + throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object); } + return isset($this->readOnlyObjects[spl_object_hash($object)]); } } diff --git a/main/inc/lib/symfony/Doctrine/ORM/Version.php b/main/inc/lib/symfony/Doctrine/ORM/Version.php index acaf57db47..9d41ec7aed 100644 --- a/main/inc/lib/symfony/Doctrine/ORM/Version.php +++ b/main/inc/lib/symfony/Doctrine/ORM/Version.php @@ -16,7 +16,7 @@ * and is licensed under the LGPL. For more information, see * . */ - + namespace Doctrine\ORM; /** @@ -36,13 +36,13 @@ class Version /** * Current Doctrine Version */ - const VERSION = '2.1.6'; + const VERSION = '2.2.2'; /** * 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 + * @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) From 7c02aa60fa96af1d9be011dada1002dab256e3e0 Mon Sep 17 00:00:00 2001 From: Hubert Borderiou Date: Wed, 2 May 2012 11:35:25 +0200 Subject: [PATCH 002/128] Solve path problem when uploading media with fckeditor if url_append != "" - ref#3933 --- .../editor/dialog/fck_flash/fck_flash.js | 7 +- .../editor/dialog/fck_image/fck_image.js | 25 ++- .../editor/dialog/fck_link/fck_link.js | 14 +- .../filemanager/connectors/php/config.php | 29 ++-- .../editor/filemanager/connectors/php/io.php | 7 +- .../editor/plugins/ImageManager/images.php | 17 +- .../fckeditor/editor/plugins/MP3/fck_mp3.js | 11 +- .../editor/plugins/audio/fck_audio.js | 46 +++-- .../plugins/fckEmbedMovies/fck_embedmovies.js | 6 +- .../editor/plugins/flvPlayer/flvPlayer.js | 160 ++++++++++++------ 10 files changed, 222 insertions(+), 100 deletions(-) mode change 100755 => 100644 main/inc/lib/fckeditor/editor/dialog/fck_flash/fck_flash.js mode change 100755 => 100644 main/inc/lib/fckeditor/editor/dialog/fck_link/fck_link.js mode change 100755 => 100644 main/inc/lib/fckeditor/editor/filemanager/connectors/php/config.php mode change 100755 => 100644 main/inc/lib/fckeditor/editor/filemanager/connectors/php/io.php mode change 100755 => 100644 main/inc/lib/fckeditor/editor/plugins/ImageManager/images.php diff --git a/main/inc/lib/fckeditor/editor/dialog/fck_flash/fck_flash.js b/main/inc/lib/fckeditor/editor/dialog/fck_flash/fck_flash.js old mode 100755 new mode 100644 index cc99655e45..91469e403f --- a/main/inc/lib/fckeditor/editor/dialog/fck_flash/fck_flash.js +++ b/main/inc/lib/fckeditor/editor/dialog/fck_flash/fck_flash.js @@ -233,9 +233,12 @@ function BrowseServer() function SetUrl( url, width, height ) { - // Added by Ivan Tcholakov. - //url = FCK.GetSelectedUrl( url ) ; url = FCK.GetSelectedFlashUrl( url ) ; + // search the URLPrefix like it is the configuration.php file + PrefixeUrl = self.location.href.replace(/\/main\/inc\/lib\/fckeditor\/editor\/dialog\/fck_flash.\html/, ""); + PrefixeUrl = PrefixeUrl.replace(/http:\/\/[^\/]+/, ""); + url = PrefixeUrl + url ; + // GetE('txtUrl').value = url ; diff --git a/main/inc/lib/fckeditor/editor/dialog/fck_image/fck_image.js b/main/inc/lib/fckeditor/editor/dialog/fck_image/fck_image.js index a35b61e498..c0eb4970b2 100644 --- a/main/inc/lib/fckeditor/editor/dialog/fck_image/fck_image.js +++ b/main/inc/lib/fckeditor/editor/dialog/fck_image/fck_image.js @@ -33,13 +33,13 @@ var FCKTools = oEditor.FCKTools ; window.document.dir = FCKLang.Dir ; // We have to avoid javascript errors if some language variables have not been defined. -FCKLang['UploadSelectFileFirst'] = FCKLang['UploadSelectFileFirst'] ? FCKLang['UploadSelectFileFirst'] : 'Please, select a file before pressing the upload button.' ; +FCKLang['UploadSelectFileFirst'] = FCKLang['UploadSelectFileFirst'] ? FCKLang['UploadSelectFileFirst'] : 'Please, select a file before pressing the upload button.' ; FCKLang['FileSuccessfullyUploaded'] = FCKLang['FileSuccessfullyUploaded'] ? FCKLang['FileSuccessfullyUploaded'] : 'Your file has been successfully uploaded.' ; -FCKLang['FileRenamed'] = FCKLang['FileRenamed'] ? FCKLang['FileRenamed'] : 'A file with the same name is already available. The uploaded file has been renamed to ' ; -FCKLang['InvalidFileType'] = FCKLang['InvalidFileType'] ? FCKLang['InvalidFileType'] : 'Invalid file type.' ; -FCKLang['SecurityError'] = FCKLang['SecurityError'] ? FCKLang['SecurityError'] : 'Security error. You probably don\'t have enough permissions to upload. Please check your server.' ; -FCKLang['ConnectorDisabled'] = FCKLang['ConnectorDisabled'] ? FCKLang['ConnectorDisabled'] : 'The upload feature (connector) is disabled.' ; -FCKLang['UploadError'] = FCKLang['UploadError'] ? FCKLang['UploadError'] : 'Error on file upload. Error number: ' ; +FCKLang['FileRenamed'] = FCKLang['FileRenamed'] ? FCKLang['FileRenamed'] : 'A file with the same name is already available. The uploaded file has been renamed to ' ; +FCKLang['InvalidFileType'] = FCKLang['InvalidFileType'] ? FCKLang['InvalidFileType'] : 'Invalid file type.' ; +FCKLang['SecurityError'] = FCKLang['SecurityError'] ? FCKLang['SecurityError'] : 'Security error. You probably don\'t have enough permissions to upload. Please check your server.' ; +FCKLang['ConnectorDisabled'] = FCKLang['ConnectorDisabled'] ? FCKLang['ConnectorDisabled'] : 'The upload feature (connector) is disabled.' ; +FCKLang['UploadError'] = FCKLang['UploadError'] ? FCKLang['UploadError'] : 'Error on file upload. Error number: ' ; var bImageButton = ( document.location.search.length > 0 && document.location.search.substr(1) == 'ImageButton' ) ; @@ -77,10 +77,13 @@ var oLink = dialog.Selection.GetSelection().MoveToAncestorNode( 'A' ) ; var oImageOriginal ; -function UpdateOriginal( resetSize ) { +function UpdateOriginal( resetSize ) +{ if ( !eImgPreview ) return ; - if ( GetE('txtUrl').value.length == 0 ) { + + if ( GetE('txtUrl').value.length == 0 ) + { oImageOriginal = null ; return ; } @@ -433,8 +436,12 @@ var sActualBrowser ; function SetUrl( url, width, height, alt ) { - // Added by Ivan Tcholakov. url = FCK.GetSelectedUrl ( url ) ; + // search the URLPrefix like it is the configuration.php file + PrefixeUrl = self.location.href.replace(/\/main\/inc\/lib\/fckeditor\/editor\/dialog\/fck_image.\html/, ""); + PrefixeUrl = PrefixeUrl.replace(/http:\/\/[^\/]+/, ""); + url = PrefixeUrl + url ; + // if ( sActualBrowser == 'Link' ) { diff --git a/main/inc/lib/fckeditor/editor/dialog/fck_link/fck_link.js b/main/inc/lib/fckeditor/editor/dialog/fck_link/fck_link.js old mode 100755 new mode 100644 index 7acbbf7f01..59a5388441 --- a/main/inc/lib/fckeditor/editor/dialog/fck_link/fck_link.js +++ b/main/inc/lib/fckeditor/editor/dialog/fck_link/fck_link.js @@ -811,7 +811,19 @@ function BrowseServer() function SetUrl( url ) { - url = FCK.GetSelectedUrl ( url ) ; + +// url = FCK.GetSelectedUrl ( url ) ; + url = FCK.GetUrl( url, FCK.SEMI_ABSOLUTE_URL ) ; + PrefixeUrl = self.location.href.replace(/\/main\/inc\/lib\/fckeditor\/editor\/dialog\/fck_link\.html/, ""); + PrefixeUrl = PrefixeUrl.replace(/http:\/\/[^\/]+/, "") + // if url_append in configuration file != "" (see ticket ref #3933) + if (PrefixeUrl != "") { + url = PrefixeUrl + url; + } + else { + url = FCK.GetSelectedUrl ( url ) ; + } + GetE('cmbLinkProtocol').value = '' ; GetE('txtUrl').value = url ; diff --git a/main/inc/lib/fckeditor/editor/filemanager/connectors/php/config.php b/main/inc/lib/fckeditor/editor/filemanager/connectors/php/config.php old mode 100755 new mode 100644 index 7738501e37..3639a648b5 --- a/main/inc/lib/fckeditor/editor/filemanager/connectors/php/config.php +++ b/main/inc/lib/fckeditor/editor/filemanager/connectors/php/config.php @@ -21,7 +21,6 @@ * * Configuration file for the File Manager Connector for PHP. */ - // Modifications by Ivan Tcholakov, JUN-2009. // Some language variables are needed. @@ -47,36 +46,40 @@ if (api_is_in_course()) { if (!api_is_in_group()) { // 1. We are inside a course and not in a group. if (api_is_allowed_to_edit()) { - $Config['UserFilesPath'] = api_get_path(REL_COURSE_PATH).api_get_course_path().'/document/'; + // $Config['UserFilesPath'] = api_get_path(REL_COURSE_PATH).api_get_course_path().'/document/'; + $Config['UserFilesPath'] = '/'.$_configuration['course_folder'].api_get_course_path().'/document/'; // } else { - // 1.2. Student + // 1.2. Student $current_session_id = api_get_session_id(); - if($current_session_id==0) - { - $Config['UserFilesPath'] = api_get_path(REL_COURSE_PATH).api_get_course_path().'/document/shared_folder/sf_user_'.api_get_user_id().'/'; + if($current_session_id==0) { + // $Config['UserFilesPath'] = api_get_path(REL_COURSE_PATH).api_get_course_path().'/document/shared_folder/sf_user_'.api_get_user_id().'/'; // + $Config['UserFilesPath'] = '/'.$_configuration['course_folder'].api_get_course_path().'/document/shared_folder/sf_user_'.api_get_user_id().'/';// } - else - { - $Config['UserFilesPath'] = api_get_path(REL_COURSE_PATH).api_get_course_path().'/document/shared_folder_session_'.$current_session_id.'/sf_user_'.api_get_user_id().'/'; + else { + // $Config['UserFilesPath'] = api_get_path(REL_COURSE_PATH).api_get_course_path().'/document/shared_folder_session_'.$current_session_id.'/sf_user_'.api_get_user_id().'/'; + $Config['UserFilesPath'] = '/'.$_configuration['course_folder'].api_get_course_path().'/document/shared_folder_session_'.$current_session_id.'/sf_user_'.api_get_user_id().'/'; } } } else { // 2. Inside a course and inside a group. global $group_properties; - $Config['UserFilesPath'] = api_get_path(REL_COURSE_PATH).api_get_course_path().'/document'.$group_properties['directory'].'/'; + // $Config['UserFilesPath'] = api_get_path(REL_COURSE_PATH).api_get_course_path().'/document'.$group_properties['directory'].'/'; // + $Config['UserFilesPath'] = '/'.$_configuration['course_folder'].api_get_course_path().'/document'.$group_properties['directory'].'/';// } } else { if (api_is_platform_admin() && $_SESSION['this_section'] == 'platform_admin') { // 3. Platform administration activities. - $Config['UserFilesPath'] = api_get_path(REL_PATH).'home/default_platform_document/'; + // $Config['UserFilesPath'] = api_get_path(REL_PATH).'home/default_platform_document/';// + $Config['UserFilesPath'] = '/home/default_platform_document/';// } else { // 4. The user is outside courses. - $my_path = UserManager::get_user_picture_path_by_id(api_get_user_id(),'rel'); - $Config['UserFilesPath'] = $my_path['dir'].'my_files/'; + $my_path = UserManager::get_user_picture_path_by_id(api_get_user_id(),'rel'); + $Config['UserFilesPath'] = $my_path['dir'].'my_files/'; } } + // Fill the following value it you prefer to specify the absolute path for the // user files directory. Useful if you are using a virtual directory, symbolic // link or alias. Examples: 'C:\\MySite\\userfiles\\' or '/root/mysite/userfiles/'. diff --git a/main/inc/lib/fckeditor/editor/filemanager/connectors/php/io.php b/main/inc/lib/fckeditor/editor/filemanager/connectors/php/io.php old mode 100755 new mode 100644 index 9eac1c89f4..c182831531 --- a/main/inc/lib/fckeditor/editor/filemanager/connectors/php/io.php +++ b/main/inc/lib/fckeditor/editor/filemanager/connectors/php/io.php @@ -20,6 +20,7 @@ * == END LICENSE == * * This is the File Manager Connector for PHP. + */ function CombinePaths( $sBasePath, $sFolder ) { @@ -126,6 +127,7 @@ function CreateServerFolder( $folderPath, $lastFolder = null ) else { $permissions = 0777 ; + // $permissions = 0770 ; if ( isset( $Config['ChmodOnFolderCreate'] ) ) { $permissions = $Config['ChmodOnFolderCreate'] ; @@ -149,7 +151,10 @@ function CreateServerFolder( $folderPath, $lastFolder = null ) $to_group_id = $group_properties['id']; } - $folder_path = substr($folderPath, strpos($folderPath, $repository_path) + strlen($repository_path) - 1); + $folder_path=preg_replace("/^.*".TOOL_DOCUMENT."/", "", $folderPath); // + $folder_path=preg_replace("/\/$/", "", $folder_path); // should be done in 1 regexp I guess ... + // $folder_path = substr($folderPath, strpos($folderPath, $repository_path) + strlen($repository_path) - 1); + $folder_name = explode('/', $folder_path); $folder_name = $folder_name[count($folder_name) - 1]; $doc_id = add_document($_course, $folder_path, 'folder', 0, $folder_name); diff --git a/main/inc/lib/fckeditor/editor/plugins/ImageManager/images.php b/main/inc/lib/fckeditor/editor/plugins/ImageManager/images.php old mode 100755 new mode 100644 index abecd2dc31..8358dfb5f6 --- a/main/inc/lib/fckeditor/editor/plugins/ImageManager/images.php +++ b/main/inc/lib/fckeditor/editor/plugins/ImageManager/images.php @@ -50,11 +50,24 @@ function drawFiles($list, &$manager) { global $relative; global $IMConfig; - + // add filename with course code in it + // here filename is images/gallery/COMES.jpg + // it should be /chamilo1884url/courses/COURSTESTSIMSUURLAPP/document/ + + global $_configuration; // + + //var topDoc = window.top.document; + foreach($list as $entry => $file) - { ?> + { + $chamiloPath = '/'.$_configuration['url_append'].'/courses/'.api_get_course_path().'/document'.$file['relative']; // + // + ?>
'; $return .= ''; $return .= ''; - $return .= ''; - // It said these lines of code - see SVN#11724 and SVN#10770 - //$return .= ''; - //$return .= ''; - //$return .= ''; - //$return .= ''; + $return .= ''; $return .= ''; $return .= ''; $return .= ''; @@ -7747,22 +7742,26 @@ class learnpath { $session_id = api_get_session_id(); $condition_session = api_get_session_condition($session_id); - $sql_link = "SELECT * FROM $tbl_link WHERE c_id = ".$course_id." $condition_session ORDER BY title ASC"; - $res_link = Database::query($sql_link); + $sql_link = "SELECT id, title FROM $tbl_link WHERE c_id = ".$course_id." $condition_session ORDER BY title ASC"; + $res_link = Database::query($sql_link); $return = '
'; $return .= '
'; $return .= ''; $return .= '' . get_lang('LinkAdd') . ''; $return .= '
'; - + $course_info = api_get_course_info(); + while ($row_link = Database :: fetch_array($res_link)) { - $return .= '
'; - $return .= ''; - $return .= ''. - $row_link['title']. - ''; - $return .= '
'; + $item_visibility = api_get_item_visibility($course_info, TOOL_LINK, $row_link['id'], $session_id); + if ($item_visibility != 2) { + $return .= '
'; + $return .= ''; + $return .= ''. + $row_link['title']. + ''; + $return .= '
'; + } } $return .= '
'; return $return; diff --git a/main/newscorm/lp_add_item.php b/main/newscorm/lp_add_item.php index 532af6eea2..e9bfee0fce 100644 --- a/main/newscorm/lp_add_item.php +++ b/main/newscorm/lp_add_item.php @@ -271,7 +271,7 @@ if ($action == 'add_item' && $type == 'document' && !isset($_GET['file'])) { echo '
'; - if (isset($new_item_id) && is_numeric($new_item_id)) { + if (isset($new_item_id) && is_numeric($new_item_id)) { switch ($type) { case 'chapter': echo $_SESSION['oLP']->display_manipulate($new_item_id, $_POST['type']); From 3f4d0a0b081f9d43a7e0cbcab4469d6f7f6fb0c2 Mon Sep 17 00:00:00 2001 From: Hubert Borderiou Date: Fri, 4 May 2012 14:51:03 +0200 Subject: [PATCH 028/128] Add plugin : loggin button for Shibboleth authentification. --- plugin/add_shibboleth_login_button/css.css | 12 ++++++ plugin/add_shibboleth_login_button/index.php | 21 +++++++++ plugin/add_shibboleth_login_button/plugin.php | 43 +++++++++++++++++++ plugin/add_shibboleth_login_button/readme.txt | 6 +++ .../add_shibboleth_login_button/template.tpl | 15 +++++++ 5 files changed, 97 insertions(+) create mode 100644 plugin/add_shibboleth_login_button/css.css create mode 100644 plugin/add_shibboleth_login_button/index.php create mode 100644 plugin/add_shibboleth_login_button/plugin.php create mode 100644 plugin/add_shibboleth_login_button/readme.txt create mode 100644 plugin/add_shibboleth_login_button/template.tpl diff --git a/plugin/add_shibboleth_login_button/css.css b/plugin/add_shibboleth_login_button/css.css new file mode 100644 index 0000000000..e16f03c6ab --- /dev/null +++ b/plugin/add_shibboleth_login_button/css.css @@ -0,0 +1,12 @@ + .shibboleth_plugin_image { + float:left; + height:50px; + margin: 0px 5px 5px 0px; + } + .shibboleth_plugin_comm { + font-style:italic; + } + .shibboleth_plugin_clear { + clear:both; + height:1px; + } diff --git a/plugin/add_shibboleth_login_button/index.php b/plugin/add_shibboleth_login_button/index.php new file mode 100644 index 0000000000..3c627b268d --- /dev/null +++ b/plugin/add_shibboleth_login_button/index.php @@ -0,0 +1,21 @@ +Plugins) + * @package chamilo.plugin + * @author Julio Montoya + */ +/** + * Plugin details (must be present) + */ + + + +//the plugin title +$plugin_info['title'] = 'Add a button to login using Shibboleth'; + +//the comments that go with the plugin +$plugin_info['comment'] = "If Shibboleth is configured, this plugin add a text and a button on the login page to login with Shibboleth. Configure plugin to add title, comment and logo."; +//the plugin version +$plugin_info['version'] = '1.0'; +//the plugin author +$plugin_info['author'] = 'Hubert Borderiou'; + +//the plugin configuration +$form = new FormValidator('add_shibboleth_button_form'); +$form->addElement('text', 'shibboleth_button_label', 'shibboleth connexion title', ''); +$form->addElement('text', 'shibboleth_button_comment', 'shibboleth connexion description', ''); +$form->addElement('text', 'shibboleth_image_url', 'Logo URL if any (image, 50px height)'); +$form->addElement('style_submit_button', 'submit_button', get_lang('Save')); +//get default value for form +$tab_default_add_shibboleth_login_button_shibboleth_button_label = api_get_setting('add_shibboleth_login_button_shibboleth_button_label'); +$tab_default_add_shibboleth_login_button_shibboleth_button_comment = api_get_setting('add_shibboleth_login_button_shibboleth_button_comment'); +$tab_default_add_shibboleth_login_button_shibboleth_image_url = api_get_setting('add_shibboleth_login_button_shibboleth_image_url'); +$defaults = array(); +$defaults['shibboleth_button_label'] = $tab_default_add_shibboleth_login_button_shibboleth_button_label['add_shibboleth_login_button']; +$defaults['shibboleth_button_comment'] = $tab_default_add_shibboleth_login_button_shibboleth_button_comment['add_shibboleth_login_button']; +$defaults['shibboleth_image_url'] = $tab_default_add_shibboleth_login_button_shibboleth_image_url['add_shibboleth_login_button']; +$form->setDefaults($defaults); +//display form +$plugin_info['settings_form'] = $form; + +//set the templates that are going to be used +$plugin_info['templates'] = array('template.tpl'); diff --git a/plugin/add_shibboleth_login_button/readme.txt b/plugin/add_shibboleth_login_button/readme.txt new file mode 100644 index 0000000000..629363d5c5 --- /dev/null +++ b/plugin/add_shibboleth_login_button/readme.txt @@ -0,0 +1,6 @@ +README +

+This plugin add a button to allow user to login to Chamilo with Shibboleth authentification.

+You have to configure your Shibboleth connexion before use this plugin.
+To activate and configure Shibboleth, for your Chamilo platform, go to Administration > Configuration settings > Shibboleth
+This plugin has been done to be added in the login_top region, but you can put it where you want.
\ No newline at end of file diff --git a/plugin/add_shibboleth_login_button/template.tpl b/plugin/add_shibboleth_login_button/template.tpl new file mode 100644 index 0000000000..6a2764bad1 --- /dev/null +++ b/plugin/add_shibboleth_login_button/template.tpl @@ -0,0 +1,15 @@ + +{% if add_shibboleth_login_button.show_message %} + +
+ {% if add_shibboleth_login_button.url_label %} + + {% endif %} +

{{add_shibboleth_login_button.button_label}}

+ {% if add_shibboleth_login_button.url_label %} +
 
+ {% endif %} +
{{add_shibboleth_login_button.comm_label}}
+ +
+{% endif %} From 013bacae1dc879ef229b4c4c0ce4b563b2eaec12 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Fri, 4 May 2012 15:57:17 +0200 Subject: [PATCH 029/128] Cleaning/fixing lp_view page when rendering LP in a 1024px screen laos adding default values to the lp TOC --- main/css/academica/default.css | 10 +- main/css/academica/scorm.css | 2 - main/css/baby_orange/default.css | 12 +- main/css/baby_orange/scorm.css | 4 +- main/css/base.css | 176 ++++++++++++++++++++++- main/css/base_chamilo.css | 54 ------- main/css/blue_lagoon/default.css | 10 +- main/css/blue_lagoon/scorm.css | 8 +- main/css/chamilo/default.css | 2 +- main/css/chamilo/scorm.css | 38 ++--- main/css/chamilo_electric_blue/scorm.css | 6 +- main/css/chamilo_green/scorm.css | 6 +- main/css/chamilo_orange/scorm.css | 5 +- main/css/chamilo_red/scorm.css | 3 - main/css/chamilo_sport_red/scorm.css | 11 +- main/css/cool_blue/default.css | 10 +- main/css/cool_blue/scorm.css | 6 +- main/css/corporate/default.css | 10 +- main/css/corporate/scorm.css | 4 +- main/css/cosmic_campus/default.css | 10 +- main/css/cosmic_campus/scorm.css | 4 +- main/css/delicious_bordeaux/default.css | 12 +- main/css/delicious_bordeaux/scorm.css | 10 +- main/css/dokeos_blue/default.css | 10 +- main/css/dokeos_blue/scorm.css | 6 +- main/css/dokeos_classic/default.css | 14 +- main/css/dokeos_classic/scorm.css | 5 +- main/css/dokeos_classic_2D/default.css | 12 +- main/css/dokeos_classic_2D/scorm.css | 4 +- main/css/empire_green/default.css | 10 +- main/css/empire_green/scorm.css | 10 +- main/css/fruity_orange/default.css | 10 +- main/css/fruity_orange/scorm.css | 6 +- main/css/medical/default.css | 6 +- main/css/medical/scorm.css | 2 - main/css/public_admin/default.css | 10 +- main/css/public_admin/scorm.css | 4 - main/css/royal_purple/default.css | 10 +- main/css/royal_purple/scorm.css | 6 +- main/css/silver_line/default.css | 11 +- main/css/silver_line/scorm.css | 4 +- main/css/sober_brown/default.css | 12 +- main/css/sober_brown/scorm.css | 4 +- main/css/tasty_olive/default.css | 10 +- main/css/tasty_olive/scorm.css | 6 +- main/newscorm/learnpath.class.php | 2 +- main/newscorm/lp_view.php | 176 +++++++++++------------ 47 files changed, 308 insertions(+), 455 deletions(-) mode change 100755 => 100644 main/css/academica/scorm.css mode change 100755 => 100644 main/css/baby_orange/scorm.css mode change 100755 => 100644 main/css/blue_lagoon/scorm.css mode change 100755 => 100644 main/css/chamilo_electric_blue/scorm.css mode change 100755 => 100644 main/css/chamilo_green/scorm.css mode change 100755 => 100644 main/css/chamilo_orange/scorm.css mode change 100755 => 100644 main/css/chamilo_red/scorm.css mode change 100755 => 100644 main/css/cool_blue/scorm.css mode change 100755 => 100644 main/css/corporate/scorm.css mode change 100755 => 100644 main/css/cosmic_campus/scorm.css mode change 100755 => 100644 main/css/delicious_bordeaux/scorm.css mode change 100755 => 100644 main/css/dokeos_blue/scorm.css mode change 100755 => 100644 main/css/dokeos_classic/scorm.css mode change 100755 => 100644 main/css/dokeos_classic_2D/scorm.css mode change 100755 => 100644 main/css/empire_green/scorm.css mode change 100755 => 100644 main/css/fruity_orange/scorm.css mode change 100755 => 100644 main/css/medical/scorm.css mode change 100755 => 100644 main/css/public_admin/scorm.css mode change 100755 => 100644 main/css/royal_purple/scorm.css mode change 100755 => 100644 main/css/silver_line/scorm.css mode change 100755 => 100644 main/css/sober_brown/scorm.css mode change 100755 => 100644 main/css/tasty_olive/scorm.css diff --git a/main/css/academica/default.css b/main/css/academica/default.css index 67452119d6..73d2c8822f 100644 --- a/main/css/academica/default.css +++ b/main/css/academica/default.css @@ -326,19 +326,11 @@ form span.form_error { background:#F8F8F8; border-bottom:1px solid #4171b5; border-top:1px solid #4171b5; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/academica/scorm.css b/main/css/academica/scorm.css old mode 100755 new mode 100644 index a799035fe6..708a02880d --- a/main/css/academica/scorm.css +++ b/main/css/academica/scorm.css @@ -20,8 +20,6 @@ overflow: auto; background-color: white; height: 210px; - width: 94%; - border-left: 10px #FFF solid; } .inner_lp_toc .scorm_item { font-size: 11px; diff --git a/main/css/baby_orange/default.css b/main/css/baby_orange/default.css index 824960963b..72be7a145e 100644 --- a/main/css/baby_orange/default.css +++ b/main/css/baby_orange/default.css @@ -306,20 +306,12 @@ form span.form_error { background-color:#FDDEAA; border-bottom:1px solid #EE4C03; border-top:1px solid #EE4C03; - height:29px; - padding-left: -17px; - margin-bottom: 1px; - vertical-align:middle; - width: 90%; - margin-left:17px; + height:29px; + margin-bottom: 1px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/baby_orange/scorm.css b/main/css/baby_orange/scorm.css old mode 100755 new mode 100644 index 6fc1299652..1d02f56b4d --- a/main/css/baby_orange/scorm.css +++ b/main/css/baby_orange/scorm.css @@ -19,9 +19,7 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 96%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; diff --git a/main/css/base.css b/main/css/base.css index 956c53fad5..50503dee9d 100644 --- a/main/css/base.css +++ b/main/css/base.css @@ -3457,12 +3457,12 @@ a.forum_group_link { /* actions */ .actions_lp { - background:#F8F8F8; - height: 40px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + background:#F8F8F8; + margin: 0px; + padding:9px 0px 9px 0px; + width:100%; + text-align: center; + } .actions_lp .btn-group { margin-left: 25px; @@ -3644,7 +3644,169 @@ footer { background-image: -webkit-linear-gradient(top, #F5F5F5 0%, #EEEEEE 100%); /* Chrome 10+,Safari 5.1+ */ background-image: -ms-linear-gradient(top, #F5F5F5 0%,#EEEEEE 100%); /* IE10+ */ background-image: -o-linear-gradient(top, #F5F5F5 0%,#EEEEEE 100%); /* Opera 11.10+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F5F5F5', endColorstr='#EEEEEE',GradientType=0 ); /* IE6-9 */ + /* Fixes bug in ie8 */ + /* filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F5F5F5', endColorstr='#EEEEEE',GradientType=0 ); */ /* IE6-9 */ background-image: linear-gradient(top, #F5F5F5 0%, #EEEEEE 100%); /* W3C */ } + + +/* Default LP left column values */ + +#learning_path_left_zone { + float:left; + width:280px; + height:100%; + padding-left: 8px; + padding-right: 4px; +} + +#learning_path_left_zone #header { + font-size:14px; +} + +#author_icon { + float:left; +} + +#lp_navigation_elem { + float:left; +} + +#author_image { + border: 1px solid #CCCCCC; + float: left; + margin: 0; + padding: 8px; + position: relative; + width: 94%; +} +#author_name { + float: left; + text-align:center; + width: 100%; + font-size: 11px; + color: #888; + margin-top: 2px; +} + +#learning_path_toc { + font-size:9pt; + margin:0; +} + +#scorm_title { + background: none repeat scroll 0 0 #EEEEEE; + color: #444444; + font-size: 16px; + font-weight: bold; + padding: 1px 5px 3px 8px; +} + +.progresstext { + text-align: center; +} + +.inner_lp_toc { + overflow: auto; + background-color: white; + height: 210px; +} + +.inner_lp_toc .scorm_item a { + font-weight: bold; + font-size: 14px; + margin-right: 1px; + padding-bottom: 2px; + text-decoration: none; + color: #2F3E46; +} + +.inner_lp_toc .scorm_item a.chapter_module { + font-weight: normal; + margin-right: 10px; +} +.inner_lp_toc .scorm_item_highlight { + border: 1px solid #999; + background:#999; + font-weight:bold; + text-shadow:0 -1px 1px #666; + background-image:-webkit-gradient(linear,left top,left bottom,from(#666),to(#999)); + background-image:-webkit-linear-gradient(top,#666,#999); + background-image:-moz-linear-gradient(top,#666,#999); + background-image:-ms-linear-gradient(top,#666,#999); + background-image:-o-linear-gradient(top,#666,#999); + background-image:linear-gradient(top,#666,#999); + margin-right: 0px; + padding: 10px 0px 10px 0px; + text-decoration: none; +} + +.inner_lp_toc .scorm_item_highlight a { + color:#fff; + margin-right: 1px; + text-decoration: none; + font-weight: bold; +} + +.inner_lp_toc .scorm_item_section { + border:1px solid #222; + background:#333; + font-weight:bold; + color:#fff; + text-shadow:0 -1px 1px #000; + background-image:-webkit-gradient(linear,left top,left bottom,from(#555),to(#333)); + background-image:-webkit-linear-gradient(top,#555,#333); + background-image:-moz-linear-gradient(top,#555,#333); + background-image:-ms-linear-gradient(top,#555,#333); + background-image:-o-linear-gradient(top,#555,#333); + background-image:linear-gradient(top,#555,#333); + margin-right: 1px; + padding: 10px 0px 10px 0px; + text-decoration: none; + +} + +.inner_lp_toc .scorm_item { + font-size: 16px; + margin-left: 10px; + margin-right:10px; + text-decoration: none; + border-color: rgba(255, 255, 255, 0.3); +} + +.inner_lp_toc .scorm_item_1 { + border-bottom: 1px solid #CCCCCC; + background:#eee; + font-weight:bold; + color:#444; + text-shadow:0 1px 1px #f6f6f6; + background-image:-webkit-gradient(linear,left top,left bottom,from(#fdfdfd),to(#eee)); + background-image:-webkit-linear-gradient(top,#fdfdfd,#eee); + background-image:-moz-linear-gradient(top,#fdfdfd,#eee); + background-image:-ms-linear-gradient(top,#fdfdfd,#eee); + background-image:-o-linear-gradient(top,#fdfdfd,#eee); + background-image:linear-gradient(top,#fdfdfd,#eee); + margin-right: 1px; + padding: 10px 0px 10px 0px; + text-decoration: none; + font-weight: normal; + /* background:#FDFDFD; */ +} + +.inner_lp_toc .scorm_item_2 { + background-image:-webkit-gradient(linear,left top,left bottom,from(#fdfdfd),to(#eee)); + background-image:-webkit-linear-gradient(top,#fdfdfd,#eee); + background-image:-moz-linear-gradient(top,#fdfdfd,#eee); + background-image:-ms-linear-gradient(top,#fdfdfd,#eee); + background-image:-o-linear-gradient(top,#fdfdfd,#eee); + background-image:linear-gradient(top,#fdfdfd,#eee); + border-bottom: 1px solid #CCCCCC; + color: #444444; + font-weight: bold; + text-shadow: 0 1px 1px #F6F6F6; + margin-right: 1px; + padding: 10px 0px 10px 0px; + text-decoration: none; + font-weight: normal; +} \ No newline at end of file diff --git a/main/css/base_chamilo.css b/main/css/base_chamilo.css index 55835ca795..7ca00621af 100755 --- a/main/css/base_chamilo.css +++ b/main/css/base_chamilo.css @@ -186,56 +186,6 @@ a.invisible:link, a.invisible:visited { line-height: 0px; height: 0; } -input.link_alike { - background-color: #FFFFFF; - border-width: 0px; - color: #4171b5; - font-weight: bold; - text-align: left; - padding: 0px; - margin: 0px; - -moz-border-radius-bottomleft:5px; - -moz-border-radius-bottomright:5px; - -moz-border-radius-topleft:5px; - -moz-border-radius-topright:5px; - border:1px solid #E1E1E0; -} -input.link_alike:hover { - background-color: #FFFFFF; - border-width: 0px; - color: #f3840d; - font-weight: bold; - text-align: left; - padding: 0px; - margin: 0px; - -moz-border-radius-bottomleft:5px; - -moz-border-radius-bottomright:5px; - -moz-border-radius-topleft:5px; - -moz-border-radius-topright:5px; - border:1px solid #E1E1E0; -} - - - -/***************************************************** - * HEADER STYLES * - *****************************************************/ -#header { - -} -/******************************************************** - * HEADER 1: Title, portal, organisation, course title * - ********************************************************/ - -#header1 a { - font-size:12px; - font-weight:normal; - color: #666666; - text-decoration: none; -} -#header1 a:hover { - text-decoration: underline; -} #sitename { margin: 0; } @@ -1809,10 +1759,6 @@ span.form_required { cursor: pointer; } -.progresstext { - text-align:center; -} - /* tips Abbr-plugin for FCKeditor */ abbr { border-bottom: 1px dotted rgb(102, 102, 102); diff --git a/main/css/blue_lagoon/default.css b/main/css/blue_lagoon/default.css index d19e4b8b43..bd182afc00 100644 --- a/main/css/blue_lagoon/default.css +++ b/main/css/blue_lagoon/default.css @@ -2055,19 +2055,11 @@ div.comments { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/blue_lagoon/scorm.css b/main/css/blue_lagoon/scorm.css old mode 100755 new mode 100644 index 10b7d69313..39c8711465 --- a/main/css/blue_lagoon/scorm.css +++ b/main/css/blue_lagoon/scorm.css @@ -19,16 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; - margin-right:10px; - //it was 20px padding-bottom: 2px; - text-decoration: none; + margin-right:10px; } .inner_lp_toc .scorm_item A { font-size: 11px; diff --git a/main/css/chamilo/default.css b/main/css/chamilo/default.css index d2d67973b0..da7441596d 100644 --- a/main/css/chamilo/default.css +++ b/main/css/chamilo/default.css @@ -60,7 +60,7 @@ a:active { /***************************************************** * FOOTER STYLES * *****************************************************/ -footer { +footer { background-color: #037fb2; background-image: url(images/bg-footer.gif); background-repeat:repeat-x; diff --git a/main/css/chamilo/scorm.css b/main/css/chamilo/scorm.css index 7a14d8f0e4..19c66edc0c 100644 --- a/main/css/chamilo/scorm.css +++ b/main/css/chamilo/scorm.css @@ -16,25 +16,23 @@ width: 99%; border-right: 1px none; } + .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 5px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item a { font-weight: bold; -/* text-shadow: 0 1px 1px #F6F6F6; */ - font-size: 14px; margin-right: 1px; padding-bottom: 2px; text-decoration: none; - font-family: Helvetica,Arial,sans-serif; - color: #2F3E46; + font-family: Helvetica,Arial,sans-serif; + color: #2F3E46; } + .inner_lp_toc .scorm_item a.chapter_module { font-weight: normal; margin-right: 10px; @@ -50,12 +48,12 @@ background-image:-moz-linear-gradient(top,#72b0d4,#4b88b6); background-image:-ms-linear-gradient(top,#72b0d4,#4b88b6); background-image:-o-linear-gradient(top,#72b0d4,#4b88b6); - background-image:linear-gradient(top,#72b0d4,#4b88b6) - - margin-right: 1px; + background-image:linear-gradient(top,#72b0d4,#4b88b6); + margin-right: 0px; padding: 10px 0px 10px 0px; text-decoration: none; } + .inner_lp_toc .scorm_item_highlight a { color:#fff; margin-right: 1px; @@ -76,7 +74,7 @@ background-image:-o-linear-gradient(top,#555,#333); background-image:linear-gradient(top,#555,#333); - margin-right: 1px; + margin-right: 1px; padding: 10px 0px 10px 0px; text-decoration: none; @@ -110,27 +108,23 @@ /* background:#FDFDFD; */ } -.inner_lp_toc .scorm_item_2 { - +.inner_lp_toc .scorm_item_2 { background-image:-webkit-gradient(linear,left top,left bottom,from(#fdfdfd),to(#eee)); background-image:-webkit-linear-gradient(top,#fdfdfd,#eee); background-image:-moz-linear-gradient(top,#fdfdfd,#eee); background-image:-ms-linear-gradient(top,#fdfdfd,#eee); background-image:-o-linear-gradient(top,#fdfdfd,#eee); - background-image:linear-gradient(top,#fdfdfd,#eee); - + background-image:linear-gradient(top,#fdfdfd,#eee); border-bottom: 1px solid #CCCCCC; color: #444444; font-weight: bold; text-shadow: 0 1px 1px #F6F6F6; - - margin-right: 1px; padding: 10px 0px 10px 0px; text-decoration: none; font-weight: normal; - } + .inner_lp_toc .scorm_title { font-weight: bold; background:#ccc; @@ -164,8 +158,6 @@ /*.scormpage .menu */ .lp_navigation_elem .progresstext { margin-top: -20px; -// margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { @@ -206,12 +198,6 @@ #image_preview { padding-left: 17px; } -#author_name { - padding-left: 5px; - padding-top: 5px; - font-size: 11px; - color:#888; -} #msg_div_id { padding-left: 17px; padding-top: 4px; diff --git a/main/css/chamilo_electric_blue/scorm.css b/main/css/chamilo_electric_blue/scorm.css old mode 100755 new mode 100644 index bc83ef12fa..cd0532696e --- a/main/css/chamilo_electric_blue/scorm.css +++ b/main/css/chamilo_electric_blue/scorm.css @@ -19,16 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; - text-decoration: none; } .inner_lp_toc .scorm_item A { font-size: 11px; diff --git a/main/css/chamilo_green/scorm.css b/main/css/chamilo_green/scorm.css old mode 100755 new mode 100644 index bc83ef12fa..cd0532696e --- a/main/css/chamilo_green/scorm.css +++ b/main/css/chamilo_green/scorm.css @@ -19,16 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; - text-decoration: none; } .inner_lp_toc .scorm_item A { font-size: 11px; diff --git a/main/css/chamilo_orange/scorm.css b/main/css/chamilo_orange/scorm.css old mode 100755 new mode 100644 index bc83ef12fa..9e712a1fc6 --- a/main/css/chamilo_orange/scorm.css +++ b/main/css/chamilo_orange/scorm.css @@ -19,15 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { diff --git a/main/css/chamilo_red/scorm.css b/main/css/chamilo_red/scorm.css old mode 100755 new mode 100644 index bc83ef12fa..0c659c870f --- a/main/css/chamilo_red/scorm.css +++ b/main/css/chamilo_red/scorm.css @@ -20,14 +20,11 @@ overflow: auto; background-color: white; height: 210px; - width: 94%; - border-left: 10px #FFF solid; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { diff --git a/main/css/chamilo_sport_red/scorm.css b/main/css/chamilo_sport_red/scorm.css index bc83ef12fa..e48d334e14 100755 --- a/main/css/chamilo_sport_red/scorm.css +++ b/main/css/chamilo_sport_red/scorm.css @@ -19,15 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { @@ -79,8 +76,6 @@ } .inner_lp_toc .scorm_title_text { margin-left: 10px; - //padding: 2px; - //cambiado no existe } .inner_lp_toc .scorm_status_img { margin:0px; @@ -105,9 +100,7 @@ } /*.scormpage .menu */ .lp_navigation_elem .progresstext { - margin-top: -20px; - //margin-left: 40%; -//em font-size: normal; + margin-top: -20px; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/css/cool_blue/default.css b/main/css/cool_blue/default.css index 4a25dba9af..751e135746 100644 --- a/main/css/cool_blue/default.css +++ b/main/css/cool_blue/default.css @@ -2003,19 +2003,11 @@ div.comments { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/cool_blue/scorm.css b/main/css/cool_blue/scorm.css old mode 100755 new mode 100644 index c78ee47abe..3aba483045 --- a/main/css/cool_blue/scorm.css +++ b/main/css/cool_blue/scorm.css @@ -19,15 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { @@ -107,7 +104,6 @@ .lp_navigation_elem .progresstext { margin-top: -20px; margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/css/corporate/default.css b/main/css/corporate/default.css index 419dc84fa8..c6fe67deac 100644 --- a/main/css/corporate/default.css +++ b/main/css/corporate/default.css @@ -415,19 +415,11 @@ ul#navigation .help a{ /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/corporate/scorm.css b/main/css/corporate/scorm.css old mode 100755 new mode 100644 index 5a47887900..68672d9597 --- a/main/css/corporate/scorm.css +++ b/main/css/corporate/scorm.css @@ -19,9 +19,7 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; diff --git a/main/css/cosmic_campus/default.css b/main/css/cosmic_campus/default.css index db9a0e8a05..38da7d1ed1 100644 --- a/main/css/cosmic_campus/default.css +++ b/main/css/cosmic_campus/default.css @@ -352,19 +352,11 @@ form span.form_error { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/cosmic_campus/scorm.css b/main/css/cosmic_campus/scorm.css old mode 100755 new mode 100644 index a799035fe6..a769f687c1 --- a/main/css/cosmic_campus/scorm.css +++ b/main/css/cosmic_campus/scorm.css @@ -19,9 +19,7 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; diff --git a/main/css/delicious_bordeaux/default.css b/main/css/delicious_bordeaux/default.css index 0f862378be..672546ce07 100644 --- a/main/css/delicious_bordeaux/default.css +++ b/main/css/delicious_bordeaux/default.css @@ -16,8 +16,6 @@ body { background-color: #fff; height: 100%; /* stick */ } - - /* ----------------------------------------------------------------------------- Side-Menu Slider (JQuery) see banner.inc.php @@ -2017,19 +2015,11 @@ div.comments { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/delicious_bordeaux/scorm.css b/main/css/delicious_bordeaux/scorm.css old mode 100755 new mode 100644 index c78ee47abe..8874da901f --- a/main/css/delicious_bordeaux/scorm.css +++ b/main/css/delicious_bordeaux/scorm.css @@ -19,15 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { @@ -78,9 +75,7 @@ color: #444; } .inner_lp_toc .scorm_title_text { - margin-left: 10px; - //padding: 2px; - //cambiado no existe + margin-left: 10px; } .inner_lp_toc .scorm_status_img { margin:0px; @@ -107,7 +102,6 @@ .lp_navigation_elem .progresstext { margin-top: -20px; margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/css/dokeos_blue/default.css b/main/css/dokeos_blue/default.css index 2e2aebc7ee..eb93ff8d96 100644 --- a/main/css/dokeos_blue/default.css +++ b/main/css/dokeos_blue/default.css @@ -2025,19 +2025,11 @@ div.comments { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/dokeos_blue/scorm.css b/main/css/dokeos_blue/scorm.css old mode 100755 new mode 100644 index c78ee47abe..3aba483045 --- a/main/css/dokeos_blue/scorm.css +++ b/main/css/dokeos_blue/scorm.css @@ -19,15 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { @@ -107,7 +104,6 @@ .lp_navigation_elem .progresstext { margin-top: -20px; margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/css/dokeos_classic/default.css b/main/css/dokeos_classic/default.css index d4378d7357..c9a05f07ef 100644 --- a/main/css/dokeos_classic/default.css +++ b/main/css/dokeos_classic/default.css @@ -1897,22 +1897,12 @@ padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;} } /* actions */ .actions_lp { - background:#F8F8F8; - //border-bottom:1px solid #999999; - //border-top:1px solid #999999; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + background:#F8F8F8; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/dokeos_classic/scorm.css b/main/css/dokeos_classic/scorm.css old mode 100755 new mode 100644 index 6a13b420a4..38f6e722a0 --- a/main/css/dokeos_classic/scorm.css +++ b/main/css/dokeos_classic/scorm.css @@ -19,9 +19,7 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; @@ -105,7 +103,6 @@ .lp_navigation_elem .progresstext { margin-top: -20px; margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/css/dokeos_classic_2D/default.css b/main/css/dokeos_classic_2D/default.css index fddbce825e..15dfcb1372 100644 --- a/main/css/dokeos_classic_2D/default.css +++ b/main/css/dokeos_classic_2D/default.css @@ -2017,21 +2017,11 @@ input.forms { /* actions */ .actions_lp { background:#F8F8F8; - /*border-bottom:1px solid #999999; */ - /*border-top:1px solid #999999; */ - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/dokeos_classic_2D/scorm.css b/main/css/dokeos_classic_2D/scorm.css old mode 100755 new mode 100644 index 3ec13858a9..9d87d93837 --- a/main/css/dokeos_classic_2D/scorm.css +++ b/main/css/dokeos_classic_2D/scorm.css @@ -19,9 +19,7 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; diff --git a/main/css/empire_green/default.css b/main/css/empire_green/default.css index ba4de8be02..8574ab3b86 100644 --- a/main/css/empire_green/default.css +++ b/main/css/empire_green/default.css @@ -2013,19 +2013,11 @@ div.comments { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/empire_green/scorm.css b/main/css/empire_green/scorm.css old mode 100755 new mode 100644 index c78ee47abe..5835abd67d --- a/main/css/empire_green/scorm.css +++ b/main/css/empire_green/scorm.css @@ -19,15 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { @@ -79,9 +76,7 @@ } .inner_lp_toc .scorm_title_text { margin-left: 10px; - //padding: 2px; - //cambiado no existe -} + } .inner_lp_toc .scorm_status_img { margin:0px; margin-left: -10px; @@ -107,7 +102,6 @@ .lp_navigation_elem .progresstext { margin-top: -20px; margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/css/fruity_orange/default.css b/main/css/fruity_orange/default.css index 583720cd95..2d0c354563 100644 --- a/main/css/fruity_orange/default.css +++ b/main/css/fruity_orange/default.css @@ -2021,19 +2021,11 @@ div.comments { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/fruity_orange/scorm.css b/main/css/fruity_orange/scorm.css old mode 100755 new mode 100644 index c78ee47abe..3aba483045 --- a/main/css/fruity_orange/scorm.css +++ b/main/css/fruity_orange/scorm.css @@ -19,15 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { @@ -107,7 +104,6 @@ .lp_navigation_elem .progresstext { margin-top: -20px; margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/css/medical/default.css b/main/css/medical/default.css index eff2277d08..7d791fdf54 100644 --- a/main/css/medical/default.css +++ b/main/css/medical/default.css @@ -1970,11 +1970,7 @@ padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;} /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; diff --git a/main/css/medical/scorm.css b/main/css/medical/scorm.css old mode 100755 new mode 100644 index f01c6042b5..a18eeecf8f --- a/main/css/medical/scorm.css +++ b/main/css/medical/scorm.css @@ -20,8 +20,6 @@ overflow: auto; background-color: white; height: 210px; - width: 94%; - border-left: 10px #FFF solid; } .inner_lp_toc .scorm_item { font-size: 11px; diff --git a/main/css/public_admin/default.css b/main/css/public_admin/default.css index 6b3bb1b531..c420a5aa10 100644 --- a/main/css/public_admin/default.css +++ b/main/css/public_admin/default.css @@ -1746,19 +1746,11 @@ padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;} /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/public_admin/scorm.css b/main/css/public_admin/scorm.css old mode 100755 new mode 100644 index 5f3dd0147a..b89ba3f840 --- a/main/css/public_admin/scorm.css +++ b/main/css/public_admin/scorm.css @@ -20,14 +20,11 @@ overflow: auto; background-color: white; height: 210px; - width: 94%; - border-left: 10px #FFF solid; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { @@ -102,7 +99,6 @@ .lp_navigation_elem .progresstext { margin-top: -20px; margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/css/royal_purple/default.css b/main/css/royal_purple/default.css index fc6e355a38..a80b503b15 100644 --- a/main/css/royal_purple/default.css +++ b/main/css/royal_purple/default.css @@ -1973,19 +1973,11 @@ div.comments { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/royal_purple/scorm.css b/main/css/royal_purple/scorm.css old mode 100755 new mode 100644 index c78ee47abe..3aba483045 --- a/main/css/royal_purple/scorm.css +++ b/main/css/royal_purple/scorm.css @@ -19,15 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { @@ -107,7 +104,6 @@ .lp_navigation_elem .progresstext { margin-top: -20px; margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/css/silver_line/default.css b/main/css/silver_line/default.css index 7c1c8c7d2f..b9a571f915 100644 --- a/main/css/silver_line/default.css +++ b/main/css/silver_line/default.css @@ -1467,20 +1467,11 @@ div.system_announcement { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin-bottom: 1px; - vertical-align:middle; - width: 90%; - margin-left:17px; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/silver_line/scorm.css b/main/css/silver_line/scorm.css old mode 100755 new mode 100644 index 1a25ef629f..0defead0d1 --- a/main/css/silver_line/scorm.css +++ b/main/css/silver_line/scorm.css @@ -19,9 +19,7 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; diff --git a/main/css/sober_brown/default.css b/main/css/sober_brown/default.css index 6ee1cdc478..d49da6df44 100644 --- a/main/css/sober_brown/default.css +++ b/main/css/sober_brown/default.css @@ -1686,21 +1686,11 @@ padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;} /* actions */ .actions_lp { background:#F8F8F8; - //border-bottom:1px solid #999999; - //border-top:1px solid #999999; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/sober_brown/scorm.css b/main/css/sober_brown/scorm.css old mode 100755 new mode 100644 index 4286daab64..f83131426a --- a/main/css/sober_brown/scorm.css +++ b/main/css/sober_brown/scorm.css @@ -19,9 +19,7 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; diff --git a/main/css/tasty_olive/default.css b/main/css/tasty_olive/default.css index 1067eab73d..adba6bc627 100644 --- a/main/css/tasty_olive/default.css +++ b/main/css/tasty_olive/default.css @@ -1946,19 +1946,11 @@ div.comments { /* actions */ .actions_lp { background:#F8F8F8; - height:29px; - padding-left: -17px; - margin: 5px 2px 1px 12px; - vertical-align:middle; - width: 90%; + height:29px; } .actions_lp img { vertical-align:middle; } -.actions_lp a { - margin-right: 10px; - vertical-align:middle; -} .actions_lp span { margin-right: 10px; vertical-align:middle; diff --git a/main/css/tasty_olive/scorm.css b/main/css/tasty_olive/scorm.css old mode 100755 new mode 100644 index ed79935617..3aba483045 --- a/main/css/tasty_olive/scorm.css +++ b/main/css/tasty_olive/scorm.css @@ -19,15 +19,12 @@ .inner_lp_toc { overflow: auto; background-color: white; - height: 210px; - width: 94%; - border-left: 10px #FFF solid; + height: 210px; } .inner_lp_toc .scorm_item { font-size: 11px; margin-left: 10px; margin-right:10px; -//cambiado era 20 padding-bottom: 2px; text-decoration: none; } .inner_lp_toc .scorm_item A { @@ -107,7 +104,6 @@ .lp_navigation_elem .progresstext { margin-top: -20px; margin-left: 40%; -//em font-size: normal; } /*.scormpage .menu */ .lp_navigation_elem .buttons { diff --git a/main/newscorm/learnpath.class.php b/main/newscorm/learnpath.class.php index e66d8e3409..95cfdeccc8 100644 --- a/main/newscorm/learnpath.class.php +++ b/main/newscorm/learnpath.class.php @@ -2678,7 +2678,7 @@ class learnpath { //echo $this->current; //$parent = $this->items[$this->current]->get_parent(); //if (empty($parent)) { $parent = $this->ordered_items[$this->items[$this->current]->get_previous_index()]; } - $html = '
' . Security::remove_XSS($this->get_name()) . '
'; + $html = '
' . Security::remove_XSS($this->get_name()) . '
'; // Build, display. if ($is_allowed_to_edit) { $gradebook = Security :: remove_XSS($_GET['gradebook']); diff --git a/main/newscorm/lp_view.php b/main/newscorm/lp_view.php index a8a3ba8951..1548384a6b 100644 --- a/main/newscorm/lp_view.php +++ b/main/newscorm/lp_view.php @@ -313,109 +313,97 @@ if (Database::num_rows($res_media) > 0) { ?> -
+
-
+ + <?php echo $entry; ?> - <?php echo Files::formatSize($file['stat']['size']); ?>
Trash diff --git a/main/inc/lib/fckeditor/editor/plugins/MP3/fck_mp3.js b/main/inc/lib/fckeditor/editor/plugins/MP3/fck_mp3.js index f739e4c862..6c9028759c 100644 --- a/main/inc/lib/fckeditor/editor/plugins/MP3/fck_mp3.js +++ b/main/inc/lib/fckeditor/editor/plugins/MP3/fck_mp3.js @@ -47,7 +47,7 @@ if ( oFakeImage ) } function window_onload(tab_to_select) -{ +{ // Translate the dialog box texts. oEditor.FCKLanguageManager.TranslatePage(document) ; @@ -123,7 +123,6 @@ function LoadSelection() //#### The OK button was hit. function Ok() { - if ( GetE('mpUrl').value.length == 0 ) { window.parent.SetSelectedTab( 'Info' ) ; @@ -200,7 +199,8 @@ function updateMovie(e) } var ePreview ; -function SetPreviewElement( previewEl ) { +function SetPreviewElement( previewEl ) +{ ePreview = previewEl ; if ( GetE('mpUrl').value.length > 0 ) @@ -238,6 +238,11 @@ function BrowseServer() function SetUrl( url ) { + PrefixeUrl = self.location.href.replace(/\/main\/inc\/lib\/fckeditor\/editor\/plugins\/MP3\/fck_mp3.\html/, ""); + PrefixeUrl = PrefixeUrl.replace(/http:\/\/[^\/]+/, ""); + url = PrefixeUrl + url; + // + document.getElementById('mpUrl').value = url ; //updatePreview(); Ok(); diff --git a/main/inc/lib/fckeditor/editor/plugins/audio/fck_audio.js b/main/inc/lib/fckeditor/editor/plugins/audio/fck_audio.js index 6477f35acc..915c869afa 100644 --- a/main/inc/lib/fckeditor/editor/plugins/audio/fck_audio.js +++ b/main/inc/lib/fckeditor/editor/plugins/audio/fck_audio.js @@ -32,13 +32,13 @@ var FCKTools = oEditor.FCKTools ; window.document.dir = FCKLang.Dir ; // We have to avoid javascript errors if some language variables have not been defined. -FCKLang['UploadSelectFileFirst'] = FCKLang['UploadSelectFileFirst'] ? FCKLang['UploadSelectFileFirst'] : 'Please, select a file before pressing the upload button.' ; +FCKLang['UploadSelectFileFirst'] = FCKLang['UploadSelectFileFirst'] ? FCKLang['UploadSelectFileFirst'] : 'Please, select a file before pressing the upload button.' ; FCKLang['FileSuccessfullyUploaded'] = FCKLang['FileSuccessfullyUploaded'] ? FCKLang['FileSuccessfullyUploaded'] : 'Your file has been successfully uploaded.' ; -FCKLang['FileRenamed'] = FCKLang['FileRenamed'] ? FCKLang['FileRenamed'] : 'A file with the same name is already available. The uploaded file has been renamed to ' ; -FCKLang['InvalidFileType'] = FCKLang['InvalidFileType'] ? FCKLang['InvalidFileType'] : 'Invalid file type.' ; -FCKLang['SecurityError'] = FCKLang['SecurityError'] ? FCKLang['SecurityError'] : 'Security error. You probably don\'t have enough permissions to upload. Please check your server.' ; -FCKLang['ConnectorDisabled'] = FCKLang['ConnectorDisabled'] ? FCKLang['ConnectorDisabled'] : 'The upload feature (connector) is disabled.' ; -FCKLang['UploadError'] = FCKLang['UploadError'] ? FCKLang['UploadError'] : 'Error on file upload. Error number: ' ; +FCKLang['FileRenamed'] = FCKLang['FileRenamed'] ? FCKLang['FileRenamed'] : 'A file with the same name is already available. The uploaded file has been renamed to ' ; +FCKLang['InvalidFileType'] = FCKLang['InvalidFileType'] ? FCKLang['InvalidFileType'] : 'Invalid file type.' ; +FCKLang['SecurityError'] = FCKLang['SecurityError'] ? FCKLang['SecurityError'] : 'Security error. You probably don\'t have enough permissions to upload. Please check your server.' ; +FCKLang['ConnectorDisabled'] = FCKLang['ConnectorDisabled'] ? FCKLang['ConnectorDisabled'] : 'The upload feature (connector) is disabled.' ; +FCKLang['UploadError'] = FCKLang['UploadError'] ? FCKLang['UploadError'] : 'Error on file upload. Error number: ' ; //#### Dialog Tabs @@ -65,18 +65,21 @@ lib_path = FCK.GetUrl( lib_path, FCK.SEMI_ABSOLUTE_URL ) ; // This is the semi-absolute URL of the audio player. var player = lib_path + 'mediaplayer/player.swf' ; + // Get the selected audio (if available). var oFakeImage = dialog.Selection.GetSelectedElement() ; var oEmbed ; -if ( oFakeImage ) { +if ( oFakeImage ) +{ if ( oFakeImage.tagName == 'IMG' && oFakeImage.getAttribute('_fckmp3') ) oEmbed = FCK.GetRealElement( oFakeImage ) ; else oFakeImage = null ; } -window.onload = function() { +window.onload = function() +{ // Translate the dialog box texts. oEditor.FCKLanguageManager.TranslatePage(document) ; @@ -98,7 +101,8 @@ window.onload = function() { SelectField( 'txtUrl' ) ; } -function LoadSelection() { +function LoadSelection() +{ if ( ! oEmbed ) return ; var flashvars = GetAttribute( oEmbed, 'flashvars', '' ).toString() ; @@ -130,8 +134,8 @@ function LoadSelection() { } //#### The OK button was hit. -function Ok() { - +function Ok() +{ if ( GetE('txtUrl').value.length == 0 ) { dialog.SetSelectedTab( 'Info' ) ; @@ -177,13 +181,16 @@ function UpdateEmbed( e ) var ePreview ; -function SetPreviewElement( previewEl ) { +function SetPreviewElement( previewEl ) +{ ePreview = previewEl ; + if ( GetE( 'txtUrl' ).value.length > 0 ) UpdatePreview() ; } -function UpdatePreview() { +function UpdatePreview() +{ if ( !ePreview ) return; @@ -221,10 +228,21 @@ function BrowseServer() OpenFileBrowser( FCKConfig.MP3BrowserURL, FCKConfig.MP3BrowserWindowWidth, FCKConfig.MP3BrowserWindowHeight ) ; } -function SetUrl( url ) { +function SetUrl( url ) +{ + //url = FCK.GetSelectedUrl( url ) ; url = FCK.GetUrl( url, FCK.SEMI_ABSOLUTE_URL ) ; + + PrefixeUrl = self.location.href.replace(/\/main\/inc\/lib\/fckeditor\/editor\/plugins\/audio\/fck_audio.\html/, ""); + PrefixeUrl = PrefixeUrl.replace(/http:\/\/[^\/]+/, ""); + url = PrefixeUrl + url; + // + + GetE('txtUrl').value = url ; + UpdatePreview() ; + dialog.SetSelectedTab( 'Info' ) ; } diff --git a/main/inc/lib/fckeditor/editor/plugins/fckEmbedMovies/fck_embedmovies.js b/main/inc/lib/fckeditor/editor/plugins/fckEmbedMovies/fck_embedmovies.js index b3adacef35..00f8a64889 100644 --- a/main/inc/lib/fckeditor/editor/plugins/fckEmbedMovies/fck_embedmovies.js +++ b/main/inc/lib/fckeditor/editor/plugins/fckEmbedMovies/fck_embedmovies.js @@ -280,7 +280,11 @@ function BrowseServer() function SetUrl( url ) { url = FCK.GetSelectedUrl( url ) ; - + PrefixeUrl = self.location.href.replace(/\/main\/inc\/lib\/fckeditor\/editor\/plugins\/fckEmbedMovies\/fck_embedmovies.\html/, ""); + PrefixeUrl = PrefixeUrl.replace(/http:\/\/[^\/]+/, ""); + url = PrefixeUrl + url; + // + GetE( 'txtUrl' ).value = url ; dialog.SetSelectedTab( 'Info' ) ; diff --git a/main/inc/lib/fckeditor/editor/plugins/flvPlayer/flvPlayer.js b/main/inc/lib/fckeditor/editor/plugins/flvPlayer/flvPlayer.js index 7571525187..36de4027ea 100644 --- a/main/inc/lib/fckeditor/editor/plugins/flvPlayer/flvPlayer.js +++ b/main/inc/lib/fckeditor/editor/plugins/flvPlayer/flvPlayer.js @@ -365,6 +365,10 @@ var sActualBrowser ; function SetUrl( url ) { url = FCK.GetUrl( url, FCK.SEMI_ABSOLUTE_URL ) ; + PrefixeUrl = self.location.href.replace(/\/main\/inc\/lib\/fckeditor\/editor\/plugins\/flvPlayer\/flvPlayer\.html/, ""); + PrefixeUrl = PrefixeUrl.replace(/http:\/\/[^\/]+/, ""); + url = PrefixeUrl + url; + // if ( sActualBrowser == 'flv' ) { @@ -448,37 +452,44 @@ Media.prototype.setAttribute = function( attr, val ) } } ; -Media.prototype.getInnerHTML = function ( objectId ) { - +Media.prototype.getInnerHTML = function ( objectId ) +{ var embeddingMethod = FCKConfig[ 'FlashEmbeddingMethod' ]; + var randomnumber = Math.floor( Math.random() * 1000001 ) ; var thisWidth = this.width ; var thisHeight = this.height ; var thisMediaType = 'single' ; - if ( !GetE( 'rbFileType' ).checked ) { + if ( !GetE( 'rbFileType' ).checked ) + { thisMediaType = 'mpl' ; } // Alignment var cssalign = '' ; var cssfloat = '' ; - if ( this.align == 'center') { + if ( this.align == 'center' ) + { cssalign = 'margin-left: auto;margin-right: auto;' ; - } else if ( this.align == 'right' ) { + } + else if ( this.align == 'right' ) + { cssfloat = 'float: right;' ; - } else if ( this.align == 'left' ) { + } + else if ( this.align == 'left' ) + { cssfloat = 'float: left;' ; } - var s = ''; + var s = '' ; - s += '\n'; - + s += '\n' ; s += '
\n'; s += '
' ; - - if (embeddingMethod == 'swfobject') { + + if (embeddingMethod == 'swfobject') + { s += '\n' ; } @@ -486,26 +497,28 @@ Media.prototype.getInnerHTML = function ( objectId ) { // A hidden div containing setting, added width, height, overflow for MSIE7 s += '' ; + s += '
' ; // The player's area. s += '
' ; - if ( embeddingMethod == 'swfobject' ) { + if ( embeddingMethod == 'swfobject' ) + { s += 'Get the Flash Player to see this video.' ; + } - if (embeddingMethod == 'object' || embeddingMethod == 'adobe' ) { + if ( embeddingMethod == 'object' || embeddingMethod == 'adobe' ) + { var p = '' ; // Parameters. var v = '' ; // Variables. @@ -516,71 +529,105 @@ Media.prototype.getInnerHTML = function ( objectId ) { p += '' ; v += 'width=' + thisWidth + '&' ; - v += 'height=' + thisHeight + '&'; - v += 'autostart=' + this.play + '&'; + v += 'height=' + thisHeight + '&' ; + v += 'autostart=' + this.play + '&' ; - if ( thisMediaType == 'mpl' ) { - v += 'file=' + this.purl + '&'; - v += 'autoscroll=true&'; - p += 'allowscriptaccess="always" '; + if ( thisMediaType == 'mpl' ) + { + v += 'file=' + this.purl + '&' ; + v += 'autoscroll=true&' ; + p += 'allowscriptaccess="always" ' ; p += '' ; var dispWidth = thisWidth ; var dispHeight = thisHeight ; var dispThumbs = false ; - if ( this.dispPlaylist != 'none' ) { - if ( this.dispPlaylist == 'right' ) { - if ( this.playlistDim.length > 0 ) { + if ( this.dispPlaylist != 'none' ) + { + if ( this.dispPlaylist == 'right' ) + { + if ( this.playlistDim.length > 0 ) + { dispWidth = thisWidth - this.playlistDim ; - if ( this.playlistDim < 100 ) { + if ( this.playlistDim < 100 ) + { dispThumbs = false ; - } else { + } + else + { dispThumbs = true ; } - } else { - if ( thisWidth >= 550 ) { + } + else + { + if ( thisWidth >= 550 ) + { dispWidth = thisWidth - 200 ; dispThumbs = true ; - } else if ( thisWidth >= 450 ) { + } + else if ( thisWidth >= 450 ) + { dispWidth = thisWidth - 100 ; dispThumbs = false ; - } else if ( thisWidth >= 350 ) { + } + else if ( thisWidth >= 350 ) + { dispWidth = thisWidth - 50 ; dispThumbs = false ; } } + v += 'displaywidth=' + dispWidth + '&' ; - } else if ( this.dispPlaylist == 'below' ) { + } + else if ( this.dispPlaylist == 'below' ) + { dispThumbs = true ; - if ( this.playlistDim.length > 0 ) { + + if ( this.playlistDim.length > 0 ) + { dispHeight = thisWidth - this.playlistDim ; - } else { - if ( thisHeight >= 550 ) { + } + else + { + if ( thisHeight >= 550 ) + { dispHeight = thisWidth - 200 ; - } else if ( thisHeight >= 450 ) { + } + else if ( thisHeight >= 450 ) + { dispHeight = thisHeight - 150 ; - } else if ( thisHeight >= 350 ) { + } + else if ( thisHeight >= 350 ) + { dispHeight = thisHeight - 100 ; } } + v += 'displayheight=' + dispHeight + '&' ; } - if ( this.playlistThumbs == 'false' ) { + if ( this.playlistThumbs == 'false' ) + { dispThumbs = false ; } + v += 'thumbsinplaylist=' + dispThumbs + '&' ; } v += 'shuffle=false&' ; - if (this.loop) { + if (this.loop) + { v += 'repeat=list&' ; - } else { + } + else + { v += 'repeat=' + this.loop + '&' ; } //v += 'transition=bgfade&' ; - } else { + } + else + { v += 'file=' + this.url + '&' ; v += 'repeat=' + this.loop + '&' ; v += 'image=' + this.iurl + '&' ; @@ -590,36 +637,41 @@ Media.prototype.getInnerHTML = function ( objectId ) { v += 'link=' + this.url + '&' ; v += 'showdigits=' + this.displayDigits + '&' ; - v += 'shownavigation=' + this.displayNavigation + '&'; + v += 'shownavigation=' + this.displayNavigation + '&' ; + // SET THE COLOR OF THE TOOLBAR var colorChoice1 = this.toolcolor ; - if ( colorChoice1.length > 0 ) { + if ( colorChoice1.length > 0 ) + { colorChoice1 = colorChoice1.replace( '#', '0x' ) ; v += 'backcolor=' + colorChoice1 + '&' ; } // SET THE COLOR OF THE TOOLBARS TEXT AND BUTTONS var colorChoice2 = this.tooltcolor ; - if ( colorChoice2.length > 0 ) { + if ( colorChoice2.length > 0 ) + { colorChoice2 = colorChoice2.replace( '#', '0x' ) ; v += 'frontcolor=' + colorChoice2 + '&' ; } // SET COLOR OF ROLLOVER TEXT AND BUTTONS var colorChoice3 = this.tooltrcolor ; - if ( colorChoice3.length > 0 ) { + if ( colorChoice3.length > 0 ) + { colorChoice3 = colorChoice3.replace( '#', '0x' ) ; v += 'lightcolor=' + colorChoice3 + '&' ; } - // SET COLOR OF BACKGROUND var colorChoice4 = this.bgcolor ; - if ( colorChoice4.length > 0 ) { + if ( colorChoice4.length > 0 ) + { colorChoice4 = colorChoice4.replace( '#', '0x' ) ; v += 'screencolor=' + colorChoice4 + '&' ; } v += 'logo=' + this.wmurl + '&' ; - if ( this.rurl.length > 0 ) { + if ( this.rurl.length > 0 ) + { v += 'recommendations=' + this.rurl + '&' ; } From 3f7c75f67ab520f07b0ac15d02f3e6a1fef99135 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 2 May 2012 11:32:20 +0200 Subject: [PATCH 003/128] Removing use of the api_get_setting('use_document_title') setting see #3781 --- documentation/changelog.html | 3 + main/admin/settings.php | 3 +- main/coursecopy/classes/Document.class.php | 6 +- .../classes/ScormDocument.class.php | 6 +- main/document/create_document.php | 121 ++++++++---------- main/document/document.inc.php | 50 +++----- main/document/document.php | 6 +- main/document/document_lite.php | 6 +- main/document/edit_document.php | 8 +- main/document/upload.php | 6 +- main/inc/course_document.inc.php | 9 +- main/install/db_main.sql | 5 +- main/install/install.lib.php | 3 +- main/install/migrate-db-1.8.8-1.9.0-pre.sql | 5 +- main/newscorm/lp_add_item.php | 1 - main/upload/upload.document.php | 7 - 16 files changed, 93 insertions(+), 152 deletions(-) mode change 100755 => 100644 main/coursecopy/classes/Document.class.php mode change 100755 => 100644 main/coursecopy/classes/ScormDocument.class.php mode change 100755 => 100644 main/upload/upload.document.php diff --git a/documentation/changelog.html b/documentation/changelog.html index fdc8170f33..9f95926c00 100644 --- a/documentation/changelog.html +++ b/documentation/changelog.html @@ -198,6 +198,9 @@ This version of Chamilo only includes new features:

Known issues

    +
  • + Document title: The option to NOT use a document title different than the filename in the documents tool has been removed. This means that if this setting was not set to the default option in your Chamilo option or if you have a very old installation that you have been upgrading over the years, you might experience problems accessing the documents. In this case, we recommend contacting an official provider of Chamilo to take this migration in charge. +

Third-Party Libraries additions/updates

diff --git a/main/admin/settings.php b/main/admin/settings.php index 5ca05929fc..240ff8b8f8 100644 --- a/main/admin/settings.php +++ b/main/admin/settings.php @@ -43,8 +43,7 @@ api_protect_admin_script(); // Settings to avoid $settings_to_avoid = array( - 'gradebook_enable' => 'false', - 'use_document_title' => 'true', + 'gradebook_enable' => 'false', 'example_material_course_creation' => 'true' // ON by default - now we have this option when we create a course ); diff --git a/main/coursecopy/classes/Document.class.php b/main/coursecopy/classes/Document.class.php old mode 100755 new mode 100644 index d9c49317ce..a26eb153e1 --- a/main/coursecopy/classes/Document.class.php +++ b/main/coursecopy/classes/Document.class.php @@ -49,10 +49,8 @@ class Document extends Resource { parent::show(); echo preg_replace('@^document@', '', $this->path); - if (!empty($this->title) && (api_get_setting('use_document_title') == 'true')) - { - if (strpos($this->path, $this->title) === false) - { + if (!empty($this->title)) { + if (strpos($this->path, $this->title) === false) { echo " - ".$this->title; } } diff --git a/main/coursecopy/classes/ScormDocument.class.php b/main/coursecopy/classes/ScormDocument.class.php old mode 100755 new mode 100644 index 540c5da9a0..cd21af91a7 --- a/main/coursecopy/classes/ScormDocument.class.php +++ b/main/coursecopy/classes/ScormDocument.class.php @@ -39,10 +39,8 @@ class ScormDocument extends Resource parent::show(); $path = preg_replace('@^scorm/@', '', $this->path); echo $path; - if (!empty($this->title) && (api_get_setting('use_document_title') == 'true')) - { - if (strpos($path, $this->title) === false) - { + if (!empty($this->title)) { + if (strpos($path, $this->title) === false) { echo " - ".$this->title; } } diff --git a/main/document/create_document.php b/main/document/create_document.php index 52fbd005df..7ab58c5f4d 100644 --- a/main/document/create_document.php +++ b/main/document/create_document.php @@ -58,8 +58,7 @@ function InnerDialogLoaded() { }; var temp=false; - var temp2=false; - var use_document_title='.api_get_setting('use_document_title').'; + var temp2=false; var load_default_template = '. ((isset($_POST['submit']) || empty($_SERVER['QUERY_STRING'])) ? 'false' : 'true' ) .'; function launch_templates() { @@ -125,10 +124,7 @@ function InnerDialogLoaded() { // comment see FS#3335 // if(document.getElementById(\'title_edited\').value == "false") // { - // document.getElementById(\'filename\').value = bestandsnaamNieuw; - // if(use_document_title){ - // document.getElementById(\'title\').value = bestandsnaamNieuw; - // } + // document.getElementById(\'filename\').value = bestandsnaamNieuw; // } } @@ -349,9 +345,15 @@ function document_exists($filename) { $filename_template = str_replace('{element}', '{element}', $renderer->_elementTemplate); // TODO: What is the point of this statement? $renderer->setElementTemplate($filename_template, 'filename'); + // Initialize group array $group = array(); +$group[] = $form->createElement('text','title',get_lang('Title'),'class="input_titles" id="document_title"'); + +// Added by Ivan Tcholakov, 10-OCT-2009. +$form->addElement('hidden', 'filename', '', array('id' => 'filename')); +/* // If allowed, add element for document title if (api_get_setting('use_document_title') == 'true') { $group[]=$form->createElement('text','title',get_lang('Title'),'class="input_titles" id="document_title"'); @@ -365,6 +367,7 @@ if (api_get_setting('use_document_title') == 'true') { // Added by Ivan Tcholakov, 10-OCT-2009. $form->addElement('hidden', 'title', '', array('id' => 'title')); } +*/ // Show read-only box only in groups if (!empty($_SESSION['_gid'])) { @@ -375,25 +378,16 @@ if (!empty($_SESSION['_gid'])) { if ($is_certificate_mode) $form->addGroup($group, 'filename_group', get_lang('CertificateName') ,'   ', false); else - $form->addGroup($group, 'filename_group', api_get_setting('use_document_title') == 'true' ? get_lang('Title') : get_lang('FileName') ,'   ', false); + $form->addGroup($group, 'filename_group', get_lang('Title'), false); $form->addRule('filename_group', get_lang('ThisFieldIsRequired'), 'required'); -if (api_get_setting('use_document_title') == 'true') { - $form->addGroupRule('filename_group', array( - 'title' => array( - array(get_lang('ThisFieldIsRequired'), 'required'), - array(get_lang('FileExists'),'callback', 'document_exists') - ) - )); -} else { - $form->addGroupRule('filename_group', array( - 'filename' => array( - array(get_lang('ThisFieldIsRequired'), 'required'), - array(get_lang('FileExists'),'callback', 'document_exists') - ) - )); -} +$form->addGroupRule('filename_group', array( + 'title' => array( + array(get_lang('ThisFieldIsRequired'), 'required'), + array(get_lang('FileExists'),'callback', 'document_exists') + ) +)); $current_session_id = api_get_session_id(); @@ -415,45 +409,39 @@ if (!$is_certificate_mode && !is_my_shared_folder($_user['user_id'], $dir, $curr // Following two conditions copied from document.inc.php::build_directory_selector() $folder_titles = array(); - if (api_get_setting('use_document_title') == 'true') { - if (is_array($folders)) { - $escaped_folders = array(); - foreach ($folders as $key => & $val) { - //Hide some folders - if ($val=='/HotPotatoes_files' || $val=='/certificates' || basename($val)=='css'){ - continue; - } - //Admin setting for Hide/Show the folders of all users - if (api_get_setting('show_users_folders') == 'false' && (strstr($val, '/shared_folder') || strstr($val, 'shared_folder_session_'))){ - continue; - } - //Admin setting for Hide/Show Default folders to all users - if (api_get_setting('show_default_folders') == 'false' && ($val=='/images' || $val=='/flash' || $val=='/audio' || $val=='/video' || strstr($val, '/images/gallery') || $val=='/video/flv')){ - continue; - } - //Admin setting for Hide/Show chat history folder - if (api_get_setting('show_chat_folder') == 'false' && $val=='/chat_files'){ - continue; - } - - $escaped_folders[$key] = Database::escape_string($val); - } - $folder_sql = implode("','", $escaped_folders); - - $sql = "SELECT * FROM $doc_table WHERE c_id = $course_id AND filetype='folder' AND path IN ('".$folder_sql."')"; - $res = Database::query($sql); - $folder_titles = array(); - while ($obj = Database::fetch_object($res)) { - $folder_titles[$obj->path] = $obj->title; - } - } - } else { - if (is_array($folders)) { - foreach ($folders as & $folder) { - $folder_titles[$folder] = basename($folder); - } - } - } + + if (is_array($folders)) { + $escaped_folders = array(); + foreach ($folders as $key => & $val) { + //Hide some folders + if ($val=='/HotPotatoes_files' || $val=='/certificates' || basename($val)=='css'){ + continue; + } + //Admin setting for Hide/Show the folders of all users + if (api_get_setting('show_users_folders') == 'false' && (strstr($val, '/shared_folder') || strstr($val, 'shared_folder_session_'))){ + continue; + } + //Admin setting for Hide/Show Default folders to all users + if (api_get_setting('show_default_folders') == 'false' && ($val=='/images' || $val=='/flash' || $val=='/audio' || $val=='/video' || strstr($val, '/images/gallery') || $val=='/video/flv')){ + continue; + } + //Admin setting for Hide/Show chat history folder + if (api_get_setting('show_chat_folder') == 'false' && $val=='/chat_files'){ + continue; + } + + $escaped_folders[$key] = Database::escape_string($val); + } + $folder_sql = implode("','", $escaped_folders); + + $sql = "SELECT * FROM $doc_table WHERE c_id = $course_id AND filetype='folder' AND path IN ('".$folder_sql."')"; + $res = Database::query($sql); + $folder_titles = array(); + while ($obj = Database::fetch_object($res)) { + $folder_titles[$obj->path] = $obj->title; + } + } + if (empty($group_dir)) { $parent_select -> addOption(get_lang('HomeDirectory'), '/'); @@ -527,18 +515,11 @@ if ($form->validate()) { if ($dir[strlen($dir) - 1] != '/') { $dir .= '/'; } - - if (api_get_setting('use_document_title') != 'true') { - $values['title'] = $values['filename']; - } else { - $values['filename'] = $values['title']; - } - + $values['title'] = $values['filename']; $values['filename'] = addslashes(trim($values['filename'])); $values['filename'] = Security::remove_XSS($values['filename']); $values['filename'] = replace_dangerous_char($values['filename']); - $values['filename'] = disable_dangerous_file($values['filename']); - + $values['filename'] = disable_dangerous_file($values['filename']); $filename = $values['filename']; $title = $values['title']; diff --git a/main/document/document.inc.php b/main/document/document.inc.php index 2d1547b3a5..8918cde32b 100644 --- a/main/document/document.inc.php +++ b/main/document/document.inc.php @@ -20,28 +20,22 @@ function build_directory_selector($folders, $document_id, $group_dir = '', $chan $doc_table = Database::get_course_table(TABLE_DOCUMENT); $course_id = api_get_course_int_id(); $folder_titles = array(); - if (api_get_setting('use_document_title') == 'true') { - if (is_array($folders)) { - $escaped_folders = array(); - foreach ($folders as $key => & $val) { - $escaped_folders[$key] = Database::escape_string($val); - } - $folder_sql = implode("','", $escaped_folders); - - $sql = "SELECT * FROM $doc_table WHERE filetype = 'folder' AND c_id = $course_id AND path IN ('".$folder_sql."')"; - $res = Database::query($sql); - $folder_titles = array(); - while ($obj = Database::fetch_object($res)) { - $folder_titles[$obj->path] = $obj->title; - } + + if (is_array($folders)) { + $escaped_folders = array(); + foreach ($folders as $key => & $val) { + $escaped_folders[$key] = Database::escape_string($val); } - } else { - if (is_array($folders)) { - foreach ($folders as & $folder) { - $folder_titles[$folder] = basename($folder); - } + $folder_sql = implode("','", $escaped_folders); + + $sql = "SELECT * FROM $doc_table WHERE filetype = 'folder' AND c_id = $course_id AND path IN ('".$folder_sql."')"; + $res = Database::query($sql); + $folder_titles = array(); + while ($obj = Database::fetch_object($res)) { + $folder_titles[$obj->path] = $obj->title; } } + $form = new FormValidator('selector', 'GET', api_get_self().'?'.api_get_cidreq()); $form->addElement('hidden', 'cidReq', api_get_course_id()); @@ -111,10 +105,9 @@ function create_document_link($document_data, $show_as_icon = false, $counter = } $course_info = api_get_course_info(); $www = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/document'; - $use_document_title = api_get_setting('use_document_title'); - + // Get the title or the basename depending on what we're using - if ($use_document_title == 'true' && $document_data['title'] != '') { + if ($document_data['title'] != '') { $title = $document_data['title']; } else { $title = basename($document_data['path']); @@ -683,10 +676,9 @@ function build_move_to_selector($folders, $curdirpath, $move_file, $group_dir = // 3. inside a subfolder of the folder you want to move if (($curdirpath != $folder) && ($folder != $move_file) && (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')) { $path_displayed = $folder; - // If document title is used, we have to display titles instead of real paths... - if (api_get_setting('use_document_title')) { - $path_displayed = get_titles_of_path($folder); - } + // If document title is used, we have to display titles instead of real paths... + $path_displayed = get_titles_of_path($folder); + if (empty($path_displayed)) { $path_displayed = get_lang('Untitled'); } @@ -696,10 +688,8 @@ function build_move_to_selector($folders, $curdirpath, $move_file, $group_dir = } } else { foreach ($folders as $folder) { - if (($curdirpath != $folder) && ($folder != $move_file) && (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')) { // Cannot copy dir into his own subdir - if (api_get_setting('use_document_title')) { - $path_displayed = get_titles_of_path($folder); - } + if (($curdirpath != $folder) && ($folder != $move_file) && (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')) { // Cannot copy dir into his own subdir + $path_displayed = get_titles_of_path($folder); $display_folder = substr($path_displayed,strlen($group_dir)); $display_folder = ($display_folder == '') ? get_lang('Documents') : $display_folder; $form .= ''; diff --git a/main/document/document.php b/main/document/document.php index b5d478369a..54db4672e9 100644 --- a/main/document/document.php +++ b/main/document/document.php @@ -921,10 +921,6 @@ $table_footer = ''; $total_size = 0; if (isset($docs_and_folders) && is_array($docs_and_folders)) { - - // Do we need the title field for the document name or not? - // We get the setting here, so we only have to do it once - $use_document_title = api_get_setting('use_document_title'); // Create a sortable table with our data $sortable_data = array(); @@ -946,7 +942,7 @@ if (isset($docs_and_folders) && is_array($docs_and_folders)) { $size = $document_data['filetype'] == 'folder' ? get_total_folder_size($document_data['path'], $is_allowed_to_edit) : $document_data['size']; // Get the title or the basename depending on what we're using - if ($use_document_title == 'true' && $document_data['title'] != '') { + if ($document_data['title'] != '') { $document_name = $document_data['title']; } else { $document_name = basename($document_data['path']); diff --git a/main/document/document_lite.php b/main/document/document_lite.php index 5a82f0d53a..1d8e2df372 100644 --- a/main/document/document_lite.php +++ b/main/document/document_lite.php @@ -717,10 +717,6 @@ $table_footer = ''; $total_size = 0; if (isset($docs_and_folders) && is_array($docs_and_folders)) { - - // Do we need the title field for the document name or not? - // We get the setting here, so we only have to do it once - $use_document_title = api_get_setting('use_document_title'); // Create a sortable table with our data $sortable_data = array(); @@ -744,7 +740,7 @@ if (isset($docs_and_folders) && is_array($docs_and_folders)) { $row['size'] = format_file_size($size); // Get the title or the basename depending on what we're using - if ($use_document_title == 'true' && $document_data['title'] != '') { + if ($document_data['title'] != '') { $document_name = $document_data['title']; } else { $document_name = basename($document_data['path']); diff --git a/main/document/edit_document.php b/main/document/edit_document.php index 75cf150eaa..dfe1b8d787 100644 --- a/main/document/edit_document.php +++ b/main/document/edit_document.php @@ -153,8 +153,6 @@ if ($is_certificate_mode) { } $is_allowed_to_edit = api_is_allowed_to_edit(null, true) || $_SESSION['group_member_with_upload_rights']|| is_my_shared_folder(api_get_user_id(), $dir, $current_session_id); - -$use_document_title = api_get_setting('use_document_title') == 'true'; $noPHP_SELF = true; /* Other initialization code */ @@ -371,11 +369,7 @@ if ($owner_id == api_get_user_id() || api_is_platform_admin() || $is_allowed_to_ $form->add_textfield('title', get_lang('Title')); - if ($use_document_title) { - $defaults['title'] = $document_data['title']; - } else { - $form->addElement('hidden', 'renameTo'); - } + $defaults['title'] = $document_data['title']; $form->addElement('hidden', 'formSent'); $defaults['formSent'] = 1; diff --git a/main/document/upload.php b/main/document/upload.php index 8c5021ed75..dca9476795 100644 --- a/main/document/upload.php +++ b/main/document/upload.php @@ -228,10 +228,8 @@ $label = get_lang('MaxFileSize').': '.ini_get('upload_max_filesize').'
'.get $form->addElement('file', 'file', array(get_lang('File'), $label), 'id="user_upload" size="45"'); -if (api_get_setting('use_document_title') == 'true') { - $form->addElement('text', 'title', get_lang('Title'), array('size' => '20', 'style' => 'width:300px', 'id' => 'title_file')); - $form->addElement('textarea', 'comment', get_lang('Comment'), 'wrap="virtual" style="width:300px;"'); -} +$form->addElement('text', 'title', get_lang('Title'), array('size' => '20', 'style' => 'width:300px', 'id' => 'title_file')); +$form->addElement('textarea', 'comment', get_lang('Comment'), 'wrap="virtual" style="width:300px;"'); $advanced = '
 '.get_lang('AdvancedParameters').'
'; // Advanced parameters diff --git a/main/inc/course_document.inc.php b/main/inc/course_document.inc.php index a240235547..703218f587 100644 --- a/main/inc/course_document.inc.php +++ b/main/inc/course_document.inc.php @@ -176,10 +176,7 @@ if ($is_allowed_to_edit) { // TEACHER ONLY $docs_and_folders = getlist ($base_work_dir.'/'); -if ($docs_and_folders) { - //do we need the title field for the document name or not? - //we get the setting here, so we only have to do it once - $use_document_title = api_get_setting('use_document_title'); +if ($docs_and_folders) { //create a sortable table with our data $sortable_data = array(); while (list ($key, $id) = each($docs_and_folders)) { @@ -196,8 +193,8 @@ if ($docs_and_folders) { //size (or total size of a directory) $size = $id['filetype'] == 'folder' ? get_total_folder_size($id['path'], $is_allowed_to_edit) : $id[size]; //get the title or the basename depending on what we're using - if ($use_document_title == 'true' AND $id['title'] != '') { - $document_name=$id['title']; + if ($id['title'] != '') { + $document_name = $id['title']; } else { $document_name = basename($id['path']); } diff --git a/main/install/db_main.sql b/main/install/db_main.sql index 9be08747de..c760a74cc7 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -626,7 +626,6 @@ VALUES ('allow_personal_agenda',NULL,'radio','User','true','AllowPersonalAgendaTitle','AllowPersonalAgendaComment',NULL,NULL, 0), ('display_coursecode_in_courselist',NULL,'radio','Platform','false','DisplayCourseCodeInCourselistTitle','DisplayCourseCodeInCourselistComment',NULL,NULL, 0), ('display_teacher_in_courselist',NULL,'radio','Platform','true','DisplayTeacherInCourselistTitle','DisplayTeacherInCourselistComment',NULL,NULL, 0), -('use_document_title',NULL,'radio','Tools','true','UseDocumentTitleTitle','UseDocumentTitleComment',NULL,NULL, 0), ('permanently_remove_deleted_files',NULL,'radio','Tools','false','PermanentlyRemoveFilesTitle','PermanentlyRemoveFilesComment',NULL,NULL, 0), ('dropbox_allow_overwrite',NULL,'radio','Tools','true','DropboxAllowOverwriteTitle','DropboxAllowOverwriteComment',NULL,NULL, 0), ('dropbox_max_filesize',NULL,'textfield','Tools','100000000','DropboxMaxFilesizeTitle','DropboxMaxFilesizeComment',NULL,NULL, 0), @@ -863,7 +862,7 @@ VALUES ('gradebook_ranking_8', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), ('gradebook_ranking_9', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), ('gradebook_ranking_10', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17631','DatabaseVersion','', NULL, NULL, 0); +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17705','DatabaseVersion','', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), @@ -943,8 +942,6 @@ VALUES ('display_coursecode_in_courselist','false','No'), ('display_teacher_in_courselist','true','Yes'), ('display_teacher_in_courselist','false','No'), -('use_document_title','true','Yes'), -('use_document_title','false','No'), ('permanently_remove_deleted_files','true','YesWillDeletePermanently'), ('permanently_remove_deleted_files','false','NoWillDeletePermanently'), ('dropbox_allow_overwrite','true','Yes'), diff --git a/main/install/install.lib.php b/main/install/install.lib.php index f0bc97f377..7b8a736532 100755 --- a/main/install/install.lib.php +++ b/main/install/install.lib.php @@ -2016,8 +2016,7 @@ function get_countries_list_from_array($combo = false) { */ function locking_settings() { $access_url_locked_settings = array( - 'server_type', - 'use_document_title', + 'server_type', 'permanently_remove_deleted_files', 'account_valid_duration', 'service_visio', diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index 45703ec199..1c52732092 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -191,9 +191,12 @@ INSERT INTO settings_options(variable,value,display_text) VALUES ('page_after_lo ALTER TABLE settings_current ADD COLUMN access_url_locked INTEGER NOT NULL DEFAULT 0; +-- Removing use_document_title +DELETE FROM settings_current WHERE variable = 'use_document_title'; +DELETE FROM settings_options WHERE variable = 'use_document_title'; -- Do not move this query -UPDATE settings_current SET selected_value = '1.9.0.17631' WHERE variable = 'chamilo_database_version'; +UPDATE settings_current SET selected_value = '1.9.0.17705' WHERE variable = 'chamilo_database_version'; -- xxSTATSxx ALTER TABLE track_e_exercices ADD COLUMN questions_to_check TEXT NOT NULL DEFAULT ''; diff --git a/main/newscorm/lp_add_item.php b/main/newscorm/lp_add_item.php index 2636d2e0b1..532af6eea2 100644 --- a/main/newscorm/lp_add_item.php +++ b/main/newscorm/lp_add_item.php @@ -27,7 +27,6 @@ $htmlHeadXtra[] = ' '; - } - // Commented ":" for message in step. - //$return .= $lang.': '; + } $url = api_get_self() . '?cidReq='.Security::remove_XSS($_GET['cidReq']).'&view=build&id='.$item_id .'&lp_id='.$this->lp_id; $return .= Display::url(Display::return_icon('edit.png', get_lang('Edit'), array(), ICON_SIZE_SMALL), $url.'&action=edit_item&path_item=' . $row['path']); @@ -7376,18 +7374,6 @@ class learnpath { $return .= Display::url(Display::return_icon('accept.png', get_lang('Prerequisites'), array(), ICON_SIZE_SMALL), $url.'&action=edit_item_prereq'); } $return .= Display::url(Display::return_icon('delete.png', get_lang('Delete'), array(), ICON_SIZE_SMALL), $url.'&action=delete_item'); -/* - // Get the audiorecorder. Use of ob_* functions since there are echos in the file. - ob_start(); - $audio_recorder_studentview = 'false'; - $audio_recorder_item_id = $item_id; - if (api_get_setting('service_visio', 'active') == 'true') { - require_once 'audiorecorder.inc.php'; - } - $return .= ob_get_contents(); - ob_end_clean(); - // End of audiorecorder include - */ $return .= '
'; return $return; } @@ -7724,10 +7710,8 @@ class learnpath { $res_quiz = Database::query($sql_quiz); $res_hot = Database::query($sql_hot); - $return = '
'; - - $return .= '
'; - //$return .= Display::return_icon('new_exercice.png', '', array(), 32); //''; + $return = '
'; + $return .= '
'; $return .= ''; $return .= '' . get_lang('NewExercise') . ''; $return .= '
'; @@ -7742,11 +7726,9 @@ class learnpath { while ($row_quiz = Database :: fetch_array($res_quiz)) { $return .= '
'; - $return .= ''; - //$return .= Display::return_icon('quiz.png', '', array(), 32); //''; + $return .= ''; $return .= '' . - Security :: remove_XSS(cut($row_quiz['title'], 80)).''; - //$return .= $row_quiz['title']; + Security :: remove_XSS(cut($row_quiz['title'], 80)).''; $return .= '
'; } @@ -7768,7 +7750,6 @@ class learnpath { $sql_link = "SELECT * FROM $tbl_link WHERE c_id = ".$course_id." $condition_session ORDER BY title ASC"; $res_link = Database::query($sql_link); - //$return .= '
' . get_lang('Links') . '
'; $return = '
'; $return .= '
'; $return .= ''; @@ -7778,15 +7759,12 @@ class learnpath { while ($row_link = Database :: fetch_array($res_link)) { $return .= '
'; $return .= ''; - $return .= '' . $row_link['title'] . ''; + $return .= ''. + $row_link['title']. + ''; $return .= '
'; } - - /*if (Database :: num_rows($res_link) == 0) - $return .= '
' . get_lang('NoLinksAvailable') . '
'; - */ $return .= '
'; - return $return; } @@ -7795,12 +7773,12 @@ class learnpath { * @return unknown */ public function get_student_publications() { - $course_id = api_get_course_int_id(); - $tbl_student = Database :: get_course_table(TABLE_STUDENT_PUBLICATION); - $session_id = api_get_session_id(); - $condition_session = api_get_session_condition($session_id); - $sql_student = "SELECT * FROM $tbl_student WHERE c_id = ".$course_id." $condition_session ORDER BY title ASC"; - $res_student = Database::query($sql_student); + //$course_id = api_get_course_int_id(); + //$tbl_student = Database :: get_course_table(TABLE_STUDENT_PUBLICATION); + //$session_id = api_get_session_id(); + //$condition_session = api_get_session_condition($session_id); + //$sql_student = "SELECT * FROM $tbl_student WHERE c_id = ".$course_id." $condition_session ORDER BY title ASC"; + //$res_student = Database::query($sql_student); //$return .= '
' . get_lang('Student_publication') . '
'; $return = '
'; $return .= '
'; From 0485a24f01e97553636902ffc3c314d178d1e3a7 Mon Sep 17 00:00:00 2001 From: Hubert Borderiou Date: Fri, 4 May 2012 14:36:31 +0200 Subject: [PATCH 026/128] Minor change to CAS authentification and plugin. -ref#3940 --- main/auth/cas/authcas.php | 22 +++++++++++++++++++++- main/auth/cas/logincas.php | 16 +++++++++++----- plugin/add_cas_login_button/index.php | 7 +++++-- plugin/add_cas_login_button/template.tpl | 12 ++++++++++-- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/main/auth/cas/authcas.php b/main/auth/cas/authcas.php index adbaef1aff..f3dd47d715 100644 --- a/main/auth/cas/authcas.php +++ b/main/auth/cas/authcas.php @@ -9,18 +9,38 @@ require_once(api_get_path(SYS_PATH).'main/auth/cas/cas_var.inc.php'); require_once(api_get_path(SYS_PATH).'main/auth/external_login/ldap.inc.php'); require_once(api_get_path(SYS_PATH).'main/auth/external_login/functions.inc.php'); + + +/** +* @return true if cas is configured +* +**/ +function cas_configured() { + global $cas_auth_ver, $cas_auth_server, $cas_auth_port, $cas_auth_uri; + $res = false; + if (!empty($cas_auth_ver) && !empty($cas_auth_server) && !empty($cas_auth_port)) { + $res = true; + } + return $res; +} + + + /** * checks if the user already get a session * @return the user login if the user already has a session ,false otherwise **/ - function cas_is_authenticated() { global $cas_auth_ver, $cas_auth_server, $cas_auth_port, $cas_auth_uri; global $PHPCAS_CLIENT; global $logout; + if (!cas_configured()) { + return; + } + if (!is_object($PHPCAS_CLIENT) ) { diff --git a/main/auth/cas/logincas.php b/main/auth/cas/logincas.php index 24672bf0e0..c0c7c8b284 100644 --- a/main/auth/cas/logincas.php +++ b/main/auth/cas/logincas.php @@ -16,9 +16,15 @@ require_once (api_get_path(LIBRARY_PATH).'events.lib.inc.php'); require_once('authcas.php'); global $cas_auth_ver, $cas_auth_server, $cas_auth_port, $cas_auth_uri; // phpCAS -if (!is_object($PHPCAS_CLIENT) ) { - phpCAS::client($cas_auth_ver,$cas_auth_server,$cas_auth_port,$cas_auth_uri); - phpCAS::setNoCasServerValidation(); + +if (cas_configured()) { + if (!is_object($PHPCAS_CLIENT) ) { + phpCAS::client($cas_auth_ver,$cas_auth_server,$cas_auth_port,$cas_auth_uri); + phpCAS::setNoCasServerValidation(); + } + phpCAS::forceAuthentication(); + header('Location: '.api_get_path(WEB_PATH).api_get_setting('page_after_login')); +} +else { + header('Location: '.api_get_path(WEB_PATH)); } -phpCAS::forceAuthentication(); -header('Location: '.api_get_path(WEB_PATH).api_get_setting('page_after_login')); diff --git a/plugin/add_cas_login_button/index.php b/plugin/add_cas_login_button/index.php index 52fa656f03..4445aafcb8 100644 --- a/plugin/add_cas_login_button/index.php +++ b/plugin/add_cas_login_button/index.php @@ -1,9 +1,12 @@  
{% endif %}
{{add_cas_login_button.comm_label}}
- + {% if add_cas_login_button.cas_activated %} + {% if add_cas_login_button.cas_configured %} + + {% else %} + CAS isn't configured. Go to Admin > Configuration > CAS.
+ {% endif %} + {% else %} + CAS isn't activated. Go to Admin > Configuration > CAS.
+ {% endif %}
{% endif %} From 453b325c13fbbea269fad1462cbbb2594965eea7 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Fri, 4 May 2012 14:39:25 +0200 Subject: [PATCH 027/128] Showing only visible links in the LP "add item" page --- main/newscorm/learnpath.class.php | 29 ++++++++++++++--------------- main/newscorm/lp_add_item.php | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/main/newscorm/learnpath.class.php b/main/newscorm/learnpath.class.php index a1c53eae36..e66d8e3409 100644 --- a/main/newscorm/learnpath.class.php +++ b/main/newscorm/learnpath.class.php @@ -7509,12 +7509,7 @@ class learnpath { $return .= '
- - - - -
- - - - - - -
- + + - - - - -
-
-
-
-
- get_preview_image()!='') { - $picture = getimagesize(api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/learning_path/images/'.$_SESSION['oLP']->get_preview_image()); - if($picture['1'] < 96) { $style = ' style="padding-top:'.((94 -$picture['1'])/2).'px;" '; } - $size = ($picture['0'] > 104 && $picture['1'] > 96 )? ' width="104" height="96" ': $style; - $my_path = api_get_path(WEB_COURSE_PATH).api_get_course_path().'/upload/learning_path/images/'.$_SESSION['oLP']->get_preview_image(); - echo ''; - } else { - echo Display :: display_icon('unknown_250_100.jpg'); - } - ?> -
-
- -
- -
- -
-
-
-
-
- - -
- get_author(); ?> -
- - -
> - + + + +
+
+ get_preview_image()!='') { + $picture = getimagesize(api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/learning_path/images/'.$_SESSION['oLP']->get_preview_image()); + if($picture['1'] < 96) { $style = ' style="padding-top:'.((94 -$picture['1'])/2).'px;" '; } + $size = ($picture['0'] > 104 && $picture['1'] > 96 )? ' width="104" height="96" ': $style; + $my_path = api_get_path(WEB_COURSE_PATH).api_get_course_path().'/upload/learning_path/images/'.$_SESSION['oLP']->get_preview_image(); + echo ''; + } else { + echo Display :: display_icon('unknown_250_100.jpg'); + } + ?>
- - - - -
-
- get_html_toc(); ?> - - scorm_debug)) { //only show log ?> - -
-
-
.
-
- - -
+
+ +
+ +
-
- - - -
- - // hub 26-05-2010 Fullscreen or not fullscreen - if ($_SESSION['oLP']->mode == 'fullscreen') { - echo ''; - } else { - echo ''; - } - ?> +
+ get_author(); ?> +
+ + + +
> + +
+ + + +
+
+ get_html_toc(); ?> + + scorm_debug)) { //only show log ?> + +
+
+
.
+
+ + +
- + +
+ + + + +
+mode == 'fullscreen') { + echo ''; + } else { + echo ''; + } +?> +
+
-'; @@ -163,28 +161,21 @@ $interbreadcrumb[] = array ('url' => '#', 'name' => get_lang('AccessDetails')); Display :: display_header(''); $main_user_info = api_get_user_info($user_id); $result_to_print = ''; -$main_date_array = array(); $sql_result = MySpace::get_connections_to_course($user_id, $course_code); $result_to_print = convert_to_string($sql_result); -api_display_tool_title(get_lang('DetailsStudentInCourse')); +echo Display::page_header(get_lang('DetailsStudentInCourse')); +echo Display::page_subheader(get_lang('User').': '.api_get_person_name($main_user_info['firstName'], $main_user_info['lastName']).' - '.get_lang('Course').': '.$course_code); + +$form = new FormValidator('myform', 'post', "javascript:get(document.getElementById('myform'));", null, array('id' => 'myform')); +$form->addElement('text', 'from', get_lang('From'), array('id' => 'date_from')); +$form->addElement('text', 'to', get_lang('Until'), array('id' => 'date_to')); + +$form->addElement('style_submit_button', 'reset', get_lang('Reset'), array('onclick' => "javascript:window.location='access_details.php?course=".$course_code."&student=".$user_id."&cidReq=".$course_code."';")); +$form->display(); ?>
-
-'.get_lang('User').': '.api_get_person_name($main_user_info['firstName'], $main_user_info['lastName']).'
'.get_lang('Course').': '.$course_code; ?>
-
-
-
-

- - - - -


-
- -


@@ -210,7 +201,6 @@ api_display_tool_title(get_lang('DetailsStudentInCourse'));
-

@@ -225,9 +215,9 @@ api_display_tool_title(get_lang('DetailsStudentInCourse'));
+ echo '

'); +
'; }?>

From 4ee98556d4cac34908cc735e7ceb97052b787651 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Mon, 7 May 2012 12:01:03 +0200 Subject: [PATCH 039/128] installation: remove warnings and file_exisits bug --- main/install/install.lib.php | 2 +- main/install/update-db-1.8.5-1.8.6.inc.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main/install/install.lib.php b/main/install/install.lib.php index 7b8a736532..9ee31881cc 100755 --- a/main/install/install.lib.php +++ b/main/install/install.lib.php @@ -516,7 +516,7 @@ function get_config_param($param, $updatePath = '') { $configFile[$variable] = $value; $a = explode("'", $variable); - $key_tmp = $a[1]; + $key_tmp = isset($a[1]) ? $a[1] : null; if ($key_tmp == $param) { $val = $value; } diff --git a/main/install/update-db-1.8.5-1.8.6.inc.php b/main/install/update-db-1.8.5-1.8.6.inc.php index 7654d58dda..573ce2ce5e 100644 --- a/main/install/update-db-1.8.5-1.8.6.inc.php +++ b/main/install/update-db-1.8.5-1.8.6.inc.php @@ -125,7 +125,7 @@ if (defined('SYSTEM_INSTALLATION')) { @mkdir($dir.$user_id, $perm); } - if (file_exists($image_repository)) { + if (file_exists($image_repository) && is_file($image_repository)) { chmod($dir.$user_id, 0777); if (is_dir($dir.$user_id)) { $picture_location = $dir.$user_id.'/'.$file; From abdf76c412cc514d2b3211af4f7fec9368db8b13 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Mon, 7 May 2012 12:11:17 +0200 Subject: [PATCH 040/128] #4694 add feedback during installation, monolog --- main/install/update-db-1.8.5-1.8.6.inc.php | 12 +- main/install/update-db-1.8.6-1.8.6.1.inc.php | 4 +- main/install/update-db-1.8.6.2-1.8.7.inc.php | 4 +- main/install/update-db-1.8.7-1.8.8.inc.php | 8 +- main/install/update-db-1.8.8-1.9.0.inc.php | 4 +- main/install/update-files-1.6.x-1.8.0.inc.php | 246 +++++++++--------- main/install/update-files-1.8.5-1.8.6.inc.php | 4 +- .../update-files-1.8.6.1-1.8.6.2.inc.php | 2 +- 8 files changed, 140 insertions(+), 144 deletions(-) diff --git a/main/install/update-db-1.8.5-1.8.6.inc.php b/main/install/update-db-1.8.5-1.8.6.inc.php index 573ce2ce5e..84bb4bbe9a 100644 --- a/main/install/update-db-1.8.5-1.8.6.inc.php +++ b/main/install/update-db-1.8.5-1.8.6.inc.php @@ -91,11 +91,11 @@ if (defined('SYSTEM_INSTALLATION')) { Database::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbNameForm,$query)", 0); + Log::notice("Database::query($dbNameForm,$query)"); } else { $res = Database::query($query); if ($log) { - Log::notice("In $dbNameForm, executed: $query", 0); + Log::notice("In $dbNameForm, executed: $query"); } } } @@ -1049,15 +1049,15 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (strlen($dbUserForm) > 40) { - Log::error('Database name '.$dbUserForm.' is too long, skipping', 0); + Log::error('Database name '.$dbUserForm.' is too long, skipping'); } elseif (!in_array($dbUserForm,$dblist)) { - Log::error('Database '.$dbUserForm.' was not found, skipping', 0); + Log::error('Database '.$dbUserForm.' was not found, skipping'); } else { Database::select_db($dbUserForm); foreach ($u_q_list as $query) { if ($only_test) { - error_log("Database::query($dbUserForm,$query)", 0); - error_log("In $dbUserForm, executed: $query", 0); + error_log("Database::query($dbUserForm,$query)"); + error_log("In $dbUserForm, executed: $query"); } else { $res = Database::query($query); } diff --git a/main/install/update-db-1.8.6-1.8.6.1.inc.php b/main/install/update-db-1.8.6-1.8.6.1.inc.php index f822419b5e..89a5fed4f3 100644 --- a/main/install/update-db-1.8.6-1.8.6.1.inc.php +++ b/main/install/update-db-1.8.6-1.8.6.1.inc.php @@ -200,11 +200,11 @@ if (defined('SYSTEM_INSTALLATION')) { } if ($only_test) { - Log::notice("Database::query(".$row_course['db_name'].",$query)", 0); + Log::notice("Database::query(".$row_course['db_name'].",$query)"); } else { $res = Database::query($query); if ($log) { - Log::notice("In ".$row_course['db_name'].", executed: $query", 0); + Log::notice("In ".$row_course['db_name'].", executed: $query"); } } } diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index c3f980b2c1..2c4f76b233 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -230,11 +230,11 @@ if (defined('SYSTEM_INSTALLATION')) { Database::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbNameForm,$query)", 0); + Log::notice("Database::query($dbNameForm,$query)"); } else { $res = Database::query($query); if ($log) { - Log::notice("In $dbNameForm, executed: $query", 0); + Log::notice("In $dbNameForm, executed: $query"); } } } diff --git a/main/install/update-db-1.8.7-1.8.8.inc.php b/main/install/update-db-1.8.7-1.8.8.inc.php index 5b982b5391..6f1beb00db 100644 --- a/main/install/update-db-1.8.7-1.8.8.inc.php +++ b/main/install/update-db-1.8.7-1.8.8.inc.php @@ -113,18 +113,18 @@ if (defined('SYSTEM_INSTALLATION')) { // We connect to the right DB first to make sure we can use the queries // without a database name. if (strlen($dbNameForm) > 40) { - error_log('Database name '.$dbNameForm.' is too long, skipping', 0); + error_log('Database name '.$dbNameForm.' is too long, skipping'); } elseif (!in_array($dbNameForm,$dblist)) { - error_log('Database '.$dbNameForm.' was not found, skipping', 0); + error_log('Database '.$dbNameForm.' was not found, skipping'); } else { Database::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { - error_log("Database::query($dbNameForm,$query)", 0); + error_log("Database::query($dbNameForm,$query)"); } else { $res = Database::query($query); if ($log) { - error_log("In $dbNameForm, executed: $query", 0); + error_log("In $dbNameForm, executed: $query"); } } } diff --git a/main/install/update-db-1.8.8-1.9.0.inc.php b/main/install/update-db-1.8.8-1.9.0.inc.php index 368216323e..399c4581b8 100755 --- a/main/install/update-db-1.8.8-1.9.0.inc.php +++ b/main/install/update-db-1.8.8-1.9.0.inc.php @@ -271,11 +271,11 @@ if (defined('SYSTEM_INSTALLATION')) { $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix{$row_course['db_name']}_$2$3", $query); } if ($only_test) { - Log::notice("Database::query(".$row_course['db_name'].",$query)", 0); + Log::notice("Database::query(".$row_course['db_name'].",$query)"); } else { $res = Database::query($query); if ($log) { - Log::notice("In ".$row_course['db_name'].", executed: $query", 0); + Log::notice("In ".$row_course['db_name'].", executed: $query"); } if ($res === false) { Log::error('Error in '.$query.': '.Database::error()); diff --git a/main/install/update-files-1.6.x-1.8.0.inc.php b/main/install/update-files-1.6.x-1.8.0.inc.php index 3850e23cc4..09d21a1e97 100644 --- a/main/install/update-files-1.6.x-1.8.0.inc.php +++ b/main/install/update-files-1.6.x-1.8.0.inc.php @@ -1,4 +1,5 @@ audio - if (!is_dir($currentCourseRepositorySys."document/audio")) { - mkdir($currentCourseRepositorySys."document/audio", $perm); - insert_db($db_name, "audio", get_lang('Audio')); - } - - // document > flash - if (!is_dir($currentCourseRepositorySys."document/flash")) { - mkdir($currentCourseRepositorySys."document/flash", $perm); - insert_db($db_name,"flash",get_lang('Flash')); - } - - // document > images - if (!is_dir($currentCourseRepositorySys."document/images")) { - mkdir($currentCourseRepositorySys."document/images", $perm); - insert_db($db_name,"images",get_lang('Images')); - } - - // document > video - if (!is_dir($currentCourseRepositorySys."document/video")) { - mkdir($currentCourseRepositorySys."document/video", $perm); - insert_db($db_name,"video",get_lang('Video')); - } - - // document > video > flv - if (!is_dir($currentCourseRepositorySys."document/video/flv")) { - mkdir($currentCourseRepositorySys."document/video/flv", $perm); - insert_db($db_name,"video",get_lang('Video')." (flv)"); - } - - // FOLDER UPLOAD - - // upload - if (!is_dir($currentCourseRepositorySys."upload")) { - mkdir($currentCourseRepositorySys."upload", $perm); - } - - // upload > blog - if (!is_dir($currentCourseRepositorySys."upload/blog")) { - mkdir($currentCourseRepositorySys."upload/blog", $perm); - } - - // upload > forum - if (!is_dir($currentCourseRepositorySys."upload/forum")) { - mkdir($currentCourseRepositorySys."upload/forum", $perm); - } - - // upload > test - if (!is_dir($currentCourseRepositorySys."upload/test")) { - mkdir($currentCourseRepositorySys."upload/test", $perm); - } - - // Updating index file in courses directories to change claroline/ into main/ - $content = ''; - unlink($currentCourseRepositorySys.'index.php'); - $fp = @ fopen($currentCourseRepositorySys.'index.php', 'w'); - if ($fp) { - error_log('Writing redirection file in '.$currentCourseRepositorySys.'index.php', 0); - fwrite($fp, $content); - fclose($fp); - } else { - error_log('Could not open file '.$currentCourseRepositorySys.'index.php', 0); - } - } - - // Write the config file - write_system_config_file(api_get_path(CONFIGURATION_PATH).'configuration.php'); - // Write a distribution file with the config as a backup for the admin - write_system_config_file(api_get_path(CONFIGURATION_PATH).'configuration.dist.php'); - // Write a .htaccess file in the course repository - write_courses_htaccess_file($urlAppendPath); - copy($updatePath.'claroline/inc/conf/add_course.conf.php', $pathForm.'main/inc/conf/add_course.conf.php'); - copy($updatePath.'claroline/inc/conf/course_info.conf.php', $pathForm.'main/inc/conf/course_info.conf.php'); - copy($updatePath.'claroline/inc/conf/mail.conf.php', $pathForm.'main/inc/conf/mail.conf.php'); - copy($updatePath.'claroline/inc/conf/profile.conf.inc.php', $pathForm.'main/inc/conf/profile.conf.php'); - - error_log('Renaming '.$updatePath.'claroline/upload/users to '.$pathForm.'main/upload/users', 0); - rename($updatePath.'claroline/upload/users', $pathForm.'main/upload/users'); - error_log('Renaming '.$updatePath.'claroline/upload/audio to '.$pathForm.'main/upload/audio', 0); - rename($updatePath.'claroline/upload/audio', $pathForm.'main/upload/audio'); - error_log('Renaming '.$updatePath.'claroline/upload/images to '.$pathForm.'main/upload/images', 0); - rename($updatePath.'claroline/upload/images', $pathForm.'main/upload/images'); - error_log('Renaming '.$updatePath.'claroline/upload/linked_files to '.$pathForm.'main/upload/linked_files', 0); - rename($updatePath.'claroline/upload/linked_files', $pathForm.'main/upload/linked_files'); - error_log('Renaming '.$updatePath.'claroline/upload/video to '.$pathForm.'main/upload/video', 0); - rename($updatePath.'claroline/upload/video', $pathForm.'main/upload/video'); - + $sys_course_path = $pathForm . 'courses/'; + //$tbl_course = Database :: get_main_table(TABLE_MAIN_COURSE); + Database::select_db($dbNameForm); + $db_name = $dbNameForm; + $sql = "SELECT * FROM course"; + Log::notice('Getting courses for files updates: ' . $sql); + $result = Database::query($sql); + + while ($courses_directories = Database::fetch_array($result)) { + + $currentCourseRepositorySys = $sys_course_path . $courses_directories["directory"] . "/"; + $db_name = $courses_directories["db_name"]; + $origCRS = $updatePath . 'courses/' . $courses_directories["directory"]; + + if (!is_dir($origCRS)) { + Log::error('Directory ' . $origCRS . ' does not exist. Skipping.'); + continue; + } + // Move everything to the new hierarchy (from old path to new path) + Log::notice('Renaming ' . $origCRS . ' to ' . $sys_course_path . $courses_directories["directory"]); + rename($origCRS, $sys_course_path . $courses_directories["directory"]); + Log::notice('Creating dirs in ' . $currentCourseRepositorySys); + + // FOLDER DOCUMENT + // document > audio + if (!is_dir($currentCourseRepositorySys . "document/audio")) { + mkdir($currentCourseRepositorySys . "document/audio", $perm); + insert_db($db_name, "audio", get_lang('Audio')); + } + + // document > flash + if (!is_dir($currentCourseRepositorySys . "document/flash")) { + mkdir($currentCourseRepositorySys . "document/flash", $perm); + insert_db($db_name, "flash", get_lang('Flash')); + } + + // document > images + if (!is_dir($currentCourseRepositorySys . "document/images")) { + mkdir($currentCourseRepositorySys . "document/images", $perm); + insert_db($db_name, "images", get_lang('Images')); + } + + // document > video + if (!is_dir($currentCourseRepositorySys . "document/video")) { + mkdir($currentCourseRepositorySys . "document/video", $perm); + insert_db($db_name, "video", get_lang('Video')); + } + + // document > video > flv + if (!is_dir($currentCourseRepositorySys . "document/video/flv")) { + mkdir($currentCourseRepositorySys . "document/video/flv", $perm); + insert_db($db_name, "video", get_lang('Video') . " (flv)"); + } + + // FOLDER UPLOAD + // upload + if (!is_dir($currentCourseRepositorySys . "upload")) { + mkdir($currentCourseRepositorySys . "upload", $perm); + } + + // upload > blog + if (!is_dir($currentCourseRepositorySys . "upload/blog")) { + mkdir($currentCourseRepositorySys . "upload/blog", $perm); + } + + // upload > forum + if (!is_dir($currentCourseRepositorySys . "upload/forum")) { + mkdir($currentCourseRepositorySys . "upload/forum", $perm); + } + + // upload > test + if (!is_dir($currentCourseRepositorySys . "upload/test")) { + mkdir($currentCourseRepositorySys . "upload/test", $perm); + } + + // Updating index file in courses directories to change claroline/ into main/ + $content = ''; + unlink($currentCourseRepositorySys . 'index.php'); + $fp = @ fopen($currentCourseRepositorySys . 'index.php', 'w'); + if ($fp) { + Log::error('Writing redirection file in ' . $currentCourseRepositorySys . 'index.php'); + fwrite($fp, $content); + fclose($fp); + } else { + Log::error('Could not open file ' . $currentCourseRepositorySys . 'index.php'); + } + } + + // Write the config file + write_system_config_file(api_get_path(CONFIGURATION_PATH) . 'configuration.php'); + // Write a distribution file with the config as a backup for the admin + write_system_config_file(api_get_path(CONFIGURATION_PATH) . 'configuration.dist.php'); + // Write a .htaccess file in the course repository + write_courses_htaccess_file($urlAppendPath); + copy($updatePath . 'claroline/inc/conf/add_course.conf.php', $pathForm . 'main/inc/conf/add_course.conf.php'); + copy($updatePath . 'claroline/inc/conf/course_info.conf.php', $pathForm . 'main/inc/conf/course_info.conf.php'); + copy($updatePath . 'claroline/inc/conf/mail.conf.php', $pathForm . 'main/inc/conf/mail.conf.php'); + copy($updatePath . 'claroline/inc/conf/profile.conf.inc.php', $pathForm . 'main/inc/conf/profile.conf.php'); + + Log::notice('Renaming ' . $updatePath . 'claroline/upload/users to ' . $pathForm . 'main/upload/users'); + rename($updatePath . 'claroline/upload/users', $pathForm . 'main/upload/users'); + Log::notice('Renaming ' . $updatePath . 'claroline/upload/audio to ' . $pathForm . 'main/upload/audio'); + rename($updatePath . 'claroline/upload/audio', $pathForm . 'main/upload/audio'); + Log::notice('Renaming ' . $updatePath . 'claroline/upload/images to ' . $pathForm . 'main/upload/images'); + rename($updatePath . 'claroline/upload/images', $pathForm . 'main/upload/images'); + Log::notice('Renaming ' . $updatePath . 'claroline/upload/linked_files to ' . $pathForm . 'main/upload/linked_files'); + rename($updatePath . 'claroline/upload/linked_files', $pathForm . 'main/upload/linked_files'); + Log::notice('Renaming ' . $updatePath . 'claroline/upload/video to ' . $pathForm . 'main/upload/video'); + rename($updatePath . 'claroline/upload/video', $pathForm . 'main/upload/video'); } else { - echo 'You are not allowed here !'; - + echo 'You are not allowed here !'; } diff --git a/main/install/update-files-1.8.5-1.8.6.inc.php b/main/install/update-files-1.8.5-1.8.6.inc.php index d2522c6620..1f29ac5701 100644 --- a/main/install/update-files-1.8.5-1.8.6.inc.php +++ b/main/install/update-files-1.8.5-1.8.6.inc.php @@ -79,9 +79,9 @@ if (defined('SYSTEM_INSTALLATION')) { continue; } // Move everything to the new hierarchy (from old path to new path) - Log::notice('Renaming ' . $origCRS . ' to ' . $sys_course_path . $courses_directories['directory'], 0); + Log::notice('Renaming ' . $origCRS . ' to ' . $sys_course_path . $courses_directories['directory']); rename($origCRS, $sys_course_path . $courses_directories['directory']); - Log::notice('Creating dirs in ' . $currentCourseRepositorySys, 0); + Log::notice('Creating dirs in ' . $currentCourseRepositorySys); // DOCUMENT FOLDER // document > shared_folder diff --git a/main/install/update-files-1.8.6.1-1.8.6.2.inc.php b/main/install/update-files-1.8.6.1-1.8.6.2.inc.php index 39813664a3..818dd37f8a 100644 --- a/main/install/update-files-1.8.6.1-1.8.6.2.inc.php +++ b/main/install/update-files-1.8.6.1-1.8.6.2.inc.php @@ -59,7 +59,7 @@ if (defined('SYSTEM_INSTALLATION')) { $db_name = $dbNameForm; $sql = "SELECT * FROM $db_name.course"; - Log::notice('Getting courses for files updates: ' . $sql, 0); + Log::notice('Getting courses for files updates: ' . $sql); $result = Database::query($sql); if (Database::num_rows($result) > 0) { From 1763e99a47c73a192d30332a59e36f7f4e228019 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 12:13:04 +0200 Subject: [PATCH 041/128] Lang updated --- main/lang/english/admin.inc.php | 21 ++++++++++----------- main/lang/english/trad4all.inc.php | 3 ++- main/lang/french/admin.inc.php | 18 ++++++++---------- main/lang/spanish/admin.inc.php | 2 ++ main/lang/spanish/gradebook.inc.php | 4 ++++ main/lang/spanish/trad4all.inc.php | 5 ++++- 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/main/lang/english/admin.inc.php b/main/lang/english/admin.inc.php index 255162346b..6d5bd42976 100644 --- a/main/lang/english/admin.inc.php +++ b/main/lang/english/admin.inc.php @@ -1304,7 +1304,7 @@ $EnabledImageMapsTitle = "Activate Image maps"; $EnabledImageMapsComment = "Activate the button to insert Image maps. This allows you to associate URLs to areas of an image, creating hotspots."; $CourseTool = "Course tool"; $BigBlueButtonEnableTitle = "BigBlueButton videoconference tool"; -$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Students will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please set one up or ask the Chamilo official providers for a quote. +$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Students will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please set one up or ask the Chamilo official providers for a quote. BigBlueButton is a free (as in freedom *and* beer), but its installation requires a set of technical skills that might not be immediately available to all. You can install it on your own or seek professional help to assist you or do it for you. This help, however, will generate a certain cost. In the pure logic of the free software, we offer you the tools to make your work easier and recommend professionals (the Chamilo Official Providers) that will be able to help you if this were too difficult."; $BigBlueButtonHostTitle = "BigBlueButton server host"; $BigBlueButtonHostComment = "This is the name of the server where your BigBlueButton server is running. Might be localhost, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com)."; @@ -1329,8 +1329,8 @@ $IncludeAsciiMathMlComment = "Activate this setting if you want to show ASCIIMat $CourseHideToolsTitle = "Hide tools from teachers"; $CourseHideToolsComment = "Check the tools you want to hide from teachers. This will prohibit access to the tool."; $MoveUserStats = "Move users results from/to a session"; -$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.
-On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.
+$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.
+On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.
Once you are sure about what to do, you can choose to move the tracking data of the students (exercises results and learning paths tracking) from a course to a session."; $PDFExportWatermarkEnableTitle = "Enable watermark in PDF export"; $PDFExportWatermarkEnableComment = "By enabling this option, you can upload an image or a text that will be automatically added as watermark to all PDF exports of documents on the system."; @@ -1385,8 +1385,8 @@ $EnableAccessibilityFontResizeTitle = "Font resize accessibility feature"; $EnableAccessibilityFontResizeComment = "Enable this option to show a set of font resize options on the top-right side of your campus. This will allow visually impaired to read their course contents more easily."; $GlobalEvent = "Platform event"; $SearchEnabledTitle = "Fulltext search"; -$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.
-This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.
+$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.
+This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.
Once enabled, a search box will appear in the courses list of every user. Searching for a specific term will bring a list of corresponding documents, exercises or forum topics, filtered depending on the availability of these contents to the user."; $SpecificSearchFieldsAvailable = "Available custom search fields"; $XapianModuleInstalled = "Xapian module installed"; @@ -1533,10 +1533,9 @@ $AllowBrowserSnifferTitle = "Activate the browser sniffer"; $AllowBrowserSnifferComment = "This will enable an investigator of the capabilities that support browsers that connect to Chamilo. Therefore will improve user experience by adapting responses to the type of browser platform that connects, but will slow initial page load of users every time that they enter to the platform."; $EnableWamiRecordTitle = "Activate Wami-recorder"; $EnableWamiRecordComment = "Wami-recorder is a voice record tool on Flash"; -$LdapDescriptionComment = "

  • LDAP authentication :
    See I. below to configure LDAP
    See II. below to activate LDAP authentication


  • Update user attributes, with LDAP data, after CAS authentication(see CAS configuration ) :
    See I. below to configure LDAP
    CAS manage user authentication, LDAP activation isn't required.


I. LDAP configuration

Edit file main/auth/external_login/ldap.conf.php
-> Edit values of array $extldap_config

Parameters are
  • base domain string (ex : 'base_dn' => 'DC=cblue,DC=be')
  • admin distinguished name (ex : 'admin_dn' =>'CN=admin,dc=cblue,dc=be')
  • admin password (ex : 'admin_password' => '123456')
  • ldap host (ex : 'host' => array('1.2.3.4', '2.3.4.5', '3.4.5.6'))
  • filter (ex : 'filter' => '')
  • port (ex : 'port' => 389)
  • protocol version (2 or 3) (ex : 'protocol_version' => 3)
  • user_search (ex : 'user_search' => 'sAMAccountName=%username%')
  • encoding (ex : 'encoding' => 'UTF-8')
  • update_userinfo (ex : 'update_userinfo' => true)
-> To update correspondences between user and LDAP attributes, edit array $extldap_user_correspondance
Array values are <chamilo_field> => >ldap_field>
Array structure is explained in file main/auth/external_login/ldap.conf.php


II. Activate LDAP authentication

Edit file main/inc/conf/configuration.php
-> Uncomment lines
$extAuthSource["extldap"]["login"] =$_configuration['root_sys'].$_configuration['code_append']."auth/external_login/login.ldap.php";
$extAuthSource["extldap"]["newUser"] =$_configuration['root_sys'].$_configuration['code_append']."auth/external_login/newUser.ldap.php";

N.B. : LDAP users use same fields than platform users to login.
N.B. : LDAP activation adds a menu External authentication [LDAP] in "e;add or modify"e; user pages."; -$LdapDescriptionTitle = "

LDAP configuration

"; +$ChangeSharedSetting = "Change setting visibility for the other portals"; +$AllowHRSkillsManagementTitle = "Allow HR skills management"; +$AllowHRSkillsManagementComment = "Allows HR to manage skills"; +$GradebookDefaultWeightTitle = "Default weight in Gradebook"; $GradebookDefaultWeightComment = "This weight will be use in all courses by default"; -$ActiveOnly = "Active only"; -$AuthenticationSource = "Authentication"; -$RegisteredDate = "Registered"; -$Zombies = "Zombies"; \ No newline at end of file +?> \ No newline at end of file diff --git a/main/lang/english/trad4all.inc.php b/main/lang/english/trad4all.inc.php index 0e2b7694ac..5d667f1bec 100644 --- a/main/lang/english/trad4all.inc.php +++ b/main/lang/english/trad4all.inc.php @@ -1060,7 +1060,7 @@ $CourseCodeAlreadyExistExplained = "When a course code is duplicated, the databa $CantDeleteReadonlyFiles = "Cannot delete files that are configured in read-only mode."; $Uploaded = "Uploaded."; $Saved = "Saved."; -$GotoCourse = "Go to the course"; +$Reset = "Reset"; $EmailSentFromDokeos = "E-mail sent from the platform"; $InfoAboutLastDoneAdvanceAndNextAdvanceNotDone = "Information about the last finished step and the next unfinished one."; $LatexCode = "LaTeX code"; @@ -1219,4 +1219,5 @@ $InputNameHere = "Enter name here"; $Reload = "Reload"; $TimeSpentLastXDays = "Time spent the last %s days"; $TimeSpentBetweenXAndY = "Time spent between %s and %s"; +$GoToCourse = "Go to the course"; ?> \ No newline at end of file diff --git a/main/lang/french/admin.inc.php b/main/lang/french/admin.inc.php index 7aabd0053a..06f59d8f2e 100644 --- a/main/lang/french/admin.inc.php +++ b/main/lang/french/admin.inc.php @@ -1132,7 +1132,7 @@ $AssignCoursesToHumanResourcesManager = "Assigner des cours au directeur RH"; $TimezoneValueTitle = "Zone de temps"; $TimezoneValueComment = "Ceci est la zone de temps configurée pour ce portail. Si vous ne configurez pas de zone de temps, la zone de temps du serveur sera utilisée. Si vous configurez une zone de temps, tous les temps de cette plateforme seront basés sur cette zone de temps. Ce"; $UseUsersTimezoneTitle = "Utiliser les zones de temps utilisateurs"; -$UseUsersTimezoneComment = "Activer la possibilité pour les utilisateurs de sélectionner leur zone horaire. Le champ de zone horaire doit être rendu visible et modifiable dans les options de profiling du panneau d'administration avant que les utilisateurs ne puissent choisir leur propre zone. +$UseUsersTimezoneComment = "Activer la possibilité pour les utilisateurs de sélectionner leur zone horaire. Le champ de zone horaire doit être rendu visible et modifiable dans les options de profiling du panneau d'administration avant que les utilisateurs ne puissent choisir leur propre zone. Une fois configurée, les utilisateurs pourront voir toutes les heures du portail (heure de remise des travaux, évènements, etc) converties dans leur propre zone horaire."; $FieldTypeTimezone = "Zone horaire"; $AssignedSessionsHaveBeenUpdatedSuccessfully = "Les sessions assignées ont été mises à jour"; @@ -1304,9 +1304,9 @@ $EnabledImageMapsTitle = "Activer les cartes sur images"; $EnabledImageMapsComment = "Activer le bouton pour ajouter des cartes sur image. Ceci vous permettra d'associer des adresses URL à des zones d'une image, générant ainsi des zones interactives."; $CourseTool = "Outil de cours"; $BigBlueButtonEnableTitle = "Outil de vidéoconférence BigBlueButton"; -$BigBlueButtonEnableComment = "Choisissez si vous désirez activer l'outil de vidéoconférence BigBlueButton. Une fois activé, il apparaît comme un outil de cours additionnel dans toutes les pages d'accueil de cours, et les enseignants peuvent lancer une conférence à tout moment. Les étudiants ne peuvent pas lancer de conférence, seulement en rejoindre une. -Si vous n'avez pas de serveur BigBlueButton fonctionnel, veuillez en installer un ou vous adresser aux fournisseurs officiels de Chamilo pour pouvoir bénéficier de cette fonctionnalité. -BigBlueButton est un logiciel libre et gratuit. Son installation requiert des compétences techniques particulières, ce qui demande un travail considérable et peut résulter coûteux si vous ne disposez pas desdites compétences. +$BigBlueButtonEnableComment = "Choisissez si vous désirez activer l'outil de vidéoconférence BigBlueButton. Une fois activé, il apparaît comme un outil de cours additionnel dans toutes les pages d'accueil de cours, et les enseignants peuvent lancer une conférence à tout moment. Les étudiants ne peuvent pas lancer de conférence, seulement en rejoindre une. +Si vous n'avez pas de serveur BigBlueButton fonctionnel, veuillez en installer un ou vous adresser aux fournisseurs officiels de Chamilo pour pouvoir bénéficier de cette fonctionnalité. +BigBlueButton est un logiciel libre et gratuit. Son installation requiert des compétences techniques particulières, ce qui demande un travail considérable et peut résulter coûteux si vous ne disposez pas desdites compétences. Dans la logique du développement durable de notre projet, nous vous offrons la possibilité d'installer vous-même la solution ou de vous faire aider par des professionnels à l'expérience démontrée."; $BigBlueButtonHostTitle = "Adresse du serveur BigBlueButton"; $BigBlueButtonHostComment = "Veuillez indiquer l'adresse du serveur BigBlueButton. Ceci peut être localhost, une adresse IP (par exemple 192.168.13.54 ou un nom de domaine (par exemple my.video.com)."; @@ -1331,8 +1331,8 @@ $IncludeAsciiMathMlComment = "Activez ce paramètre si vous désirez pouvoir aff $CourseHideToolsTitle = "Cacher des outils par rapport aux enseignants"; $CourseHideToolsComment = "Sélectionnez les outils que vous désirez cacher des enseignants. Cette option interdira l'accès à l'outil."; $MoveUserStats = "Déplacer les résultats utilisateurs dans/vers une session"; -$CompareUserResultsBetweenCoursesAndCoursesInASession = "Cet outil avancé vous permet d'améliorer le suivi des résultats utilisateurs lorsque vous changez d'une méthodologie de purs cours ver une méthodologie de sessions (ou cycles de cours). Dans la plupart des cas, vous n'aurez pas besoin de cet outil.
-Sur cet écran, vous pouvez comparer les résultats des utilisateurs entre un contexte de cours isolé et un contexte de session.
+$CompareUserResultsBetweenCoursesAndCoursesInASession = "Cet outil avancé vous permet d'améliorer le suivi des résultats utilisateurs lorsque vous changez d'une méthodologie de purs cours ver une méthodologie de sessions (ou cycles de cours). Dans la plupart des cas, vous n'aurez pas besoin de cet outil.
+Sur cet écran, vous pouvez comparer les résultats des utilisateurs entre un contexte de cours isolé et un contexte de session.
Une fois que vous vous êtes décidé sur le meilleur contexte au sein duquel devrait exister le suivi des utilisateurs (score des exercices et suivi des parcours), vous pourrez déplacer ce suivi d'un cours vers une session."; $PDFExportWatermarkEnableTitle = "Activer les filigranes dans les exports PDF"; $PDFExportWatermarkEnableComment = "En activant cette fonctionnalité, vous pourrez utiliser une image ou un texte comme filigranne qui sera ajouté aux documents exportés en PDF."; @@ -1387,8 +1387,8 @@ $EnableAccessibilityFontResizeTitle = "Redimensionnement des caractères"; $EnableAccessibilityFontResizeComment = "Activer cette option montrera une série d'options de redimensionnement des caractères dans le coin supérieur-droit de votre campus. Celles-ci permettront aux personnes à déficience visuelle de lire leurs contenus de cours plus facilement."; $GlobalEvent = "Évènement global"; $SearchEnabledTitle = "Recherche full-text"; -$SearchEnabledComment = "Cette fonctionnalité vous permet d'indexer la plupart des documents envoyés sur votre portail, et ainsi fournir à vos utilisateurs une fonctionnalité complète de recherche de contenus.
-Cette fonctionnalité n'indexera pas les documents qui ont déjà été envoyés, c'est pourquoi il est important de l'activer au début d'une implémentarion.
+$SearchEnabledComment = "Cette fonctionnalité vous permet d'indexer la plupart des documents envoyés sur votre portail, et ainsi fournir à vos utilisateurs une fonctionnalité complète de recherche de contenus.
+Cette fonctionnalité n'indexera pas les documents qui ont déjà été envoyés, c'est pourquoi il est important de l'activer au début d'une implémentarion.
Une fois activée, une boîte de recherche apparaîtra dans la liste de cours des utilisateurs. La recherche sur un terme spécifique générera une liste des documents, exercices ou sujets de forum correspondants, filtrés selon la disponibilité de ces contenus pour les utilisateurs."; $SpecificSearchFieldsAvailable = "Champs de recherche personnalisables disponibles"; $XapianModuleInstalled = "Module Xapian installé"; @@ -1506,6 +1506,4 @@ $CasUserAddLastnameAttributeComment = "Enregistrer le nom de famille CAS de l'ut $ShowAdminToolbarTitle = "Afficher la barre d'administration"; $ShowAdminToolbarComment = "Affiche une barre d'outils globale au sommet de la page aux utilisateurs des rôles désignés. Cette barre d'outils, très similaire à celles de Wordpress et de Google, peut considérablement accélérer certaines opérations complexes et augmente l'espace disponible pour les contenus de cours, mais elle pourrait rendre certains utilisateurs confus."; $FirstLetterCourseTitle = "Première lettre (title)"; -$LdapDescriptionComment = "

  • Authentification LDAP :
    Voir I. ci-dessous pour configurer LDAP
    Voir II. ci-dessous pour activer l'authentification LDAP


  • Mise à jour des attributs de l'utilisateur, auprès du serveur LDAP,après une authentification CAS (voir configurationde CAS ) :
    Voir I. ci-dessous pour configurer LDAP
    L'authentification est gérée par CAS, il n'est pas nécessaired'activer l'authentification LDAP dans ce cas.


I. Configuration des paramètres du serveur LDAP

Éditez le fichier main/auth/external_login/ldap.conf.php
-> Mettez à jour les informations de configuration LDAP du tableau $extldap_config
Les paramètres sont
  • base domain string (ex : 'base_dn' => 'DC=cblue,DC=be')
  • admin distinguished name (ex : 'admin_dn' =>'CN=admin,dc=cblue,dc=be')
  • admin password (ex : 'admin_password' => '123456')
  • ldap host (ex : 'host' => array('1.2.3.4', '2.3.4.5', '3.4.5.6'))
  • filter (ex : 'filter' => '')
  • port (ex : 'port' => 389)
  • protocol version (2 or 3) (ex : 'protocol_version' =>3)
  • user_search (ex : 'user_search' => 'sAMAccountName=%username%')
  • encoding (ex : 'encoding' => 'UTF-8')
  • update_userinfo (ex : 'update_userinfo' => true)
-> Mettez à jour les informations de correspondances entre les attributsLDAP et les champs utilisateurs Chamilo du tableau $extldap_user_correspondance
Le tableau est de la forme : <chamilo_field> =>>ldap_field>
Sa structure est détaillée dans le fichiermain/auth/external_login/ldap.conf.php


II. Activation de l'authentification LDAP

Éditez le fichier main/inc/conf/configuration.php
-> Décommenter les lignes
$extAuthSource["extldap"]["login"] =$_configuration['root_sys'].$_configuration['code_append']."auth/external_login/login.ldap.php";
$extAuthSource["extldap"]["newUser"] =$_configuration['root_sys'].$_configuration['code_append']."auth/external_login/newUser.ldap.php";

Notes : les utilisateurs authentifiés par LDAP saisissent leur login et motde passe dans les même champs que les utilisateurs locaux à la plate forme.
Notes : activer l'authentification LDAP ajoute un menu Externalauthentification [LDAP] dans l'interface d'ajout et de modification d'unutilisateur."; -$LdapDescriptionTitle = "

Configuration de LDAP

"; ?> \ No newline at end of file diff --git a/main/lang/spanish/admin.inc.php b/main/lang/spanish/admin.inc.php index 7b8c3bbcba..ed4354351f 100644 --- a/main/lang/spanish/admin.inc.php +++ b/main/lang/spanish/admin.inc.php @@ -1537,6 +1537,8 @@ $AllowBrowserSnifferComment = "Esto activará un investigador de las capacidades $EnableWamiRecordTitle = "Activar Wami-recorder"; $EnableWamiRecordComment = "Wami-recorder es una herramienta de grabación de voz sobre Flash"; $ChangeSharedSetting = "Cambiar visibilidad de la configuración para los otros portales"; +$AllowHRSkillsManagementTitle = "Permitir al perfil RRHH administrar las competencias"; +$AllowHRSkillsManagementComment = "El usuario podrá crear, editar competencias"; $GradebookDefaultWeightTitle = "Peso total por defecto en la herramienta \"Evaluaciones\""; $GradebookDefaultWeightComment = "Este peso será utilizado en todos los cursos"; ?> \ No newline at end of file diff --git a/main/lang/spanish/gradebook.inc.php b/main/lang/spanish/gradebook.inc.php index cea6066c59..06ddb6b4a9 100644 --- a/main/lang/spanish/gradebook.inc.php +++ b/main/lang/spanish/gradebook.inc.php @@ -228,4 +228,8 @@ $SelectGradebook = "Seleccionar evaluación"; $CheckYourGradingModelValues = "Compruebe sus valores de modelo de evaluación"; $SkillsAchievedWhenAchievingThisGradebook = "Competencias obtenidas al lograr esta evaluación"; $AddGradebook = "Añadir evaluación"; +$SelectGradeModel = "Seleccionar un modelo de calificación"; +$AllMustWeight100 = "La suma debe ser de 100"; +$Components = "Componentes"; +$OnlyActiveWhenThereAreAnyComponents = "Esta opción está habilitada si tiene evaluaciones o categorías"; ?> \ No newline at end of file diff --git a/main/lang/spanish/trad4all.inc.php b/main/lang/spanish/trad4all.inc.php index 91b2852dfd..b2daef339b 100644 --- a/main/lang/spanish/trad4all.inc.php +++ b/main/lang/spanish/trad4all.inc.php @@ -1062,7 +1062,7 @@ $CourseCodeAlreadyExistExplained = "Cuando un código de curso se duplica, el si $CantDeleteReadonlyFiles = "No se puede eliminar los archivos que están configurados en modo de sólo lectura"; $Uploaded = "Subido."; $Saved = "Guardado."; -$GotoCourse = "Ir al curso"; +$Reset = "Reinicializar"; $EmailSentFromDokeos = "Correo electrónico enviado desde la plataforma"; $InfoAboutLastDoneAdvanceAndNextAdvanceNotDone = "Información sobre el último paso terminado y el siguiente sin terminar."; $LatexCode = "Código LaTeX"; @@ -1222,4 +1222,7 @@ recordar)"; $WamiStartRecorder = "Inicie la grabación pulsando el micrófono y deténgala pulsándolo de nuevo. Cada vez que haga esto se generará un archivo."; $InputNameHere = "Escriba el nombre aquí"; $Reload = "Recargar"; +$TimeSpentLastXDays = "Tiempo dedicado en los últimos %s días"; +$TimeSpentBetweenXAndY = "Tiempo dedicado entre el %s y el %s"; +$GoToCourse = "Ir al curso"; ?> \ No newline at end of file From f62ffc909f119befd944714cf856a53ea1389482 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 12:18:09 +0200 Subject: [PATCH 042/128] Removing gradebook_ranking fields --- main/install/db_main.sql | 12 +----------- main/install/migrate-db-1.8.8-1.9.0-pre.sql | 16 ++-------------- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/main/install/db_main.sql b/main/install/db_main.sql index 405ca59664..de57c3a5fd 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -852,17 +852,7 @@ VALUES ('allow_browser_sniffer', NULL, 'radio', 'Tuning', 'false', 'AllowBrowserSnifferTitle', 'AllowBrowserSnifferComment', NULL, NULL, 0), ('enable_wami_record',NULL,'radio','Tools','false','EnableWamiRecordTitle','EnableWamiRecordComment',NULL,NULL, 0), ('gradebook_default_weight', NULL, 'textfield', 'Gradebook', '100', 'GradebookDefaultWeightTitle', 'GradebookDefaultWeightComment', NULL, NULL, 0), -('gradebook_ranking_1', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('gradebook_ranking_2', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('gradebook_ranking_3', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('gradebook_ranking_4', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('gradebook_ranking_5', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('gradebook_ranking_6', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('gradebook_ranking_7', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('gradebook_ranking_8', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('gradebook_ranking_9', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('gradebook_ranking_10', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17733','DatabaseVersion','', NULL, NULL, 0); +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17748','DatabaseVersion','', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index 8b4088de6b..9912a0ef04 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -148,20 +148,8 @@ INSERT INTO settings_options (variable, value, display_text) VALUES ('enable_wam INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_default_weight', NULL, 'textfield', 'Gradebook', '100', 'GradebookDefaultWeightTitle', 'GradebookDefaultWeightComment', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_1', 'ranking', 'gradebook_ranking', 'Gradebook', '', 'GradebookRankingTitle', '', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_2', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_3', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_4', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_5', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_6', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_7', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_8', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_9', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1); -INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_ranking_10', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1); - -- Course ranking - -CREATE TABLE track_course_ranking (id int unsigned not null PRIMARY KEY AUTO_INCREMENT,c_id int unsigned not null, session_id int unsigned not null default 0, url_id int unsigned not null default 0, accesses int unsigned not null default 0, total_score int unsigned not null default 0, users int unsigned not null default 0, creation_date datetime not null); +CREATE TABLE track_course_ranking (id int unsigned not null PRIMARY KEY AUTO_INCREMENT, c_id int unsigned not null, session_id int unsigned not null default 0, url_id int unsigned not null default 0, accesses int unsigned not null default 0, total_score int unsigned not null default 0, users int unsigned not null default 0, creation_date datetime not null); ALTER TABLE track_course_ranking ADD INDEX idx_tcc_cid (c_id); ALTER TABLE track_course_ranking ADD INDEX idx_tcc_sid (session_id); @@ -196,7 +184,7 @@ DELETE FROM settings_current WHERE variable = 'use_document_title'; DELETE FROM settings_options WHERE variable = 'use_document_title'; -- Do not move this query -UPDATE settings_current SET selected_value = '1.9.0.17733' WHERE variable = 'chamilo_database_version'; +UPDATE settings_current SET selected_value = '1.9.0.17748' WHERE variable = 'chamilo_database_version'; -- xxSTATSxx ALTER TABLE track_e_exercices ADD COLUMN questions_to_check TEXT NOT NULL DEFAULT ''; From 1e6d64a08c6a8439a9738c5ad3ae6723ac7ce3b6 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 12:20:17 +0200 Subject: [PATCH 043/128] Removing gradebook_ranking attributes now we use a table grade_model and grade_components --- main/admin/grade_models.php | 2 +- main/admin/settings.lib.php | 4 +- main/admin/settings.php | 4 +- main/gradebook/index.php | 78 ++++++++++++++++++++----------------- 4 files changed, 47 insertions(+), 41 deletions(-) diff --git a/main/admin/grade_models.php b/main/admin/grade_models.php index 5447951b39..084bd15022 100644 --- a/main/admin/grade_models.php +++ b/main/admin/grade_models.php @@ -6,7 +6,7 @@ */ // Language files that need to be included. -$language_file = array('admin'); +$language_file = array('admin', 'gradebook'); $cidReset = true; require_once '../inc/global.inc.php'; diff --git a/main/admin/settings.lib.php b/main/admin/settings.lib.php index d31cd6fadc..6c45adad06 100644 --- a/main/admin/settings.lib.php +++ b/main/admin/settings.lib.php @@ -1230,7 +1230,7 @@ function generate_settings_form($settings, $settings_by_access_list) { $form->addElement('select', $row['variable'], array(get_lang($row['title']), get_lang($row['comment'])), call_user_func('select_'.$row['variable']), $hideme); $default_values[$row['variable']] = $row['selected_value']; break; - case 'gradebook_ranking': + /*case 'gradebook_ranking': $value = explode('::', $row['selected_value']); $form->addElement('text', 'gradebook_display['.$row['variable'].'][text]', array(get_lang($row['title']), get_lang($row['comment'])), array('class' => 'span1', 'value' => $value[0]), $hideme); @@ -1239,7 +1239,7 @@ function generate_settings_form($settings, $settings_by_access_list) { $renderer = $form -> defaultRenderer(); $renderer->setElementTemplate(' {label}
{element} %= ', 'gradebook_display['.$row['variable'].'][text]'); $renderer->setElementTemplate(' {element}

', 'gradebook_display['.$row['variable'].'][score]'); - break; + break;*/ case 'custom': break; } diff --git a/main/admin/settings.php b/main/admin/settings.php index 6d8918f4f8..415f499d88 100644 --- a/main/admin/settings.php +++ b/main/admin/settings.php @@ -180,13 +180,13 @@ if (!empty($_GET['category']) && !in_array($_GET['category'], array('Plugins', ' foreach ($values as $key => $value) { if (in_array($key, $settings_to_avoid)) { continue; } - //Gradebook fix + /*//Gradebook fix if ($key == 'gradebook_display') { foreach ($value as $new_key => $item) { $final_value = $item['text'].'::'.$item['score']; $result = api_set_setting($new_key, $final_value, 'ranking', null, $_configuration['access_url']); } - } + }*/ // // Treat gradebook values in separate function. //if (strpos($key, 'gradebook_score_display_custom_values') === false) { diff --git a/main/gradebook/index.php b/main/gradebook/index.php index 9839c66a06..cabc0c8713 100644 --- a/main/gradebook/index.php +++ b/main/gradebook/index.php @@ -820,48 +820,54 @@ if (isset($first_time) && $first_time==1 && api_is_allowed_to_edit(null,true)) { $obj = new GradeModel(); $grade_models = $obj->get_all(); $options = array('-1' => get_lang('none')); - foreach ($grade_models as $item) { - $options[$item['id']] = $item['name']; - } + + if (!empty($grade_models)) { + foreach ($grade_models as $item) { + $options[$item['id']] = $item['name']; + } + } $grade_model_id = $cats[0]->get_grade_model_id(); //No children if (count($cats) == 1 && empty($grade_model_id)) { - $form = new FormValidator('grade_model_settings'); - $form->addElement('select', 'grade_model', get_lang('SelectGradeModel'), $options); - $form->addElement('style_submit_button', 'submit', get_lang('Save'), 'class="save"'); + if (!empty($grade_models)) { - if ($form->validate()) { - $value = $form->exportValue('grade_model'); - $gradebook = new Gradebook(); - $gradebook->update(array('id'=> $cats[0]->get_id(), 'grade_model_id' => $value), true); - - //do something - $obj = new GradeModel(); - $components = $obj->get_components($value); - - foreach ($components as $component) { - $gradebook = new Gradebook(); - $params = array(); - - $params['name'] = $component['acronym']; - $params['description'] = $component['title']; - $params['user_id'] = api_get_user_id(); - $params['parent_id'] = $cats[0]->get_id(); - $params['weight'] = $component['percentage']; - $params['session_id'] = api_get_session_id(); - $params['course_code'] = api_get_course_id(); - $params['grade_model_id'] = api_get_session_id(); - - $gradebook->save($params); - } - - //Reloading cats - $cats = Category :: load(null, null, $course_code, null, null, $session_id, false); //already init - } else { - $form->display(); - } + $form = new FormValidator('grade_model_settings'); + $form->addElement('select', 'grade_model', get_lang('SelectGradeModel'), $options); + $form->addElement('style_submit_button', 'submit', get_lang('Save'), 'class="save"'); + + if ($form->validate()) { + $value = $form->exportValue('grade_model'); + $gradebook = new Gradebook(); + $gradebook->update(array('id'=> $cats[0]->get_id(), 'grade_model_id' => $value), true); + + //do something + $obj = new GradeModel(); + $components = $obj->get_components($value); + + foreach ($components as $component) { + $gradebook = new Gradebook(); + $params = array(); + + $params['name'] = $component['acronym']; + $params['description'] = $component['title']; + $params['user_id'] = api_get_user_id(); + $params['parent_id'] = $cats[0]->get_id(); + $params['weight'] = $component['percentage']; + $params['session_id'] = api_get_session_id(); + $params['course_code'] = api_get_course_id(); + $params['grade_model_id'] = api_get_session_id(); + + $gradebook->save($params); + } + + //Reloading cats + $cats = Category :: load(null, null, $course_code, null, null, $session_id, false); //already init + } else { + $form->display(); + } + } } } From 3460e9492fe07e74c6c4a17c4f2910a96072e72f Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Mon, 7 May 2012 12:22:58 +0200 Subject: [PATCH 044/128] #4694 add feedback during installation, remove warnings --- main/inc/lib/database.lib.php | 4 ++-- main/install/index.php | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/main/inc/lib/database.lib.php b/main/inc/lib/database.lib.php index f41fc9cc43..1611761896 100644 --- a/main/inc/lib/database.lib.php +++ b/main/inc/lib/database.lib.php @@ -781,9 +781,9 @@ class Database { if (empty($line) && $line !== false) { $line = $caller['line']; } - $type = $owner['type']; + $type = isset($owner['type']) ? $owner['type'] : null; $function = $owner['function']; - $class = $owner['class']; + $class = isset($owner['class']) ? $owner['class'] : null; $server_type = api_get_setting('server_type'); if (!empty($line) && !empty($server_type) && $server_type != 'production') { $info = '
' .
diff --git a/main/install/index.php b/main/install/index.php
index 414f75e497..5903c81448 100644
--- a/main/install/index.php
+++ b/main/install/index.php
@@ -162,13 +162,13 @@ if (!empty($_POST['updatePath'])) {
 	$proposedUpdatePath = $_POST['updatePath'];
 }
 
-if ($_POST['step2_install'] || $_POST['step2_update_8'] || $_POST['step2_update_6']) {
-	if ($_POST['step2_install']) {
+if (@$_POST['step2_install'] || @$_POST['step2_update_8'] || @$_POST['step2_update_6']) {
+	if (@$_POST['step2_install']) {
 		$installType = 'new';
 		$_POST['step2'] = 1;
 	} else {
 		$installType = 'update';
-		if ($_POST['step2_update_8']) {
+		if (@$_POST['step2_update_8']) {
 			$emptyUpdatePath = false;
 			$proposedUpdatePath = api_add_trailing_slash(empty($_POST['updatePath']) ? api_get_path(SYS_PATH) : $_POST['updatePath']);
 			if (file_exists($proposedUpdatePath)) {
@@ -201,7 +201,7 @@ if ($_POST['step2_install'] || $_POST['step2_update_8'] || $_POST['step2_update_
 			}
 		}
 	}
-} elseif ($_POST['step1']) {
+} elseif (@$_POST['step1']) {
 	$_POST['updatePath'] = '';
 	$installType = '';
 	$updateFromConfigFile = '';
@@ -545,13 +545,13 @@ if ($encryptPassForm == '1') {
 	
 	
 
     
@@ -707,7 +707,7 @@ if ($_POST['step2']) {
Date: Mon, 7 May 2012 12:49:31 +0200 Subject: [PATCH 045/128] #4694 add feedback during installation, remove warnings --- main/inc/lib/database.lib.php | 13 ++++++++++--- main/inc/lib/main_api.lib.php | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/main/inc/lib/database.lib.php b/main/inc/lib/database.lib.php index 1611761896..a9c6b142ef 100644 --- a/main/inc/lib/database.lib.php +++ b/main/inc/lib/database.lib.php @@ -418,9 +418,16 @@ class Database { if (!isset($parameters['client_flags'])) { $parameters['client_flags'] = 0; } - return $parameters['persistent'] - ? mysql_pconnect($parameters['server'], $parameters['username'], $parameters['password'], $parameters['client_flags']) - : mysql_connect($parameters['server'], $parameters['username'], $parameters['password'], $parameters['new_link'], $parameters['client_flags']); + + $persistent = isset($parameters['persistent']) ? $parameters['persistent'] : null; + $server = isset($parameters['server']) ? $parameters['server'] : null; + $username = isset($parameters['username']) ? $parameters['username'] : null; + $password = isset($parameters['password']) ? $parameters['password'] : null; + $client_flag = isset($parameters['client_flags']) ? $parameters['client_flags'] : null; + $new_link = isset($parameters['new_link']) ? $parameters['new_link'] : null; + return $persistent + ? mysql_pconnect($server, $username, $password, $client_flags) + : mysql_connect($server, $username, $password, $new_link, $client_flags); } /** diff --git a/main/inc/lib/main_api.lib.php b/main/inc/lib/main_api.lib.php index 7f1496f37f..d8d28c6128 100644 --- a/main/inc/lib/main_api.lib.php +++ b/main/inc/lib/main_api.lib.php @@ -1062,7 +1062,7 @@ function api_get_user_info_from_username($username = '') { * Returns the current course code (string) */ function api_get_course_id() { - return $GLOBALS['_cid']; + return isset($GLOBALS['_cid']) ? $GLOBALS['_cid'] : null; } /** From 4b35f1d5bf9a8bed1a356ac9a1e5b641b6857914 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 12:59:45 +0200 Subject: [PATCH 046/128] Minor install UI changes --- main/inc/global_error_message.inc.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/main/inc/global_error_message.inc.php b/main/inc/global_error_message.inc.php index adf61ca6b1..649f12c7cd 100644 --- a/main/inc/global_error_message.inc.php +++ b/main/inc/global_error_message.inc.php @@ -84,12 +84,14 @@ if (is_int($global_error_code) && $global_error_code > 0) { $css_def = ''; foreach ($css_list as $css_item) { $css_base_chamilo_file = $root_sys.$css_item; - if (file_exists($css_base_chamilo_file)) { + if (file_exists($css_base_chamilo_file)) { $css_def .= @file_get_contents($css_base_chamilo_file); } } - $css_def = str_replace('behavior:url("/main/css/csshover3.htc");', '', $css_def); + + $css_def = str_replace("@import url('bootstrap.css');", '', $css_def); + $css_def = str_replace('behavior:url("/main/css/csshover3.htc");', '', $css_def); $css_def = str_replace('main/', $root_rel.'main/', $css_def); $css_def = str_replace('images/', $root_rel.$css_path.$theme.'images/', $css_def); $css_def = str_replace('../../img/', $root_rel.'main/img/', $css_def); @@ -122,10 +124,12 @@ if (is_int($global_error_code) && $global_error_code > 0) { $click_to_install = substr($InstallationDescription, 0, $pos); $read_installation_guide = substr($InstallationDescription, $pos + 2); $InstallationDescription = '
- -

- '.$read_installation_guide.''; +

+ + '.$read_installation_guide.' +

+ '; $global_error_message['description'] = $InstallationDescription; break; case 3: @@ -181,11 +185,10 @@ if (is_int($global_error_code) && $global_error_code > 0) { - + +
From a5b640151c402412f64c3f64d0e86b4626862ae4 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 13:22:45 +0200 Subject: [PATCH 047/128] Droping course tables during a new installation "can create attendance_sheet_log" bug --- main/inc/lib/add_course.lib.inc.php | 68 +++++++++-------------------- main/inc/lib/database.lib.php | 1 + main/install/db_main.sql | 2 +- main/install/index.php | 1 - main/install/install.lib.php | 1 - main/install/install_db.inc.php | 7 ++- 6 files changed, 27 insertions(+), 53 deletions(-) diff --git a/main/inc/lib/add_course.lib.inc.php b/main/inc/lib/add_course.lib.inc.php index 113eb07041..b6f64c27bf 100644 --- a/main/inc/lib/add_course.lib.inc.php +++ b/main/inc/lib/add_course.lib.inc.php @@ -74,21 +74,6 @@ function define_course_keys($wanted_code, $prefix_for_all = '', $prefix_for_base $try_new_fsc_id ++; $final_suffix['CourseId'] = substr(md5(uniqid(rand())), 0, 4); } - /* - if ($_configuration['single_database']) { - $query = "SHOW TABLES FROM ".$_configuration['main_database']." LIKE '".$_configuration['table_prefix'].$keys_course_db_name.$_configuration['db_glue']."%'"; - $result = Database::query($query); - } else { - $query = "SHOW DATABASES LIKE '$keys_course_db_name'"; - $result = Database::query($query); - } - - if (Database::num_rows($result)) { - $keys_are_unique = false; - $try_new_fsc_db ++; - $final_suffix['CourseDb'] = substr('_'.md5(uniqid(rand())), 0, 4); - }*/ - if (file_exists(api_get_path(SYS_COURSE_PATH).$keys_course_repository)) { $keys_are_unique = false; $try_new_fsc_dir ++; @@ -99,15 +84,9 @@ function define_course_keys($wanted_code, $prefix_for_all = '', $prefix_for_base return $keys; } } - /* - // Db name can't begin with a number. - if (stripos('abcdefghijklmnopqrstuvwxyz', $keys_course_db_name[0]) === false) { - $keys_course_db_name = $prefixAntiNumber . $keys_course_db_name; - }*/ - + $keys['currentCourseCode'] = $keys_course_code; $keys['currentCourseId'] = $keys_course_id; - //$keys['currentCourseDbName'] = $keys_course_db_name; $keys['currentCourseRepository'] = $keys_course_repository; return $keys; @@ -185,15 +164,11 @@ function get_course_tables() { $tables[]= 'tool'; $tables[]= 'tool_intro'; - - // Group tool $tables[]= 'group_info'; $tables[]= 'group_category'; $tables[]= 'group_rel_user'; $tables[]= 'group_rel_tutor'; - $tables[]= 'item_property'; - $tables[]= 'userinfo_content'; $tables[]= 'userinfo_def'; $tables[]= 'course_description'; @@ -264,7 +239,6 @@ function get_course_tables() { $tables[]= 'wiki_conf'; $tables[]= 'wiki_discuss'; $tables[]= 'wiki_mailcue'; - //$tables[]= 'audiorecorder'; $tables[]= 'course_setting'; $tables[]= 'glossary'; $tables[]= 'notebook'; @@ -276,18 +250,26 @@ function get_course_tables() { $tables[]= 'thematic'; $tables[]= 'thematic_plan'; $tables[]= 'thematic_advance'; + $tables[]= 'metadata'; - return $tables; - + return $tables; +} + +/* Executed only before create_course_tables() */ +function drop_course_tables() { + $list = get_course_tables(); + foreach ($list as $table) { + $sql = "DROP TABLE IF EXISTS ".DB_COURSE_PREFIX.$table; + Database::query($sql); + } } + /** * Creates all the necessary tables for a new course */ -function update_db_course($course_db_name = null) { - global $_configuration; - - $charset_clause = ' DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci'; - +function create_course_tables($course_db_name = null) { + global $_configuration; + $charset_clause = ' DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci'; $use_one_db = true; if ($use_one_db) { @@ -302,24 +284,19 @@ function update_db_course($course_db_name = null) { //@todo define the backticks inside those table names directly (instead of adding them afterwards) $tbl_course_homepage = $course_db_name . 'tool'; $TABLEINTROS = $course_db_name . 'tool_intro'; - - // Group tool $TABLEGROUPS = $course_db_name . 'group_info'; $TABLEGROUPCATEGORIES = $course_db_name . 'group_category'; $TABLEGROUPUSER = $course_db_name . 'group_rel_user'; $TABLEGROUPTUTOR = $course_db_name . 'group_rel_tutor'; - $TABLEITEMPROPERTY = $course_db_name . 'item_property'; - $TABLETOOLUSERINFOCONTENT = $course_db_name . 'userinfo_content'; $TABLETOOLUSERINFODEF = $course_db_name . 'userinfo_def'; - $TABLETOOLCOURSEDESC = $course_db_name . 'course_description'; $TABLETOOLAGENDA = $course_db_name . 'calendar_event'; $TABLETOOLAGENDAREPEAT = $course_db_name . 'calendar_event_repeat'; $TABLETOOLAGENDAREPEATNOT = $course_db_name . 'calendar_event_repeat_not'; $TABLETOOLAGENDAATTACHMENT = $course_db_name . 'calendar_event_attachment'; - + // Announcements $TABLETOOLANNOUNCEMENTS = $course_db_name . 'announcement'; $TABLETOOLANNOUNCEMENTSATTACHMENT = $course_db_name . 'announcement_attachment'; @@ -360,8 +337,7 @@ function update_db_course($course_db_name = null) { $TABLEQUIZQUESTION = $course_db_name . 'quiz_rel_question'; $TABLEQUIZQUESTIONLIST = $course_db_name . 'quiz_question'; $TABLEQUIZANSWERSLIST = $course_db_name . 'quiz_answer'; - $TABLEQUIZQUESTIONOPTION = $course_db_name . 'quiz_question_option'; - + $TABLEQUIZQUESTIONOPTION = $course_db_name . 'quiz_question_option'; $table_quiz_question_category = $course_db_name . 'quiz_question_category'; $table_quiz_question_rel_category = $course_db_name . 'quiz_question_rel_category'; @@ -415,9 +391,6 @@ function update_db_course($course_db_name = null) { $TABLEWIKIDISCUSS = $course_db_name . 'wiki_discuss'; $TABLEWIKIMAILCUE = $course_db_name . 'wiki_mailcue'; - // audiorecorder - //$TABLEAUDIORECORDER = $course_db_name . 'audiorecorder'; - // Course settings $TABLESETTING = $course_db_name . 'course_setting'; @@ -437,8 +410,7 @@ function update_db_course($course_db_name = null) { // Thematic $TBL_THEMATIC = $course_db_name . 'thematic'; $TBL_THEMATIC_PLAN = $course_db_name . 'thematic_plan'; - $TBL_THEMATIC_ADVANCE = $course_db_name . 'thematic_advance'; - + $TBL_THEMATIC_ADVANCE = $course_db_name . 'thematic_advance'; $TBL_METADATA = $course_db_name . 'metadata'; $add_to_all_tables = ' c_id INT NOT NULL, '; @@ -519,7 +491,7 @@ function update_db_course($course_db_name = null) { )" . $charset_clause; Database::query($sql); - /* Forum tool */ + /* Forum tool */ // Forum Category $sql = " diff --git a/main/inc/lib/database.lib.php b/main/inc/lib/database.lib.php index f41fc9cc43..5eec8f7c56 100644 --- a/main/inc/lib/database.lib.php +++ b/main/inc/lib/database.lib.php @@ -696,6 +696,7 @@ class Database { if (strpos($query, 'c_')) { //Check if the table contains inner joins if ( + strpos($query, 'DROP TABLE IF EXISTS') === false && strpos($query, 'thematic_advance') === false && strpos($query, 'thematic_plan') === false && strpos($query, 'track_c_countries') === false && diff --git a/main/install/db_main.sql b/main/install/db_main.sql index de57c3a5fd..35f786d45f 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -1190,7 +1190,7 @@ VALUES ('cas_add_user_activate', 'extldap', 'casAddUserActivateLDAP'), ('update_user_info_cas_with_ldap', 'true', 'Yes'), ('update_user_info_cas_with_ldap', 'false', 'No'), -('teachers_can_change_score_settings', 'false', 'Yes'), +('teachers_can_change_score_settings', 'true', 'Yes'), ('teachers_can_change_score_settings', 'false', 'No'); diff --git a/main/install/index.php b/main/install/index.php index 7023998220..805ef00ceb 100644 --- a/main/install/index.php +++ b/main/install/index.php @@ -800,7 +800,6 @@ if ($_POST['step2']) { break; } } else { - set_file_folder_permissions(); database_server_connect(); diff --git a/main/install/install.lib.php b/main/install/install.lib.php index 7b8a736532..304117c1cd 100755 --- a/main/install/install.lib.php +++ b/main/install/install.lib.php @@ -2053,5 +2053,4 @@ function locking_settings() { $sql = "UPDATE $table SET access_url_locked = 1 WHERE variable = '$setting'"; Database::query($sql); } - } \ No newline at end of file diff --git a/main/install/install_db.inc.php b/main/install/install_db.inc.php index 3e60952942..3c767b2fe2 100644 --- a/main/install/install_db.inc.php +++ b/main/install/install_db.inc.php @@ -8,7 +8,8 @@ * @package chamilo.install */ -// This page can only be access through including from the install script. +/* This page is called only during a NEW chamilo installation */ +/* This page can only be access through including from the install script. */ if (!defined('SYSTEM_INSTALLATION')) { echo 'You are not allowed here!'; @@ -117,7 +118,9 @@ load_main_database($installation_settings); //Adds the c_XXX courses tables see #3910 require_once api_get_path(LIBRARY_PATH).'add_course.lib.inc.php'; -update_db_course(); + +drop_course_tables(); +create_course_tables(); load_database_script('db_stats.sql'); From 4bff54824ef40d21651da162514ba9c7c15c4d47 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 13:41:03 +0200 Subject: [PATCH 048/128] Removing variables that are already added: cas_add_user_activate, update_user_info_cas_with_ldap --- main/install/db_main.sql | 7 +------ main/install/migrate-db-1.8.8-1.9.0-pre.sql | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/main/install/db_main.sql b/main/install/db_main.sql index 35f786d45f..88cdc10050 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -852,7 +852,7 @@ VALUES ('allow_browser_sniffer', NULL, 'radio', 'Tuning', 'false', 'AllowBrowserSnifferTitle', 'AllowBrowserSnifferComment', NULL, NULL, 0), ('enable_wami_record',NULL,'radio','Tools','false','EnableWamiRecordTitle','EnableWamiRecordComment',NULL,NULL, 0), ('gradebook_default_weight', NULL, 'textfield', 'Gradebook', '100', 'GradebookDefaultWeightTitle', 'GradebookDefaultWeightComment', NULL, NULL, 0), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17748','DatabaseVersion','', NULL, NULL, 0); +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17752','DatabaseVersion','', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), @@ -1187,13 +1187,8 @@ VALUES ('allow_browser_sniffer', 'false', 'No'), ('enable_wami_record', 'true', 'Yes'), ('enable_wami_record', 'false', 'No'), -('cas_add_user_activate', 'extldap', 'casAddUserActivateLDAP'), -('update_user_info_cas_with_ldap', 'true', 'Yes'), -('update_user_info_cas_with_ldap', 'false', 'No'), ('teachers_can_change_score_settings', 'true', 'Yes'), ('teachers_can_change_score_settings', 'false', 'No'); - - UNLOCK TABLES; /* ('activate_send_event_by_mail', 'true', 'Yes'), diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index 9912a0ef04..acad86c891 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -184,7 +184,7 @@ DELETE FROM settings_current WHERE variable = 'use_document_title'; DELETE FROM settings_options WHERE variable = 'use_document_title'; -- Do not move this query -UPDATE settings_current SET selected_value = '1.9.0.17748' WHERE variable = 'chamilo_database_version'; +UPDATE settings_current SET selected_value = '1.9.0.17752' WHERE variable = 'chamilo_database_version'; -- xxSTATSxx ALTER TABLE track_e_exercices ADD COLUMN questions_to_check TEXT NOT NULL DEFAULT ''; From 1e9d8619c31c88ec30d8cad3697171cba3c8630f Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 13:41:38 +0200 Subject: [PATCH 049/128] Commenting error_log "Chamilo Notice: Could not find previous config file at ..." --- main/install/install.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/install/install.lib.php b/main/install/install.lib.php index 304117c1cd..f80f690df4 100755 --- a/main/install/install.lib.php +++ b/main/install/install.lib.php @@ -427,7 +427,7 @@ function get_config_param($param, $updatePath = '') { $updateFromConfigFile = 'claroline/inc/conf/claro_main.conf.php'; } else { // Give up recovering. - error_log('Chamilo Notice: Could not find previous config file at '.$updatePath.'main/inc/conf/configuration.php nor at '.$updatePath.'claroline/inc/conf/claro_main.conf.php in get_config_param(). Will start new config (in '.__FILE__.', line '.__LINE__.')', 0); + //error_log('Chamilo Notice: Could not find previous config file at '.$updatePath.'main/inc/conf/configuration.php nor at '.$updatePath.'claroline/inc/conf/claro_main.conf.php in get_config_param(). Will start new config (in '.__FILE__.', line '.__LINE__.')', 0); return null; } } From 44c32c9e69f79ff103f8a4457b24cdd70d93dbbc Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 13:42:18 +0200 Subject: [PATCH 050/128] Minor - cosmetic changes --- main/inc/global_error_message.inc.php | 6 ++---- main/install/install_db.inc.php | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/main/inc/global_error_message.inc.php b/main/inc/global_error_message.inc.php index 649f12c7cd..892ffb0dc1 100644 --- a/main/inc/global_error_message.inc.php +++ b/main/inc/global_error_message.inc.php @@ -120,13 +120,11 @@ if (is_int($global_error_code) && $global_error_code > 0) { $global_error_message['title'] = $InstallationTitle; if (($pos = strpos($InstallationDescription, '%s')) === false) { $InstallationDescription = 'Click to INSTALL Chamilo %s or read the installation guide'; - } - $click_to_install = substr($InstallationDescription, 0, $pos); + } $read_installation_guide = substr($InstallationDescription, $pos + 2); $InstallationDescription = '

- + '.$read_installation_guide.'

'; diff --git a/main/install/install_db.inc.php b/main/install/install_db.inc.php index 3c767b2fe2..7d5ca30958 100644 --- a/main/install/install_db.inc.php +++ b/main/install/install_db.inc.php @@ -118,8 +118,8 @@ load_main_database($installation_settings); //Adds the c_XXX courses tables see #3910 require_once api_get_path(LIBRARY_PATH).'add_course.lib.inc.php'; - drop_course_tables(); + create_course_tables(); load_database_script('db_stats.sql'); From 9113ede12baaa82f2892d6e644f5c57114ecceb0 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 14:38:22 +0200 Subject: [PATCH 051/128] Should fix bugs in gradebook due recent see #4685 --- main/gradebook/gradebook_edit_eval.php | 18 +++++--- main/gradebook/gradebook_edit_link.php | 15 +++++-- main/gradebook/lib/fe/evalform.class.php | 15 ++++--- .../gradebook/lib/fe/gradebooktable.class.php | 16 ++++--- .../lib/fe/linkaddeditform.class.php | 14 ++++--- .../gradebook/lib/gradebook_functions.inc.php | 42 ++++++++++--------- 6 files changed, 73 insertions(+), 47 deletions(-) diff --git a/main/gradebook/gradebook_edit_eval.php b/main/gradebook/gradebook_edit_eval.php index 6b75197a58..0d5e0ed974 100644 --- a/main/gradebook/gradebook_edit_eval.php +++ b/main/gradebook/gradebook_edit_eval.php @@ -27,13 +27,19 @@ if ($form->validate()) { $eval->set_user_id($values['hid_user_id']); $eval->set_course_code($values['hid_course_code']); $eval->set_category_id($values['hid_category_id']); - - $parent_cat = Category :: load($values['hid_category_id']); - $cat = Category :: load($parent_cat[0]->get_parent_id()); - $global_weight = $cat[0] -> get_weight(); - $values['weight'] = $values['weight_mask']/$global_weight*$parent_cat[0]->get_weight(); - $eval->set_weight($values['weight']); + $parent_cat = Category :: load($values['hid_category_id']); + + $final_weight = null; + if ($parent_cat[0]->get_parent_id() == 0) { + $final_weight = $values['weight_mask']; + } else { + $cat = Category :: load($parent_cat[0]->get_parent_id()); + $global_weight = $cat[0]->get_weight(); + $final_weight = $values['weight_mask']/$global_weight*$parent_cat[0]->get_weight(); + } + + $eval->set_weight($final_weight); $eval->set_max($values['max']); if (empty ($values['visible'])) { diff --git a/main/gradebook/gradebook_edit_link.php b/main/gradebook/gradebook_edit_link.php index b294409f4a..7c3e17c0e8 100644 --- a/main/gradebook/gradebook_edit_link.php +++ b/main/gradebook/gradebook_edit_link.php @@ -34,10 +34,17 @@ $form = new LinkAddEditForm(LinkAddEditForm :: TYPE_EDIT, $cats, null, $link, 'e if ($form->validate()) { $values = $form->exportValues(); $parent_cat = Category :: load($values['select_gradebook']); - $cat = Category :: load($parent_cat[0]->get_parent_id()); - $global_weight = $cat[0]->get_weight(); - $values['weight'] = $values['weight_mask']/$global_weight*$parent_cat[0]->get_weight(); - $link->set_weight($values['weight']); + + $final_weight = null; + if ($parent_cat[0]->get_parent_id() == 0) { + $final_weight = $values['weight_mask']; + } else { + $cat = Category :: load($parent_cat[0]->get_parent_id()); + $global_weight = $cat[0]->get_weight(); + $final_weight = $values['weight_mask']/$global_weight*$parent_cat[0]->get_weight(); + } + + $link->set_weight($final_weight); if (!empty($values['select_gradebook'])) { $link->set_category_id($values['select_gradebook']); diff --git a/main/gradebook/lib/fe/evalform.class.php b/main/gradebook/lib/fe/evalform.class.php index c05e59ec91..7bff50bcd2 100644 --- a/main/gradebook/lib/fe/evalform.class.php +++ b/main/gradebook/lib/fe/evalform.class.php @@ -172,7 +172,7 @@ class EvalForm extends FormValidator } usort($results_and_users, array ('EvalForm', 'sort_by_user')); - $defaults= array (); + $defaults = array(); foreach ($results_and_users as $result_and_user) { $user = $result_and_user['user']; @@ -383,10 +383,13 @@ class EvalForm extends FormValidator */ protected function build_editing_form() { $parent_cat = Category :: load($this->evaluation_object->get_category_id()); - $cat = Category :: load($parent_cat[0]->get_parent_id()); - $global_weight = $cat[0]->get_weight(); - //$values['weight'] = $values['weight_mask']/$global_weight*$parent_cat[0]->get_weight(); - $weight_mask = $global_weight*$this->evaluation_object->get_weight()/$parent_cat[0]->get_weight() ; + if ($parent_cat[0]->get_parent_id() == 0) { + $weight_mask = $this->evaluation_object->get_weight(); + } else { + $cat = Category :: load($parent_cat[0]->get_parent_id()); + $global_weight = $cat[0]->get_weight(); + $weight_mask = $global_weight*$this->evaluation_object->get_weight()/$parent_cat[0]->get_weight() ; + } $this->setDefaults(array ( 'hid_id' => $this->evaluation_object->get_id(), 'name' => $this->evaluation_object->get_name(), @@ -434,7 +437,7 @@ class EvalForm extends FormValidator if (count($all_categories) == 1) { $this->addElement('hidden', 'hid_category_id', $cat_id); - } else { + } else { $select_gradebook = $this->addElement('select', 'hid_category_id', get_lang('SelectGradebook'), array(), array('id' => 'hid_category_id')); $this->addRule('hid_category_id', get_lang('ThisFieldIsRequired'), 'nonzero'); diff --git a/main/gradebook/lib/fe/gradebooktable.class.php b/main/gradebook/lib/fe/gradebooktable.class.php index ccfed6af15..bf3be39e6b 100644 --- a/main/gradebook/lib/fe/gradebooktable.class.php +++ b/main/gradebook/lib/fe/gradebooktable.class.php @@ -215,13 +215,17 @@ class GradebookTable extends SortableTable { $row[] = $this->build_edit_column($item); } } else { - //students get the results and certificates columns - if (count($this->evals_links)>0 && $status_user!=1 ) { - $value_data = isset($data[4]) ? $data[4] : null; - if (!is_null($value_data)) { + //students get the results and certificates columns + if (count($this->evals_links) > 0 && $status_user != 1) { + $value_data = isset($data[4]) ? $data[4] : null; + if (!is_null($value_data)) { $row[] = Display::tag('h4', $value_data); - } - } + } else { + $row[] = $this->build_edit_column($item); + } + } else { + $row[] = $this->build_edit_column($item); + } } //Category added diff --git a/main/gradebook/lib/fe/linkaddeditform.class.php b/main/gradebook/lib/fe/linkaddeditform.class.php index 2b789290c6..c52042f389 100644 --- a/main/gradebook/lib/fe/linkaddeditform.class.php +++ b/main/gradebook/lib/fe/linkaddeditform.class.php @@ -112,12 +112,16 @@ class LinkAddEditForm extends FormValidator $this->addRule('weight_mask',get_lang('OnlyNumbers'),'numeric'); $this->addRule(array ('weight_mask', 'zero'), get_lang('NegativeValue'), 'compare', '>='); if ($form_type == self :: TYPE_EDIT) { - $parent_cat = Category :: load($link->get_category_id()); - $cat = Category :: load($parent_cat[0]->get_parent_id()); - $global_weight = $cat[0]->get_weight(); + $parent_cat = Category :: load($link->get_category_id()); - $values['weight'] = $link->get_weight()/$parent_cat[0]->get_weight()*$global_weight; - //$defaults['weight'] = $link->get_weight(); + if ($parent_cat[0]->get_parent_id() == 0) { + $values['weight'] = $link->get_weight(); + } else { + $cat = Category :: load($parent_cat[0]->get_parent_id()); + $global_weight = $cat[0]->get_weight(); + $values['weight'] = $link->get_weight()/$parent_cat[0]->get_weight()*$global_weight; + } + $defaults['weight_mask'] = $values['weight'] ; $defaults['select_gradebook'] = $link->get_category_id(); diff --git a/main/gradebook/lib/gradebook_functions.inc.php b/main/gradebook/lib/gradebook_functions.inc.php index 5b92ddeb27..9c5f30343d 100644 --- a/main/gradebook/lib/gradebook_functions.inc.php +++ b/main/gradebook/lib/gradebook_functions.inc.php @@ -207,26 +207,27 @@ function build_edit_icons_cat($cat, $selectcat) { $modify_icons .= ''.Display::return_icon('view_more_stats.gif', get_lang('Show'),'',ICON_SIZE_SMALL).''; - if (empty($grade_model_id) || $grade_model_id == -1) { - $modify_icons .= ''.Display::return_icon('edit.png', get_lang('Modify'),'',ICON_SIZE_SMALL).''; + if (api_is_allowed_to_edit(null, true)) { + if (empty($grade_model_id) || $grade_model_id == -1) { + $modify_icons .= ''.Display::return_icon('edit.png', get_lang('Modify'),'',ICON_SIZE_SMALL).''; + } + + $modify_icons .= ' '.Display::return_icon($visibility_icon.'.png', get_lang('Visible'),'',ICON_SIZE_SMALL).''; + + //no move ability for root categories + if ($cat->is_movable()) { + /*$modify_icons .= '  + ';*/ + } else { + //$modify_icons .= ' '; + } + + if (empty($grade_model_id) || $grade_model_id == -1) { + /*$modify_icons .= ' '. + Display::return_icon('percentage.png', get_lang('EditAllWeights'),'',ICON_SIZE_SMALL).' '; */ + } + $modify_icons .= ' '.Display::return_icon('delete.png', get_lang('DeleteAll'),'',ICON_SIZE_SMALL).''; } - - $modify_icons .= ' '.Display::return_icon($visibility_icon.'.png', get_lang('Visible'),'',ICON_SIZE_SMALL).''; - - //no move ability for root categories - if ($cat->is_movable()) { - /*$modify_icons .= '  - ';*/ - } else { - //$modify_icons .= ' '; - } - - if (empty($grade_model_id) || $grade_model_id == -1) { - /*$modify_icons .= ' '. - Display::return_icon('percentage.png', get_lang('EditAllWeights'),'',ICON_SIZE_SMALL).' '; */ - } - - $modify_icons .= ' '.Display::return_icon('delete.png', get_lang('DeleteAll'),'',ICON_SIZE_SMALL).''; return $modify_icons; } @@ -242,7 +243,8 @@ function build_edit_icons_eval($eval, $selectcat) { $eval->get_course_code(); $cat=new Category(); $message_eval=$cat->show_message_resource_delete($eval->get_course_code()); - if ($message_eval===false) { + + if ($message_eval===false && api_is_allowed_to_edit(null, true)) { $visibility_icon= ($eval->is_visible() == 0) ? 'invisible' : 'visible'; $visibility_command= ($eval->is_visible() == 0) ? 'set_visible' : 'set_invisible'; $modify_icons= ' From a251f5be3151751c30c8a6e68bd1322aa46b6524 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 14:38:43 +0200 Subject: [PATCH 052/128] Minor - removing comments --- main/admin/settings.lib.php | 10 ---------- main/admin/settings.php | 8 -------- 2 files changed, 18 deletions(-) diff --git a/main/admin/settings.lib.php b/main/admin/settings.lib.php index 6c45adad06..9a019333dc 100644 --- a/main/admin/settings.lib.php +++ b/main/admin/settings.lib.php @@ -1230,16 +1230,6 @@ function generate_settings_form($settings, $settings_by_access_list) { $form->addElement('select', $row['variable'], array(get_lang($row['title']), get_lang($row['comment'])), call_user_func('select_'.$row['variable']), $hideme); $default_values[$row['variable']] = $row['selected_value']; break; - /*case 'gradebook_ranking': - $value = explode('::', $row['selected_value']); - - $form->addElement('text', 'gradebook_display['.$row['variable'].'][text]', array(get_lang($row['title']), get_lang($row['comment'])), array('class' => 'span1', 'value' => $value[0]), $hideme); - $form->addElement('text', 'gradebook_display['.$row['variable'].'][score]', array(get_lang($row['title']), get_lang($row['comment'])), array('class' => 'span3','value' => $value[1]), $hideme); - - $renderer = $form -> defaultRenderer(); - $renderer->setElementTemplate(' {label}
{element} %= ', 'gradebook_display['.$row['variable'].'][text]'); - $renderer->setElementTemplate(' {element}

', 'gradebook_display['.$row['variable'].'][score]'); - break;*/ case 'custom': break; } diff --git a/main/admin/settings.php b/main/admin/settings.php index 415f499d88..e41c299d76 100644 --- a/main/admin/settings.php +++ b/main/admin/settings.php @@ -179,14 +179,6 @@ if (!empty($_GET['category']) && !in_array($_GET['category'], array('Plugins', ' foreach ($values as $key => $value) { if (in_array($key, $settings_to_avoid)) { continue; } - - /*//Gradebook fix - if ($key == 'gradebook_display') { - foreach ($value as $new_key => $item) { - $final_value = $item['text'].'::'.$item['score']; - $result = api_set_setting($new_key, $final_value, 'ranking', null, $_configuration['access_url']); - } - }*/ // // Treat gradebook values in separate function. //if (strpos($key, 'gradebook_score_display_custom_values') === false) { From 93cb0983e8c7b6a5064278cc466c8cd2a413dac2 Mon Sep 17 00:00:00 2001 From: Hubert Borderiou Date: Mon, 7 May 2012 15:28:38 +0200 Subject: [PATCH 053/128] Add Shibbolet and Facebook auth configuration details for Chamilo admin conf --- main/admin/settings.php | 2 ++ main/img/icons/32/facebook.png | Bin 0 -> 1138 bytes main/img/icons/32/shibboleth.png | Bin 0 -> 1253 bytes main/install/db_main.sql | 21 +++++++++++++++++++-- main/lang/english/admin.inc.php | 23 ++++++++++++++++------- main/lang/french/admin.inc.php | 23 ++++++++++++++--------- 6 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 main/img/icons/32/facebook.png create mode 100644 main/img/icons/32/shibboleth.png diff --git a/main/admin/settings.php b/main/admin/settings.php index e41c299d76..a838f3a5b8 100644 --- a/main/admin/settings.php +++ b/main/admin/settings.php @@ -312,6 +312,8 @@ $action_images['search'] = 'search.png'; $action_images['stylesheets'] = 'stylesheets.png'; $action_images['templates'] = 'template.png'; $action_images['plugins'] = 'plugins.png'; +$action_images['shibboleth'] = 'shibboleth.png'; +$action_images['facebook'] = 'facebook.png'; // Grabbing the categories. $resultcategories = api_get_settings_categories(array('stylesheets', 'Plugins', 'Templates', 'Search')); diff --git a/main/img/icons/32/facebook.png b/main/img/icons/32/facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..e2c3731bc8d8c4b2fa474086dca6ff546d6e2f1d GIT binary patch literal 1138 zcmV-&1daQNP)eT#EAa_%uguCOT)k z%;q^wa#eDvJyCl~Vw01x<70!nNo=cvrs0yV+=`T{(k!n%2U} z)#&T-ft<^Zso6+rrfG@6b%B~XREmq4w}qwHP<6CJVxB)#eyXy>K~{lIYMoGRq===} zSZRu9b(BL{hJm2aEJS&aqRM-Wu|Qs#-s0*mLTcCC=a;hIHA;4spSFXd(lkzmvAN2H zkEM>R-ifH$iJ{U`XOb~Wf6UR_OJw2Z3UI#-c>iK3aS&N^G1fuYuKk;zYEj+V6N zhLo`&HDiyg+eT-kjHcF=q{T^VsVY8g|NsAnq|=L=zMrYWqp7+_Uyn*?qN%&u`uqI# z_xgvIxRj&6h^E;5{r&v?{!ezdNnC_lcdnwY%zclzG*py_p3aJ+)L(r?@PLOP4OOyP&@6JEmiZ9P>uAOY3Za}-z2{Le%;>pp;c*m78!=lMC;(4!#N z%@*iIDN4LsKIeHC&@bh3mpD70&o3)QdQl5XJg)1a$eq)O=li(GNj0R$9ff+(hT-=Q1_OT| zgZo2{7RmHH^5ViCzNd% zBjnDNC+6t8$j#c?ZM)r`w8&&`H5gdCxrsc_n|}ou08e-1N0m8l@Bjb+07*qoM6N<$ Ef<}xt7XSbN literal 0 HcmV?d00001 diff --git a/main/img/icons/32/shibboleth.png b/main/img/icons/32/shibboleth.png new file mode 100644 index 0000000000000000000000000000000000000000..5c0ca2dfec294ee596c20da45030bc6917b6f592 GIT binary patch literal 1253 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+7#jk7LR^pRiTLv6>z<9i>tduXp7xoVDf!+&V``A}@87>) z+zgo5oAJ|AB|ppW`ODS+PKy4FRG8W6^&?YeMXA`brArPSJysYNdM#7x*mA8upVEI^ zReSmJ)vjGTS5KK*n3+}>AoaUb^v_e@4g-_9GlG7VOPxQJm7}fp_{o#ockcEE__sHd zESiyfvRUNkY{ApPa(AY3UTYSeJ9~OZYs+RIx$V-*Keq|Jtd=-4gFD1Px+qHHO{R>G zo}s6U^Rp>J=cH85nW;Zs!#Jf(V)BHxTwA3t3RCdjEg-z>Rd_43OTg_r7T z^*PIR)>w2mdT!Xf_44J*SC{ht-^tUIEdBeQ)vJDyd2Q_-rgHyR@jqQHtf8PfxmIt9 zrOf$@m+n7!`0m~NucuXGyquC$$-h|0`zv2&U2WsbliIW9E_!#?Xik^z+R3J;PM%u1(4{(2 z=U|sks<7;b4gW42r#mk|4ieAa@`Eg9WR1Is*e!zNd?0NX4y~$v?wyIS3pV zX7Zdeg=3?5b zQ^gZ$y&;h&HcbynRpc+>TfcqZX|G8SuJ4{$Q9nJ1xz#d%Z=AW!<3j=Yju9#PN~;() zSd|B>`?k%UYaZm#74U!UTCr874%0j*zqGhv`K()->4}<&*S2+er^J_i>0DaYcjeAB zo3^aRKdk3xU(#;7?6XlL;?BBlYz5aYJvFMAI)7nJb*w`~;^zR~1vj#`$lw1q=UulLOyw?l<{7Ejx?wQq;w5jX#)-*UHlr03_msw${YJaZ(s z=b_I2M-w9!Z``tiX+>$qoAZx;zqxs9XS>_G-tV5O3Uxd8>1^64A-9L`nSYqg1v{ST zbOsA4(*+wg|E`+7bKjk!+^akvjV0RT?>DCIKetb6o=lx{{V}1|Z55~0c#4e|G`)Po z9n$Ub=aIQ~QF&d){|HN+!aHv`O}>aoZJ#2qP#$e0#rEt(P4&*hPetb2tP;5EoFg%_ zM6xyUhC?2!W$LVuukQa=`1)w8^c~|et-hnY!ejG?M~N;^9ZYw~EuFGUQ{wzBF8isc zcLs!-PG58ISdNyf($vjOud+^kYCa!c=(osCWU}{8he+-dZ+FLa?)?3)(tc`^M(%0f o@QlunQ)_&Z7yNi1&&bBW84?@)>&U-Lz-++a>FVdQ&MBb@081W_H2?qr literal 0 HcmV?d00001 diff --git a/main/install/db_main.sql b/main/install/db_main.sql index 88cdc10050..76905d60f3 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -852,7 +852,19 @@ VALUES ('allow_browser_sniffer', NULL, 'radio', 'Tuning', 'false', 'AllowBrowserSnifferTitle', 'AllowBrowserSnifferComment', NULL, NULL, 0), ('enable_wami_record',NULL,'radio','Tools','false','EnableWamiRecordTitle','EnableWamiRecordComment',NULL,NULL, 0), ('gradebook_default_weight', NULL, 'textfield', 'Gradebook', '100', 'GradebookDefaultWeightTitle', 'GradebookDefaultWeightComment', NULL, NULL, 0), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17752','DatabaseVersion','', NULL, NULL, 0); +('gradebook_ranking_1', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('gradebook_ranking_2', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('gradebook_ranking_3', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('gradebook_ranking_4', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('gradebook_ranking_5', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('gradebook_ranking_6', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('gradebook_ranking_7', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('gradebook_ranking_8', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('gradebook_ranking_9', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('gradebook_ranking_10', 'ranking', 'gradebook_ranking', 'Gradebook', '', '', '', NULL, NULL, 1), +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17734','DatabaseVersion','', NULL, NULL, 0); +('shibboleth_description', NULL, 'radio', 'Shibboleth', 'false', 'ShibbolethMainActivateTitle', 'ShibbolethMainActivateComment', NULL, NULL, 0), +('facebook_description', NULL, 'radio', 'Facebook', 'false', 'FacebookMainActivateTitle', 'FacebookMainActivateComment', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), @@ -1187,8 +1199,13 @@ VALUES ('allow_browser_sniffer', 'false', 'No'), ('enable_wami_record', 'true', 'Yes'), ('enable_wami_record', 'false', 'No'), -('teachers_can_change_score_settings', 'true', 'Yes'), +('cas_add_user_activate', 'extldap', 'casAddUserActivateLDAP'), +('update_user_info_cas_with_ldap', 'true', 'Yes'), +('update_user_info_cas_with_ldap', 'false', 'No'), +('teachers_can_change_score_settings', 'false', 'Yes'), ('teachers_can_change_score_settings', 'false', 'No'); + + UNLOCK TABLES; /* ('activate_send_event_by_mail', 'true', 'Yes'), diff --git a/main/lang/english/admin.inc.php b/main/lang/english/admin.inc.php index 6d5bd42976..71d8e161d4 100644 --- a/main/lang/english/admin.inc.php +++ b/main/lang/english/admin.inc.php @@ -2,7 +2,7 @@ /* for more information: see languages.txt in the lang folder. */ -$CasMainActivateComment = "Enabling CAS authentication will allow users to authenticate with their CAS credentials"; +$CasMainActivateComment = "Enabling CAS authentication will allow users to authenticate with their CAS credentials.
Go to
Plugin to add a configurable 'CAS Login' button for your Chamilo campus."; $AdminBy = "Administration by"; $AdministrationTools = "Administration"; $State = "Portal status"; @@ -1304,7 +1304,7 @@ $EnabledImageMapsTitle = "Activate Image maps"; $EnabledImageMapsComment = "Activate the button to insert Image maps. This allows you to associate URLs to areas of an image, creating hotspots."; $CourseTool = "Course tool"; $BigBlueButtonEnableTitle = "BigBlueButton videoconference tool"; -$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Students will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please set one up or ask the Chamilo official providers for a quote. +$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Students will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please set one up or ask the Chamilo official providers for a quote. BigBlueButton is a free (as in freedom *and* beer), but its installation requires a set of technical skills that might not be immediately available to all. You can install it on your own or seek professional help to assist you or do it for you. This help, however, will generate a certain cost. In the pure logic of the free software, we offer you the tools to make your work easier and recommend professionals (the Chamilo Official Providers) that will be able to help you if this were too difficult."; $BigBlueButtonHostTitle = "BigBlueButton server host"; $BigBlueButtonHostComment = "This is the name of the server where your BigBlueButton server is running. Might be localhost, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com)."; @@ -1329,8 +1329,8 @@ $IncludeAsciiMathMlComment = "Activate this setting if you want to show ASCIIMat $CourseHideToolsTitle = "Hide tools from teachers"; $CourseHideToolsComment = "Check the tools you want to hide from teachers. This will prohibit access to the tool."; $MoveUserStats = "Move users results from/to a session"; -$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.
-On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.
+$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.
+On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.
Once you are sure about what to do, you can choose to move the tracking data of the students (exercises results and learning paths tracking) from a course to a session."; $PDFExportWatermarkEnableTitle = "Enable watermark in PDF export"; $PDFExportWatermarkEnableComment = "By enabling this option, you can upload an image or a text that will be automatically added as watermark to all PDF exports of documents on the system."; @@ -1385,8 +1385,8 @@ $EnableAccessibilityFontResizeTitle = "Font resize accessibility feature"; $EnableAccessibilityFontResizeComment = "Enable this option to show a set of font resize options on the top-right side of your campus. This will allow visually impaired to read their course contents more easily."; $GlobalEvent = "Platform event"; $SearchEnabledTitle = "Fulltext search"; -$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.
-This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.
+$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.
+This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.
Once enabled, a search box will appear in the courses list of every user. Searching for a specific term will bring a list of corresponding documents, exercises or forum topics, filtered depending on the availability of these contents to the user."; $SpecificSearchFieldsAvailable = "Available custom search fields"; $XapianModuleInstalled = "Xapian module installed"; @@ -1535,7 +1535,16 @@ $EnableWamiRecordTitle = "Activate Wami-recorder"; $EnableWamiRecordComment = "Wami-recorder is a voice record tool on Flash"; $ChangeSharedSetting = "Change setting visibility for the other portals"; $AllowHRSkillsManagementTitle = "Allow HR skills management"; +$LdapDescriptionComment = "

  • LDAP authentication :
    See I. below to configure LDAP
    See II. below to activate LDAP authentication


  • Update user attributes, with LDAP data, after CAS authentication(see CAS configuration ) :
    See I. below to configure LDAP
    CAS manage user authentication, LDAP activation isn't required.


I. LDAP configuration

Edit file main/auth/external_login/ldap.conf.php
-> Edit values of array $extldap_config

Parameters are
  • base domain string (ex : 'base_dn' => 'DC=cblue,DC=be')
  • admin distinguished name (ex : 'admin_dn' =>'CN=admin,dc=cblue,dc=be')
  • admin password (ex : 'admin_password' => '123456')
  • ldap host (ex : 'host' => array('1.2.3.4', '2.3.4.5', '3.4.5.6'))
  • filter (ex : 'filter' => '')
  • port (ex : 'port' => 389)
  • protocol version (2 or 3) (ex : 'protocol_version' => 3)
  • user_search (ex : 'user_search' => 'sAMAccountName=%username%')
  • encoding (ex : 'encoding' => 'UTF-8')
  • update_userinfo (ex : 'update_userinfo' => true)
-> To update correspondences between user and LDAP attributes, edit array $extldap_user_correspondance
Array values are <chamilo_field> => >ldap_field>
Array structure is explained in file main/auth/external_login/ldap.conf.php


II. Activate LDAP authentication

Edit file main/inc/conf/configuration.php
-> Uncomment lines
$extAuthSource["extldap"]["login"] =$_configuration['root_sys'].$_configuration['code_append']."auth/external_login/login.ldap.php";
$extAuthSource["extldap"]["newUser"] =$_configuration['root_sys'].$_configuration['code_append']."auth/external_login/newUser.ldap.php";

N.B. : LDAP users use same fields than platform users to login.
N.B. : LDAP activation adds a menu External authentication [LDAP] in "add or modify" user pages."; +$LdapDescriptionTitle = "

LDAP autentication

"; $AllowHRSkillsManagementComment = "Allows HR to manage skills"; $GradebookDefaultWeightTitle = "Default weight in Gradebook"; $GradebookDefaultWeightComment = "This weight will be use in all courses by default"; -?> \ No newline at end of file +$ActiveOnly = "Active only"; +$AuthenticationSource = "Authentication"; +$RegisteredDate = "Registered"; +$Zombies = "Zombies"; +$ShibbolethMainActivateTitle = "

Shibboleth authentication

"; +$ShibbolethMainActivateComment = "

First of all, you have to configure Shibboleth for your web server.

To configure it for Chamilo
edit file main/auth/shibboleth/config/aai.class.php

Modify object $result values with the name of your Shibboleth attributes

  • $result->unique_id = 'mail';
  • $result->firstname = 'cn';
  • $result->lastname = 'uid';
  • $result->email = 'mail';
  • $result->language = '-';
  • $result->gender = '-';
  • $result->address = '-';
  • $result->staff_category = '-';
  • $result->home_organization_type = '-';
  • $result->home_organization = '-';
  • $result->affiliation = '-';
  • $result->persistent_id = '-';
  • ...

Go to Plugin to add a configurable 'Shibboleth Login' button for your Chamilo campus."; +$FacebookMainActivateTitle = "

Facebook authentication

"; +$FacebookMainActivateComment = "

First of all, you have create a Facebook Application (see https://developers.facebook.com/apps) with your Facebook account. In the Facebook Apps parameters, the site URL value should have a GET parameter 'action=fbconnect' (e.g. http://mychamilo.com/?action=fbconnect).

Then,
edit file main/auth/external_login/facebook.conf.php
and enter 'appId' and 'secret' values for $facebook_config.
Go to Plugin to add a configurable 'Facebook Login' button for your Chamilo campus."; diff --git a/main/lang/french/admin.inc.php b/main/lang/french/admin.inc.php index 06f59d8f2e..a3e4a7710a 100644 --- a/main/lang/french/admin.inc.php +++ b/main/lang/french/admin.inc.php @@ -2,7 +2,7 @@ /* for more information: see languages.txt in the lang folder. */ -$CasMainActivateComment = "Activer l'authentification CAS permettra aux utilisateurs de s'identifier à l'aide de leur compte CAS"; +$CasMainActivateComment = "Activer l'authentification CAS permettra aux utilisateurs de s'identifier à l'aide de leur compte CAS
Vous trouverez dans les Plugin un bouton 'Login CAS', parametrable, qui s'ajoutera sur la page d'accueil de votre campus Chamilo."; $AdminBy = "Administration par"; $AdministrationTools = "Administration"; $State = "Etat du système"; @@ -1132,7 +1132,7 @@ $AssignCoursesToHumanResourcesManager = "Assigner des cours au directeur RH"; $TimezoneValueTitle = "Zone de temps"; $TimezoneValueComment = "Ceci est la zone de temps configurée pour ce portail. Si vous ne configurez pas de zone de temps, la zone de temps du serveur sera utilisée. Si vous configurez une zone de temps, tous les temps de cette plateforme seront basés sur cette zone de temps. Ce"; $UseUsersTimezoneTitle = "Utiliser les zones de temps utilisateurs"; -$UseUsersTimezoneComment = "Activer la possibilité pour les utilisateurs de sélectionner leur zone horaire. Le champ de zone horaire doit être rendu visible et modifiable dans les options de profiling du panneau d'administration avant que les utilisateurs ne puissent choisir leur propre zone. +$UseUsersTimezoneComment = "Activer la possibilité pour les utilisateurs de sélectionner leur zone horaire. Le champ de zone horaire doit être rendu visible et modifiable dans les options de profiling du panneau d'administration avant que les utilisateurs ne puissent choisir leur propre zone. Une fois configurée, les utilisateurs pourront voir toutes les heures du portail (heure de remise des travaux, évènements, etc) converties dans leur propre zone horaire."; $FieldTypeTimezone = "Zone horaire"; $AssignedSessionsHaveBeenUpdatedSuccessfully = "Les sessions assignées ont été mises à jour"; @@ -1304,9 +1304,9 @@ $EnabledImageMapsTitle = "Activer les cartes sur images"; $EnabledImageMapsComment = "Activer le bouton pour ajouter des cartes sur image. Ceci vous permettra d'associer des adresses URL à des zones d'une image, générant ainsi des zones interactives."; $CourseTool = "Outil de cours"; $BigBlueButtonEnableTitle = "Outil de vidéoconférence BigBlueButton"; -$BigBlueButtonEnableComment = "Choisissez si vous désirez activer l'outil de vidéoconférence BigBlueButton. Une fois activé, il apparaît comme un outil de cours additionnel dans toutes les pages d'accueil de cours, et les enseignants peuvent lancer une conférence à tout moment. Les étudiants ne peuvent pas lancer de conférence, seulement en rejoindre une. -Si vous n'avez pas de serveur BigBlueButton fonctionnel, veuillez en installer un ou vous adresser aux fournisseurs officiels de Chamilo pour pouvoir bénéficier de cette fonctionnalité. -BigBlueButton est un logiciel libre et gratuit. Son installation requiert des compétences techniques particulières, ce qui demande un travail considérable et peut résulter coûteux si vous ne disposez pas desdites compétences. +$BigBlueButtonEnableComment = "Choisissez si vous désirez activer l'outil de vidéoconférence BigBlueButton. Une fois activé, il apparaît comme un outil de cours additionnel dans toutes les pages d'accueil de cours, et les enseignants peuvent lancer une conférence à tout moment. Les étudiants ne peuvent pas lancer de conférence, seulement en rejoindre une. +Si vous n'avez pas de serveur BigBlueButton fonctionnel, veuillez en installer un ou vous adresser aux fournisseurs officiels de Chamilo pour pouvoir bénéficier de cette fonctionnalité. +BigBlueButton est un logiciel libre et gratuit. Son installation requiert des compétences techniques particulières, ce qui demande un travail considérable et peut résulter coûteux si vous ne disposez pas desdites compétences. Dans la logique du développement durable de notre projet, nous vous offrons la possibilité d'installer vous-même la solution ou de vous faire aider par des professionnels à l'expérience démontrée."; $BigBlueButtonHostTitle = "Adresse du serveur BigBlueButton"; $BigBlueButtonHostComment = "Veuillez indiquer l'adresse du serveur BigBlueButton. Ceci peut être localhost, une adresse IP (par exemple 192.168.13.54 ou un nom de domaine (par exemple my.video.com)."; @@ -1331,8 +1331,8 @@ $IncludeAsciiMathMlComment = "Activez ce paramètre si vous désirez pouvoir aff $CourseHideToolsTitle = "Cacher des outils par rapport aux enseignants"; $CourseHideToolsComment = "Sélectionnez les outils que vous désirez cacher des enseignants. Cette option interdira l'accès à l'outil."; $MoveUserStats = "Déplacer les résultats utilisateurs dans/vers une session"; -$CompareUserResultsBetweenCoursesAndCoursesInASession = "Cet outil avancé vous permet d'améliorer le suivi des résultats utilisateurs lorsque vous changez d'une méthodologie de purs cours ver une méthodologie de sessions (ou cycles de cours). Dans la plupart des cas, vous n'aurez pas besoin de cet outil.
-Sur cet écran, vous pouvez comparer les résultats des utilisateurs entre un contexte de cours isolé et un contexte de session.
+$CompareUserResultsBetweenCoursesAndCoursesInASession = "Cet outil avancé vous permet d'améliorer le suivi des résultats utilisateurs lorsque vous changez d'une méthodologie de purs cours ver une méthodologie de sessions (ou cycles de cours). Dans la plupart des cas, vous n'aurez pas besoin de cet outil.
+Sur cet écran, vous pouvez comparer les résultats des utilisateurs entre un contexte de cours isolé et un contexte de session.
Une fois que vous vous êtes décidé sur le meilleur contexte au sein duquel devrait exister le suivi des utilisateurs (score des exercices et suivi des parcours), vous pourrez déplacer ce suivi d'un cours vers une session."; $PDFExportWatermarkEnableTitle = "Activer les filigranes dans les exports PDF"; $PDFExportWatermarkEnableComment = "En activant cette fonctionnalité, vous pourrez utiliser une image ou un texte comme filigranne qui sera ajouté aux documents exportés en PDF."; @@ -1387,8 +1387,8 @@ $EnableAccessibilityFontResizeTitle = "Redimensionnement des caractères"; $EnableAccessibilityFontResizeComment = "Activer cette option montrera une série d'options de redimensionnement des caractères dans le coin supérieur-droit de votre campus. Celles-ci permettront aux personnes à déficience visuelle de lire leurs contenus de cours plus facilement."; $GlobalEvent = "Évènement global"; $SearchEnabledTitle = "Recherche full-text"; -$SearchEnabledComment = "Cette fonctionnalité vous permet d'indexer la plupart des documents envoyés sur votre portail, et ainsi fournir à vos utilisateurs une fonctionnalité complète de recherche de contenus.
-Cette fonctionnalité n'indexera pas les documents qui ont déjà été envoyés, c'est pourquoi il est important de l'activer au début d'une implémentarion.
+$SearchEnabledComment = "Cette fonctionnalité vous permet d'indexer la plupart des documents envoyés sur votre portail, et ainsi fournir à vos utilisateurs une fonctionnalité complète de recherche de contenus.
+Cette fonctionnalité n'indexera pas les documents qui ont déjà été envoyés, c'est pourquoi il est important de l'activer au début d'une implémentarion.
Une fois activée, une boîte de recherche apparaîtra dans la liste de cours des utilisateurs. La recherche sur un terme spécifique générera une liste des documents, exercices ou sujets de forum correspondants, filtrés selon la disponibilité de ces contenus pour les utilisateurs."; $SpecificSearchFieldsAvailable = "Champs de recherche personnalisables disponibles"; $XapianModuleInstalled = "Module Xapian installé"; @@ -1506,4 +1506,9 @@ $CasUserAddLastnameAttributeComment = "Enregistrer le nom de famille CAS de l'ut $ShowAdminToolbarTitle = "Afficher la barre d'administration"; $ShowAdminToolbarComment = "Affiche une barre d'outils globale au sommet de la page aux utilisateurs des rôles désignés. Cette barre d'outils, très similaire à celles de Wordpress et de Google, peut considérablement accélérer certaines opérations complexes et augmente l'espace disponible pour les contenus de cours, mais elle pourrait rendre certains utilisateurs confus."; $FirstLetterCourseTitle = "Première lettre (title)"; +$ShibbolethMainActivateTitle = "

Configuration de l'authentification Shibboleth

"; +$ShibbolethMainActivateComment = "

Vous devez, en premier lieu, configurer Shibboleth pour votre serveur web. Pour le configurer pour Chamilo.

éditez le fichier main/auth/shibboleth/config/aai.class.php

Modifiez les valeurs de l'objet $result avec les nom des attributs retourné par votre serveur Shibboleth.

Les valeurs à modifier sont
  • $result->unique_id = 'mail';
  • $result->firstname = 'cn';
  • $result->lastname = 'uid';
  • $result->email = 'mail';
  • $result->language = '-';
  • $result->gender = '-';
  • $result->address = '-';
  • $result->staff_category = '-';
  • $result->home_organization_type = '-';
  • $result->home_organization = '-';
  • $result->affiliation = '-';
  • $result->persistent_id = '-';
  • ...

Vous trouverez dans les Plugin un bouton 'Login Shibboleth', parametrable, qui s'ajoutera sur la page d'accueil de votre campus Chamilo."; +$FacebookMainActivateTitle = "

Configuration de l'authentification via Facebook

"; +$FacebookMainActivateComment = "

Vous devez, en premier lieu, créer une application Facebook (cf. https://developers.facebook.com/apps) avec votre compte Facebbok. Le paramètre de l'application Facebook 'URL du site' doit comporter 'action=fbconnect' comme paramètre en GET (exemple : http://mychamilo.com/?action=fbconnect)

Ensuite,
éditez le fichier main/auth/external_login/facebook.conf.php
et entrez les valeurs 'appId' et 'secret', fournies par Facebbok, pour la variable $facebook_config.
Vous trouverez dans les Plugin un bouton 'Login Facebook', parametrable, qui s'ajoutera à la page d'accueil de votre campus Chamilo."; + ?> \ No newline at end of file From 3b29811e524b585ba692cf892e780d2a1bf400d9 Mon Sep 17 00:00:00 2001 From: Hubert Borderiou Date: Mon, 7 May 2012 15:33:09 +0200 Subject: [PATCH 054/128] Minor : correct wrong merge in install/db_main --- main/install/db_main.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/install/db_main.sql b/main/install/db_main.sql index 76905d60f3..046918d328 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -1202,7 +1202,7 @@ VALUES ('cas_add_user_activate', 'extldap', 'casAddUserActivateLDAP'), ('update_user_info_cas_with_ldap', 'true', 'Yes'), ('update_user_info_cas_with_ldap', 'false', 'No'), -('teachers_can_change_score_settings', 'false', 'Yes'), +('teachers_can_change_score_settings', 'true', 'Yes'), ('teachers_can_change_score_settings', 'false', 'No'); From ada71dddb184e9795f98429647eef91cf3e61ac9 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Mon, 7 May 2012 16:59:40 +0200 Subject: [PATCH 055/128] #4694,#4712, #4712 add feedback during installation, remove warnings Undefined variable --- main/inc/lib/database.lib.php | 1 + main/install/index.php | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/main/inc/lib/database.lib.php b/main/inc/lib/database.lib.php index a9c6b142ef..b1e8221b03 100644 --- a/main/inc/lib/database.lib.php +++ b/main/inc/lib/database.lib.php @@ -425,6 +425,7 @@ class Database { $password = isset($parameters['password']) ? $parameters['password'] : null; $client_flag = isset($parameters['client_flags']) ? $parameters['client_flags'] : null; $new_link = isset($parameters['new_link']) ? $parameters['new_link'] : null; + $client_flags = isset($parameters['client_flags']) ? $parameters['client_flags'] : null; return $persistent ? mysql_pconnect($server, $username, $password, $client_flags) : mysql_connect($server, $username, $password, $new_link, $client_flags); diff --git a/main/install/index.php b/main/install/index.php index 5903c81448..5a4e725ba2 100644 --- a/main/install/index.php +++ b/main/install/index.php @@ -491,10 +491,12 @@ if ($encryptPassForm == '1') { echo ''; $instalation_type_label = ''; - if ($installType == 'new') + if ($installType == 'new'){ $instalation_type_label = get_lang('NewInstallation'); - elseif ($installType == 'update') + }elseif ($installType == 'update') { + $update_from_version = isset($update_from_version) ? $update_from_version : null; $instalation_type_label = get_lang('UpdateFromDokeosVersion').(is_array($update_from_version) ? implode('|', $update_from_version) : ''); + } if (!empty($instalation_type_label)) { echo "

$instalation_type_label


"; } @@ -822,6 +824,7 @@ if (@$_POST['step2']) { include 'install_files.inc.php'; } $current_step = 7; + $nbr_courses = isset($nbr_courses) ? $nbr_courses : null; display_after_install_message($installType, $nbr_courses); } elseif ($_POST['step1'] || $badUpdatePath) { From 165e005e6c3373ea8e8f975229c90a0f70a2d2c0 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 17:28:33 +0200 Subject: [PATCH 056/128] Adding new setting; teachers_can_change_grade_model_settings see BT#4080 --- main/gradebook/index.php | 2 +- main/gradebook/lib/fe/catform.class.php | 2 +- main/install/db_main.sql | 8 ++++++-- main/install/migrate-db-1.8.8-1.9.0-pre.sql | 6 +++++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/main/gradebook/index.php b/main/gradebook/index.php index cabc0c8713..92f4cf8aa9 100644 --- a/main/gradebook/index.php +++ b/main/gradebook/index.php @@ -815,7 +815,7 @@ if (isset($first_time) && $first_time==1 && api_is_allowed_to_edit(null,true)) { if (!empty($cats)) { - if (api_is_allowed_to_edit(null, true)) { + if (api_is_allowed_to_edit(null, true) && api_get_setting('teachers_can_change_grade_model_settings') == 'true') { //Getting grade models $obj = new GradeModel(); $grade_models = $obj->get_all(); diff --git a/main/gradebook/lib/fe/catform.class.php b/main/gradebook/lib/fe/catform.class.php index 54535fee14..70d16dcae2 100644 --- a/main/gradebook/lib/fe/catform.class.php +++ b/main/gradebook/lib/fe/catform.class.php @@ -193,7 +193,7 @@ class CatForm extends FormValidator { $this->addElement('hidden','hid_parent_id'); $this->addElement('textarea', 'description', get_lang('Description'),array('class'=>'span3','cols' => '34')); - if (isset($this->category_object) && $this->category_object->get_parent_id() == 0) { + if (isset($this->category_object) && $this->category_object->get_parent_id() == 0 && api_get_setting('teachers_can_change_grade_model_settings') == 'true') { //Getting grade models $obj = new GradeModel(); $grade_models = $obj->get_all(); diff --git a/main/install/db_main.sql b/main/install/db_main.sql index 88cdc10050..43a5c3e808 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -852,7 +852,9 @@ VALUES ('allow_browser_sniffer', NULL, 'radio', 'Tuning', 'false', 'AllowBrowserSnifferTitle', 'AllowBrowserSnifferComment', NULL, NULL, 0), ('enable_wami_record',NULL,'radio','Tools','false','EnableWamiRecordTitle','EnableWamiRecordComment',NULL,NULL, 0), ('gradebook_default_weight', NULL, 'textfield', 'Gradebook', '100', 'GradebookDefaultWeightTitle', 'GradebookDefaultWeightComment', NULL, NULL, 0), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17752','DatabaseVersion','', NULL, NULL, 0); +('teachers_can_change_score_settings', NULL, 'radio', 'Gradebook', 'true', 'TeachersCanChangeScoreSettingsTitle', 'TeachersCanChangeScoreSettingsComment', NULL, NULL, 1), +('teachers_can_change_grade_model_settings', NULL, 'radio', 'Gradebook', 'true', 'TeachersCanChangeGradeModelSettingsTitle', 'TeachersCanChangeGradeModelSettingsComment', NULL, NULL, 1), +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17759','DatabaseVersion','', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), @@ -1188,7 +1190,9 @@ VALUES ('enable_wami_record', 'true', 'Yes'), ('enable_wami_record', 'false', 'No'), ('teachers_can_change_score_settings', 'true', 'Yes'), -('teachers_can_change_score_settings', 'false', 'No'); +('teachers_can_change_score_settings', 'false', 'No'), +('teachers_can_change_grade_model_settings', 'true', 'Yes'), +('teachers_can_change_grade_model_settings', 'false', 'No'); UNLOCK TABLES; /* ('activate_send_event_by_mail', 'true', 'Yes'), diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index acad86c891..1d89882058 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -96,6 +96,10 @@ INSERT INTO settings_current (variable, subkey, type, category, selected_value, INSERT INTO settings_options (variable, value, display_text) VALUES ('teachers_can_change_score_settings', 'true', 'Yes'); INSERT INTO settings_options (variable, value, display_text) VALUES ('teachers_can_change_score_settings', 'false', 'No'); +INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('teachers_can_change_grade_model_settings', NULL, 'radio', 'Gradebook', 'true', 'TeachersCanChangeGradeModelSettingsTitle', 'TeachersCanChangeGradeModelSettingsComment', NULL, NULL, 1); +INSERT INTO settings_options (variable, value, display_text) VALUES ('teachers_can_change_grade_model_settings', 'true', 'Yes'); +INSERT INTO settings_options (variable, value, display_text) VALUES ('teachers_can_change_grade_model_settings', 'false', 'No'); + INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('allow_users_to_change_email_with_no_password', NULL, 'radio', 'User', 'false', 'AllowUsersToChangeEmailWithNoPasswordTitle', 'AllowUsersToChangeEmailWithNoPasswordComment', NULL, NULL, 0); INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_users_to_change_email_with_no_password', 'true', 'Yes'); INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_users_to_change_email_with_no_password', 'false', 'No'); @@ -184,7 +188,7 @@ DELETE FROM settings_current WHERE variable = 'use_document_title'; DELETE FROM settings_options WHERE variable = 'use_document_title'; -- Do not move this query -UPDATE settings_current SET selected_value = '1.9.0.17752' WHERE variable = 'chamilo_database_version'; +UPDATE settings_current SET selected_value = '1.9.0.17759' WHERE variable = 'chamilo_database_version'; -- xxSTATSxx ALTER TABLE track_e_exercices ADD COLUMN questions_to_check TEXT NOT NULL DEFAULT ''; From 1e163bdb7649666872a9b507d59cfec187d84a18 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Mon, 7 May 2012 17:28:48 +0200 Subject: [PATCH 057/128] Moving PDF exporting in a function --- main/gradebook/gradebook_flatview.php | 149 +----------------- .../gradebook/lib/gradebook_functions.inc.php | 139 ++++++++++++++++ 2 files changed, 142 insertions(+), 146 deletions(-) diff --git a/main/gradebook/gradebook_flatview.php b/main/gradebook/gradebook_flatview.php index 0e944716e5..1ffb6c5d62 100644 --- a/main/gradebook/gradebook_flatview.php +++ b/main/gradebook/gradebook_flatview.php @@ -107,152 +107,9 @@ if (isset($_GET['exportpdf'])) { $export_pdf_form = new DataForm(DataForm::TYPE_EXPORT_PDF, 'export_pdf_form', null, api_get_self().'?exportpdf=&offset='.intval($_GET['offset']).'&selectcat='.intval($_GET['selectcat']), '_blank', ''); - if ($export_pdf_form->validate()) { - - // Beginning of PDF report creation - - $printable_data = get_printable_data($cat[0], $users, $alleval, $alllinks); - $export = $export_pdf_form->exportValues(); - - // Reading report's CSS - - //$css_file = api_get_path(TO_SYS, WEB_CSS_PATH).api_get_setting('stylesheets').'/print.css'; - $css_file = api_get_path(SYS_CODE_PATH).'gradebook/print.css'; - $css = file_exists($css_file) ? @file_get_contents($css_file) : ''; - - // HTML report creation first - - $time = time(); - $course_code = trim($cat[0]->get_course_code()); - $organization = api_get_setting('Institution'); - - $displayscore = ScoreDisplay :: instance(); - $customdisplays = $displayscore->get_custom_score_display_settings(); - - if (is_array($customdisplays) && count(($customdisplays))) { - $total = array(); - foreach($customdisplays as $custom) { - $total[$custom['display']] = 0; - } - $user_results = $flatviewtable->datagen->get_data_to_graph2(); - foreach($user_results as $user_result) { - $total[$user_result[count($user_result)-1][1]]++; - } - } - - $html = ''; - - $img = api_get_path(SYS_CODE_PATH).'css/'.api_get_visual_theme().'/images/header-logo.png'; - if (file_exists($img)) { - $img = api_get_path(WEB_CODE_PATH).'css/'.api_get_visual_theme().'/images/header-logo.png'; - $html .= ""; - } else { - if (!empty($organization)) { - $html .= '

'.$organization.'

'; - } - } - $html .= '

'.get_lang('FlatView').'

'; - - $html .= ''; - - $html .= ''; - $html .= '
'; - - $html .= ''; - $session_name = api_get_session_name(api_get_session_id()); - $teacher_list = CourseManager::get_teacher_list_from_course_code_to_string($course_code); - if (!empty($session_name)) { - $html .= Display::tag('tr', Display::tag('td', get_lang('Session')).Display::tag('td', Display::tag('strong', $session_name))); - } - $html .= Display::tag('tr', Display::tag('td', get_lang('Course')).Display::tag('td', Display::tag('strong', $course_code))); - $html .= Display::tag('tr', Display::tag('td', get_lang('Date')).Display::tag('td', Display::tag('strong', api_convert_and_format_date(date('Y-m-d', time()), DATE_TIME_FORMAT_LONG)))); - $html .= Display::tag('tr', Display::tag('td', get_lang('Teacher')).Display::tag('td', Display::tag('strong', $teacher_list))); - $html .= '
'; - - if (!empty($total)) { - foreach($total as $label => $count) { - $total_custom_score = round($count/count($user_results), 2) *100; - $html .= Display::tag('tr', Display::tag('td', $label).': '.Display::tag('td', Display::tag('strong', $total_custom_score.' %'))); - } - } - $html .= '
'; - $headers = $printable_data[0]; - unset($headers[0]); - unset($headers[1]); - unset($headers[count($headers)+1]); - - foreach ($headers as $head) { - //$html .= Display::tag('tr', Display::tag('td', 'P1').Display::tag('td', Display::tag('strong', $head))); - $html .= Display::tag('tr', Display::tag('td', Display::tag('strong', $head))); - } - $html .= '

'; - - $columns = count($printable_data[0]); - $has_data = is_array($printable_data[1]) && count($printable_data[1]) > 0; - - if (api_is_western_name_order()) { - // Choosing the right person name order according to the current language. - list($printable_data[0][0], $printable_data[0][1]) = array($printable_data[0][1], $printable_data[0][0]); - if ($has_data) { - foreach ($printable_data[1] as &$printable_data_row) { - list($printable_data_row[0], $printable_data_row[1]) = array($printable_data_row[1], $printable_data_row[0]); - } - } - } - - $table = new HTML_Table(array('class' => 'data_table')); - $row = 0; - $column = 0; - foreach ($printable_data[0] as $printable_data_cell) { - $table->setHeaderContents($row, $column, $printable_data_cell); - $column++; - } - $row++; - if ($has_data) { - foreach ($printable_data[1] as &$printable_data_row) { - $column = 0; - foreach ($printable_data_row as &$printable_data_cell) { - $table->setCellContents($row, $column, $printable_data_cell); - $table->updateCellAttributes($row, $column, 'align="center"'); - $column++; - } - $table->updateRowAttributes($row, $row % 2 ? 'class="row_even"' : 'class="row_odd"', true); - $row++; - } - } else { - $column = 0; - $table->setCellContents($row, $column, get_lang('NoResults')); - $table->updateCellAttributes($row, $column, 'colspan="'.$columns.'" align="center" class="row_odd"'); - } - - $html .= $table->toHtml(); - - //echo $html;exit; - // Memory release - - unset($printable_data); - unset($table); - - // Conversion of the created HTML report to a PDF report - - $html = api_utf8_encode($html); - //@todo this is really a must? - $creator_pdf = api_utf8_encode($creator); - $title_pdf = api_utf8_encode($report_name); - $subject_pdf = api_utf8_encode(get_lang('FlatView')); - $keywods_pdf = api_utf8_encode($course_code); - - $page_format = $export['orientation'] == 'landscape' ? 'A4-L' : 'A4'; - $pdf = new PDF($page_format, $export['orientation']); - - // Sending the created PDF report to the client - $file_name = date('YmdHi_', $time); - if (!empty($course_code)) { - $file_name .= $course_code.'_'; - } - $file_name .= get_lang('FlatView').'.pdf'; - $pdf->content_to_pdf($html, $css, $file_name, api_get_course_id()); - exit; + if ($export_pdf_form->validate()) { + $params = $export_pdf_form->exportValues(); + export_pdf_flatview($cat, $users, $alleval, $alllinks, $params); } else { Display :: display_header(get_lang('ExportPDF')); } diff --git a/main/gradebook/lib/gradebook_functions.inc.php b/main/gradebook/lib/gradebook_functions.inc.php index 9c5f30343d..2f20d5ca05 100644 --- a/main/gradebook/lib/gradebook_functions.inc.php +++ b/main/gradebook/lib/gradebook_functions.inc.php @@ -208,6 +208,10 @@ function build_edit_icons_cat($cat, $selectcat) { $modify_icons .= ''.Display::return_icon('view_more_stats.gif', get_lang('Show'),'',ICON_SIZE_SMALL).''; if (api_is_allowed_to_edit(null, true)) { + + //PDF + $modify_icons .= ' '.Display::return_icon('pdf.png', get_lang('ExportToPDF'),'',ICON_SIZE_SMALL).''; + if (empty($grade_model_id) || $grade_model_id == -1) { $modify_icons .= ''.Display::return_icon('edit.png', get_lang('Modify'),'',ICON_SIZE_SMALL).''; } @@ -605,3 +609,138 @@ function get_user_certificate_content($user_id, $course_code, $is_preview = fals $new_content_html = $new_content[0].$print.''.$new_content_html; return array('content' => $new_content_html, 'variables'=>$content_html['variables']); } + + +function export_pdf_flatview($cat, $users, $alleval, $alllinks, $params = array()) { + // Beginning of PDF report creation + + $printable_data = get_printable_data($cat[0], $users, $alleval, $alllinks); + + // Reading report's CSS + $css_file = api_get_path(SYS_CODE_PATH).'gradebook/print.css'; + $css = file_exists($css_file) ? @file_get_contents($css_file) : ''; + + // HTML report creation first + $time = time(); + $course_code = trim($cat[0]->get_course_code()); + $organization = api_get_setting('Institution'); + + $displayscore = ScoreDisplay :: instance(); + $customdisplays = $displayscore->get_custom_score_display_settings(); + + $total = array(); + if (is_array($customdisplays) && count(($customdisplays))) { + foreach($customdisplays as $custom) { + $total[$custom['display']] = 0; + } + $user_results = $flatviewtable->datagen->get_data_to_graph2(); + foreach($user_results as $user_result) { + $total[$user_result[count($user_result)-1][1]]++; + } + } + + $html = ''; + + $img = api_get_path(SYS_CODE_PATH).'css/'.api_get_visual_theme().'/images/header-logo.png'; + + if (file_exists($img)) { + $img = api_get_path(WEB_CODE_PATH).'css/'.api_get_visual_theme().'/images/header-logo.png'; + $html .= ""; + } else { + if (!empty($organization)) { + $html .= '

'.$organization.'

'; + } + } + + $html .= '

'.get_lang('FlatView').'

'; + $html .= ''; + + $html .= ''; + $html .= '
'; + + $html .= ''; + $session_name = api_get_session_name(api_get_session_id()); + $teacher_list = CourseManager::get_teacher_list_from_course_code_to_string($course_code); + if (!empty($session_name)) { + $html .= Display::tag('tr', Display::tag('td', get_lang('Session')).Display::tag('td', Display::tag('strong', $session_name))); + } + $html .= Display::tag('tr', Display::tag('td', get_lang('Course')).Display::tag('td', Display::tag('strong', $course_code))); + $html .= Display::tag('tr', Display::tag('td', get_lang('Date')).Display::tag('td', Display::tag('strong', api_convert_and_format_date(date('Y-m-d', time()), DATE_TIME_FORMAT_LONG)))); + $html .= Display::tag('tr', Display::tag('td', get_lang('Teacher')).Display::tag('td', Display::tag('strong', $teacher_list))); + $html .= '
'; + + if (!empty($total)) { + foreach($total as $label => $count) { + $total_custom_score = round($count/count($user_results), 2) *100; + $html .= Display::tag('tr', Display::tag('td', $label).': '.Display::tag('td', Display::tag('strong', $total_custom_score.' %'))); + } + } + $html .= '
'; + $headers = $printable_data[0]; + unset($headers[0]); + unset($headers[1]); + unset($headers[count($headers)+1]); + + foreach ($headers as $head) { + $html .= Display::tag('tr', Display::tag('td', Display::tag('strong', $head))); + } + $html .= '

'; + + $columns = count($printable_data[0]); + $has_data = is_array($printable_data[1]) && count($printable_data[1]) > 0; + + if (api_is_western_name_order()) { + // Choosing the right person name order according to the current language. + list($printable_data[0][0], $printable_data[0][1]) = array($printable_data[0][1], $printable_data[0][0]); + if ($has_data) { + foreach ($printable_data[1] as &$printable_data_row) { + list($printable_data_row[0], $printable_data_row[1]) = array($printable_data_row[1], $printable_data_row[0]); + } + } + } + + $table = new HTML_Table(array('class' => 'data_table')); + $row = 0; + $column = 0; + foreach ($printable_data[0] as $printable_data_cell) { + $table->setHeaderContents($row, $column, $printable_data_cell); + $column++; + } + $row++; + if ($has_data) { + foreach ($printable_data[1] as &$printable_data_row) { + $column = 0; + foreach ($printable_data_row as &$printable_data_cell) { + $table->setCellContents($row, $column, $printable_data_cell); + $table->updateCellAttributes($row, $column, 'align="center"'); + $column++; + } + $table->updateRowAttributes($row, $row % 2 ? 'class="row_even"' : 'class="row_odd"', true); + $row++; + } + } else { + $column = 0; + $table->setCellContents($row, $column, get_lang('NoResults')); + $table->updateCellAttributes($row, $column, 'colspan="'.$columns.'" align="center" class="row_odd"'); + } + + $html .= $table->toHtml(); + + unset($printable_data); + unset($table); + + // Conversion of the created HTML report to a PDF report + + $html = api_utf8_encode($html); + $page_format = $params['orientation'] == 'landscape' ? 'A4-L' : 'A4'; + $pdf = new PDF($page_format, $params['orientation']); + + // Sending the created PDF report to the client + $file_name = date('YmdHi_', $time); + if (!empty($course_code)) { + $file_name .= $course_code.'_'; + } + $file_name .= get_lang('FlatView').'.pdf'; + $pdf->content_to_pdf($html, $css, $file_name, api_get_course_id()); + exit; +} \ No newline at end of file From d1841c6795df6e701aad5e00ab088fdf81538949 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Mon, 7 May 2012 16:54:26 -0500 Subject: [PATCH 058/128] Languages update + Bengali + Somali --- main/lang/bengali/accessibility.inc.php | 5 ++ main/lang/bengali/admin.inc.php | 5 ++ main/lang/bengali/agenda.inc.php | 5 ++ main/lang/bengali/announcements.inc.php | 5 ++ main/lang/bengali/blog.inc.php | 5 ++ main/lang/bengali/chat.inc.php | 5 ++ main/lang/bengali/course_description.inc.php | 5 ++ main/lang/bengali/course_home.inc.php | 5 ++ main/lang/bengali/course_info.inc.php | 5 ++ main/lang/bengali/coursebackup.inc.php | 5 ++ main/lang/bengali/courses.inc.php | 5 ++ main/lang/bengali/create_course.inc.php | 5 ++ main/lang/bengali/document.inc.php | 5 ++ main/lang/bengali/dropbox.inc.php | 5 ++ main/lang/bengali/exercice.inc.php | 5 ++ main/lang/bengali/external_module.inc.php | 5 ++ main/lang/bengali/forum.inc.php | 5 ++ main/lang/bengali/glossary.inc.php | 5 ++ main/lang/bengali/gradebook.inc.php | 5 ++ main/lang/bengali/group.inc.php | 5 ++ main/lang/bengali/help.inc.php | 5 ++ main/lang/bengali/hotspot.inc.php | 5 ++ main/lang/bengali/import.inc.php | 5 ++ main/lang/bengali/index.inc.php | 5 ++ main/lang/bengali/install.inc.php | 5 ++ main/lang/bengali/learnpath.inc.php | 5 ++ main/lang/bengali/link.inc.php | 5 ++ main/lang/bengali/md_document.inc.php | 5 ++ main/lang/bengali/md_link.inc.php | 5 ++ main/lang/bengali/md_mix.inc.php | 5 ++ main/lang/bengali/md_scorm.inc.php | 5 ++ main/lang/bengali/messages.inc.php | 5 ++ main/lang/bengali/myagenda.inc.php | 5 ++ main/lang/bengali/notebook.inc.php | 5 ++ main/lang/bengali/notification.inc.php | 5 ++ main/lang/bengali/pedaSuggest.inc.php | 5 ++ main/lang/bengali/registration.inc.php | 5 ++ main/lang/bengali/reservation.inc.php | 5 ++ main/lang/bengali/resourcelinker.inc.php | 5 ++ main/lang/bengali/scorm.inc.php | 5 ++ main/lang/bengali/scormbuilder.inc.php | 5 ++ main/lang/bengali/scormdocument.inc.php | 5 ++ main/lang/bengali/slideshow.inc.php | 5 ++ main/lang/bengali/survey.inc.php | 5 ++ main/lang/bengali/tracking.inc.php | 5 ++ main/lang/bengali/trad4all.inc.php | 5 ++ main/lang/bengali/userInfo.inc.php | 5 ++ main/lang/bengali/videoconf.inc.php | 5 ++ main/lang/bengali/wiki.inc.php | 5 ++ main/lang/bengali/work.inc.php | 5 ++ main/lang/brazilian/trad4all.inc.php | 1 - main/lang/english/admin.inc.php | 25 ++---- main/lang/finnish/exercice.inc.php | 1 + main/lang/finnish/trad4all.inc.php | 1 - main/lang/french/admin.inc.php | 23 ++--- main/lang/french/trad4all.inc.php | 1 - main/lang/galician/trad4all.inc.php | 1 - main/lang/indonesian/admin.inc.php | 88 +++++++++++++++++++ main/lang/italian/trad4all.inc.php | 1 - main/lang/latvian/trad4all.inc.php | 1 - main/lang/slovenian/admin.inc.php | 35 ++++++++ .../lang/slovenian/course_description.inc.php | 1 + main/lang/slovenian/courses.inc.php | 14 +-- main/lang/slovenian/document.inc.php | 1 + main/lang/slovenian/exercice.inc.php | 12 ++- main/lang/slovenian/gradebook.inc.php | 4 + main/lang/slovenian/index.inc.php | 26 +++--- main/lang/slovenian/registration.inc.php | 6 +- main/lang/slovenian/tracking.inc.php | 3 + main/lang/slovenian/trad4all.inc.php | 55 ++++++++++-- main/lang/slovenian/wiki.inc.php | 17 ++++ main/lang/slovenian/work.inc.php | 4 +- main/lang/somali/accessibility.inc.php | 5 ++ main/lang/somali/admin.inc.php | 5 ++ main/lang/somali/agenda.inc.php | 5 ++ main/lang/somali/announcements.inc.php | 5 ++ main/lang/somali/blog.inc.php | 5 ++ main/lang/somali/chat.inc.php | 5 ++ main/lang/somali/course_description.inc.php | 5 ++ main/lang/somali/course_home.inc.php | 5 ++ main/lang/somali/course_info.inc.php | 5 ++ main/lang/somali/coursebackup.inc.php | 5 ++ main/lang/somali/courses.inc.php | 5 ++ main/lang/somali/create_course.inc.php | 5 ++ main/lang/somali/document.inc.php | 5 ++ main/lang/somali/dropbox.inc.php | 5 ++ main/lang/somali/exercice.inc.php | 5 ++ main/lang/somali/external_module.inc.php | 5 ++ main/lang/somali/forum.inc.php | 5 ++ main/lang/somali/glossary.inc.php | 5 ++ main/lang/somali/gradebook.inc.php | 5 ++ main/lang/somali/group.inc.php | 5 ++ main/lang/somali/help.inc.php | 5 ++ main/lang/somali/hotspot.inc.php | 5 ++ main/lang/somali/import.inc.php | 5 ++ main/lang/somali/index.inc.php | 5 ++ main/lang/somali/install.inc.php | 5 ++ main/lang/somali/learnpath.inc.php | 5 ++ main/lang/somali/link.inc.php | 5 ++ main/lang/somali/md_document.inc.php | 5 ++ main/lang/somali/md_link.inc.php | 5 ++ main/lang/somali/md_mix.inc.php | 5 ++ main/lang/somali/md_scorm.inc.php | 5 ++ main/lang/somali/messages.inc.php | 5 ++ main/lang/somali/myagenda.inc.php | 5 ++ main/lang/somali/notebook.inc.php | 5 ++ main/lang/somali/notification.inc.php | 5 ++ main/lang/somali/pedaSuggest.inc.php | 5 ++ main/lang/somali/registration.inc.php | 5 ++ main/lang/somali/reservation.inc.php | 5 ++ main/lang/somali/resourcelinker.inc.php | 5 ++ main/lang/somali/scorm.inc.php | 5 ++ main/lang/somali/scormbuilder.inc.php | 5 ++ main/lang/somali/scormdocument.inc.php | 5 ++ main/lang/somali/slideshow.inc.php | 5 ++ main/lang/somali/survey.inc.php | 5 ++ main/lang/somali/tracking.inc.php | 5 ++ main/lang/somali/trad4all.inc.php | 5 ++ main/lang/somali/userInfo.inc.php | 5 ++ main/lang/somali/videoconf.inc.php | 5 ++ main/lang/somali/wiki.inc.php | 5 ++ main/lang/somali/work.inc.php | 5 ++ main/lang/turkce/admin.inc.php | 4 +- main/lang/turkce/import.inc.php | 1 - main/lang/turkce/trad4all.inc.php | 1 - 125 files changed, 753 insertions(+), 74 deletions(-) create mode 100644 main/lang/bengali/accessibility.inc.php create mode 100644 main/lang/bengali/admin.inc.php create mode 100644 main/lang/bengali/agenda.inc.php create mode 100644 main/lang/bengali/announcements.inc.php create mode 100644 main/lang/bengali/blog.inc.php create mode 100644 main/lang/bengali/chat.inc.php create mode 100644 main/lang/bengali/course_description.inc.php create mode 100644 main/lang/bengali/course_home.inc.php create mode 100644 main/lang/bengali/course_info.inc.php create mode 100644 main/lang/bengali/coursebackup.inc.php create mode 100644 main/lang/bengali/courses.inc.php create mode 100644 main/lang/bengali/create_course.inc.php create mode 100644 main/lang/bengali/document.inc.php create mode 100644 main/lang/bengali/dropbox.inc.php create mode 100644 main/lang/bengali/exercice.inc.php create mode 100644 main/lang/bengali/external_module.inc.php create mode 100644 main/lang/bengali/forum.inc.php create mode 100644 main/lang/bengali/glossary.inc.php create mode 100644 main/lang/bengali/gradebook.inc.php create mode 100644 main/lang/bengali/group.inc.php create mode 100644 main/lang/bengali/help.inc.php create mode 100644 main/lang/bengali/hotspot.inc.php create mode 100644 main/lang/bengali/import.inc.php create mode 100644 main/lang/bengali/index.inc.php create mode 100644 main/lang/bengali/install.inc.php create mode 100644 main/lang/bengali/learnpath.inc.php create mode 100644 main/lang/bengali/link.inc.php create mode 100644 main/lang/bengali/md_document.inc.php create mode 100644 main/lang/bengali/md_link.inc.php create mode 100644 main/lang/bengali/md_mix.inc.php create mode 100644 main/lang/bengali/md_scorm.inc.php create mode 100644 main/lang/bengali/messages.inc.php create mode 100644 main/lang/bengali/myagenda.inc.php create mode 100644 main/lang/bengali/notebook.inc.php create mode 100644 main/lang/bengali/notification.inc.php create mode 100644 main/lang/bengali/pedaSuggest.inc.php create mode 100644 main/lang/bengali/registration.inc.php create mode 100644 main/lang/bengali/reservation.inc.php create mode 100644 main/lang/bengali/resourcelinker.inc.php create mode 100644 main/lang/bengali/scorm.inc.php create mode 100644 main/lang/bengali/scormbuilder.inc.php create mode 100644 main/lang/bengali/scormdocument.inc.php create mode 100644 main/lang/bengali/slideshow.inc.php create mode 100644 main/lang/bengali/survey.inc.php create mode 100644 main/lang/bengali/tracking.inc.php create mode 100644 main/lang/bengali/trad4all.inc.php create mode 100644 main/lang/bengali/userInfo.inc.php create mode 100644 main/lang/bengali/videoconf.inc.php create mode 100644 main/lang/bengali/wiki.inc.php create mode 100644 main/lang/bengali/work.inc.php create mode 100644 main/lang/somali/accessibility.inc.php create mode 100644 main/lang/somali/admin.inc.php create mode 100644 main/lang/somali/agenda.inc.php create mode 100644 main/lang/somali/announcements.inc.php create mode 100644 main/lang/somali/blog.inc.php create mode 100644 main/lang/somali/chat.inc.php create mode 100644 main/lang/somali/course_description.inc.php create mode 100644 main/lang/somali/course_home.inc.php create mode 100644 main/lang/somali/course_info.inc.php create mode 100644 main/lang/somali/coursebackup.inc.php create mode 100644 main/lang/somali/courses.inc.php create mode 100644 main/lang/somali/create_course.inc.php create mode 100644 main/lang/somali/document.inc.php create mode 100644 main/lang/somali/dropbox.inc.php create mode 100644 main/lang/somali/exercice.inc.php create mode 100644 main/lang/somali/external_module.inc.php create mode 100644 main/lang/somali/forum.inc.php create mode 100644 main/lang/somali/glossary.inc.php create mode 100644 main/lang/somali/gradebook.inc.php create mode 100644 main/lang/somali/group.inc.php create mode 100644 main/lang/somali/help.inc.php create mode 100644 main/lang/somali/hotspot.inc.php create mode 100644 main/lang/somali/import.inc.php create mode 100644 main/lang/somali/index.inc.php create mode 100644 main/lang/somali/install.inc.php create mode 100644 main/lang/somali/learnpath.inc.php create mode 100644 main/lang/somali/link.inc.php create mode 100644 main/lang/somali/md_document.inc.php create mode 100644 main/lang/somali/md_link.inc.php create mode 100644 main/lang/somali/md_mix.inc.php create mode 100644 main/lang/somali/md_scorm.inc.php create mode 100644 main/lang/somali/messages.inc.php create mode 100644 main/lang/somali/myagenda.inc.php create mode 100644 main/lang/somali/notebook.inc.php create mode 100644 main/lang/somali/notification.inc.php create mode 100644 main/lang/somali/pedaSuggest.inc.php create mode 100644 main/lang/somali/registration.inc.php create mode 100644 main/lang/somali/reservation.inc.php create mode 100644 main/lang/somali/resourcelinker.inc.php create mode 100644 main/lang/somali/scorm.inc.php create mode 100644 main/lang/somali/scormbuilder.inc.php create mode 100644 main/lang/somali/scormdocument.inc.php create mode 100644 main/lang/somali/slideshow.inc.php create mode 100644 main/lang/somali/survey.inc.php create mode 100644 main/lang/somali/tracking.inc.php create mode 100644 main/lang/somali/trad4all.inc.php create mode 100644 main/lang/somali/userInfo.inc.php create mode 100644 main/lang/somali/videoconf.inc.php create mode 100644 main/lang/somali/wiki.inc.php create mode 100644 main/lang/somali/work.inc.php diff --git a/main/lang/bengali/accessibility.inc.php b/main/lang/bengali/accessibility.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/accessibility.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/admin.inc.php b/main/lang/bengali/admin.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/admin.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/agenda.inc.php b/main/lang/bengali/agenda.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/agenda.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/announcements.inc.php b/main/lang/bengali/announcements.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/announcements.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/blog.inc.php b/main/lang/bengali/blog.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/blog.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/chat.inc.php b/main/lang/bengali/chat.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/chat.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/course_description.inc.php b/main/lang/bengali/course_description.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/course_description.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/course_home.inc.php b/main/lang/bengali/course_home.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/course_home.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/course_info.inc.php b/main/lang/bengali/course_info.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/course_info.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/coursebackup.inc.php b/main/lang/bengali/coursebackup.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/coursebackup.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/courses.inc.php b/main/lang/bengali/courses.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/courses.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/create_course.inc.php b/main/lang/bengali/create_course.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/create_course.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/document.inc.php b/main/lang/bengali/document.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/document.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/dropbox.inc.php b/main/lang/bengali/dropbox.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/dropbox.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/exercice.inc.php b/main/lang/bengali/exercice.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/exercice.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/external_module.inc.php b/main/lang/bengali/external_module.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/external_module.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/forum.inc.php b/main/lang/bengali/forum.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/forum.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/glossary.inc.php b/main/lang/bengali/glossary.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/glossary.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/gradebook.inc.php b/main/lang/bengali/gradebook.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/gradebook.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/group.inc.php b/main/lang/bengali/group.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/group.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/help.inc.php b/main/lang/bengali/help.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/help.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/hotspot.inc.php b/main/lang/bengali/hotspot.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/hotspot.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/import.inc.php b/main/lang/bengali/import.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/import.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/index.inc.php b/main/lang/bengali/index.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/index.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/install.inc.php b/main/lang/bengali/install.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/install.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/learnpath.inc.php b/main/lang/bengali/learnpath.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/learnpath.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/link.inc.php b/main/lang/bengali/link.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/link.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/md_document.inc.php b/main/lang/bengali/md_document.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/md_document.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/md_link.inc.php b/main/lang/bengali/md_link.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/md_link.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/md_mix.inc.php b/main/lang/bengali/md_mix.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/md_mix.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/md_scorm.inc.php b/main/lang/bengali/md_scorm.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/md_scorm.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/messages.inc.php b/main/lang/bengali/messages.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/messages.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/myagenda.inc.php b/main/lang/bengali/myagenda.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/myagenda.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/notebook.inc.php b/main/lang/bengali/notebook.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/notebook.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/notification.inc.php b/main/lang/bengali/notification.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/notification.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/pedaSuggest.inc.php b/main/lang/bengali/pedaSuggest.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/pedaSuggest.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/registration.inc.php b/main/lang/bengali/registration.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/registration.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/reservation.inc.php b/main/lang/bengali/reservation.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/reservation.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/resourcelinker.inc.php b/main/lang/bengali/resourcelinker.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/resourcelinker.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/scorm.inc.php b/main/lang/bengali/scorm.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/scorm.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/scormbuilder.inc.php b/main/lang/bengali/scormbuilder.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/scormbuilder.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/scormdocument.inc.php b/main/lang/bengali/scormdocument.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/scormdocument.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/slideshow.inc.php b/main/lang/bengali/slideshow.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/slideshow.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/survey.inc.php b/main/lang/bengali/survey.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/survey.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/tracking.inc.php b/main/lang/bengali/tracking.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/tracking.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/trad4all.inc.php b/main/lang/bengali/trad4all.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/trad4all.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/userInfo.inc.php b/main/lang/bengali/userInfo.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/userInfo.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/videoconf.inc.php b/main/lang/bengali/videoconf.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/videoconf.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/wiki.inc.php b/main/lang/bengali/wiki.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/wiki.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/bengali/work.inc.php b/main/lang/bengali/work.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/bengali/work.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/brazilian/trad4all.inc.php b/main/lang/brazilian/trad4all.inc.php index dab8af199a..809ed41bec 100644 --- a/main/lang/brazilian/trad4all.inc.php +++ b/main/lang/brazilian/trad4all.inc.php @@ -1059,7 +1059,6 @@ $CourseCodeAlreadyExistExplained = "Quando o código do curso é duplicado, o si $CantDeleteReadonlyFiles = "Não é possível excluir os arquivos que estão configurados no modo somente-leitura."; $Uploaded = "Atualizado."; $Saved = "Salvo."; -$GotoCourse = "Ir para o curso"; $EmailSentFromDokeos = "E-mail enviado a partir da plataforma"; $InfoAboutLastDoneAdvanceAndNextAdvanceNotDone = "Informações sobre a última etapa concluída e a próxima inacabaca."; $LatexCode = "Código LaTeX"; diff --git a/main/lang/english/admin.inc.php b/main/lang/english/admin.inc.php index 71d8e161d4..28784639b6 100644 --- a/main/lang/english/admin.inc.php +++ b/main/lang/english/admin.inc.php @@ -2,7 +2,7 @@ /* for more information: see languages.txt in the lang folder. */ -$CasMainActivateComment = "Enabling CAS authentication will allow users to authenticate with their CAS credentials.
Go to Plugin to add a configurable 'CAS Login' button for your Chamilo campus."; +$CasMainActivateComment = "Enabling CAS authentication will allow users to authenticate with their CAS credentials"; $AdminBy = "Administration by"; $AdministrationTools = "Administration"; $State = "Portal status"; @@ -1304,7 +1304,7 @@ $EnabledImageMapsTitle = "Activate Image maps"; $EnabledImageMapsComment = "Activate the button to insert Image maps. This allows you to associate URLs to areas of an image, creating hotspots."; $CourseTool = "Course tool"; $BigBlueButtonEnableTitle = "BigBlueButton videoconference tool"; -$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Students will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please set one up or ask the Chamilo official providers for a quote. +$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Students will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please set one up or ask the Chamilo official providers for a quote. BigBlueButton is a free (as in freedom *and* beer), but its installation requires a set of technical skills that might not be immediately available to all. You can install it on your own or seek professional help to assist you or do it for you. This help, however, will generate a certain cost. In the pure logic of the free software, we offer you the tools to make your work easier and recommend professionals (the Chamilo Official Providers) that will be able to help you if this were too difficult."; $BigBlueButtonHostTitle = "BigBlueButton server host"; $BigBlueButtonHostComment = "This is the name of the server where your BigBlueButton server is running. Might be localhost, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com)."; @@ -1329,8 +1329,8 @@ $IncludeAsciiMathMlComment = "Activate this setting if you want to show ASCIIMat $CourseHideToolsTitle = "Hide tools from teachers"; $CourseHideToolsComment = "Check the tools you want to hide from teachers. This will prohibit access to the tool."; $MoveUserStats = "Move users results from/to a session"; -$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.
-On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.
+$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.
+On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.
Once you are sure about what to do, you can choose to move the tracking data of the students (exercises results and learning paths tracking) from a course to a session."; $PDFExportWatermarkEnableTitle = "Enable watermark in PDF export"; $PDFExportWatermarkEnableComment = "By enabling this option, you can upload an image or a text that will be automatically added as watermark to all PDF exports of documents on the system."; @@ -1385,8 +1385,8 @@ $EnableAccessibilityFontResizeTitle = "Font resize accessibility feature"; $EnableAccessibilityFontResizeComment = "Enable this option to show a set of font resize options on the top-right side of your campus. This will allow visually impaired to read their course contents more easily."; $GlobalEvent = "Platform event"; $SearchEnabledTitle = "Fulltext search"; -$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.
-This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.
+$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.
+This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.
Once enabled, a search box will appear in the courses list of every user. Searching for a specific term will bring a list of corresponding documents, exercises or forum topics, filtered depending on the availability of these contents to the user."; $SpecificSearchFieldsAvailable = "Available custom search fields"; $XapianModuleInstalled = "Xapian module installed"; @@ -1535,16 +1535,9 @@ $EnableWamiRecordTitle = "Activate Wami-recorder"; $EnableWamiRecordComment = "Wami-recorder is a voice record tool on Flash"; $ChangeSharedSetting = "Change setting visibility for the other portals"; $AllowHRSkillsManagementTitle = "Allow HR skills management"; -$LdapDescriptionComment = "

  • LDAP authentication :
    See I. below to configure LDAP
    See II. below to activate LDAP authentication


  • Update user attributes, with LDAP data, after CAS authentication(see CAS configuration ) :
    See I. below to configure LDAP
    CAS manage user authentication, LDAP activation isn't required.


I. LDAP configuration

Edit file main/auth/external_login/ldap.conf.php
-> Edit values of array $extldap_config

Parameters are
  • base domain string (ex : 'base_dn' => 'DC=cblue,DC=be')
  • admin distinguished name (ex : 'admin_dn' =>'CN=admin,dc=cblue,dc=be')
  • admin password (ex : 'admin_password' => '123456')
  • ldap host (ex : 'host' => array('1.2.3.4', '2.3.4.5', '3.4.5.6'))
  • filter (ex : 'filter' => '')
  • port (ex : 'port' => 389)
  • protocol version (2 or 3) (ex : 'protocol_version' => 3)
  • user_search (ex : 'user_search' => 'sAMAccountName=%username%')
  • encoding (ex : 'encoding' => 'UTF-8')
  • update_userinfo (ex : 'update_userinfo' => true)
-> To update correspondences between user and LDAP attributes, edit array $extldap_user_correspondance
Array values are <chamilo_field> => >ldap_field>
Array structure is explained in file main/auth/external_login/ldap.conf.php


II. Activate LDAP authentication

Edit file main/inc/conf/configuration.php
-> Uncomment lines
$extAuthSource["extldap"]["login"] =$_configuration['root_sys'].$_configuration['code_append']."auth/external_login/login.ldap.php";
$extAuthSource["extldap"]["newUser"] =$_configuration['root_sys'].$_configuration['code_append']."auth/external_login/newUser.ldap.php";

N.B. : LDAP users use same fields than platform users to login.
N.B. : LDAP activation adds a menu External authentication [LDAP] in "add or modify" user pages."; -$LdapDescriptionTitle = "

LDAP autentication

"; $AllowHRSkillsManagementComment = "Allows HR to manage skills"; $GradebookDefaultWeightTitle = "Default weight in Gradebook"; $GradebookDefaultWeightComment = "This weight will be use in all courses by default"; -$ActiveOnly = "Active only"; -$AuthenticationSource = "Authentication"; -$RegisteredDate = "Registered"; -$Zombies = "Zombies"; -$ShibbolethMainActivateTitle = "

Shibboleth authentication

"; -$ShibbolethMainActivateComment = "

First of all, you have to configure Shibboleth for your web server.

To configure it for Chamilo
edit file main/auth/shibboleth/config/aai.class.php

Modify object $result values with the name of your Shibboleth attributes

  • $result->unique_id = 'mail';
  • $result->firstname = 'cn';
  • $result->lastname = 'uid';
  • $result->email = 'mail';
  • $result->language = '-';
  • $result->gender = '-';
  • $result->address = '-';
  • $result->staff_category = '-';
  • $result->home_organization_type = '-';
  • $result->home_organization = '-';
  • $result->affiliation = '-';
  • $result->persistent_id = '-';
  • ...

Go to Plugin to add a configurable 'Shibboleth Login' button for your Chamilo campus."; -$FacebookMainActivateTitle = "

Facebook authentication

"; -$FacebookMainActivateComment = "

First of all, you have create a Facebook Application (see https://developers.facebook.com/apps) with your Facebook account. In the Facebook Apps parameters, the site URL value should have a GET parameter 'action=fbconnect' (e.g. http://mychamilo.com/?action=fbconnect).

Then,
edit file main/auth/external_login/facebook.conf.php
and enter 'appId' and 'secret' values for $facebook_config.
Go to Plugin to add a configurable 'Facebook Login' button for your Chamilo campus."; +$TeachersCanChangeScoreSettingsTitle = "Teachers can change the Gradebook score settings"; +$TeachersCanChangeScoreSettingsComment = "When editing the Gradebook settings"; +?> \ No newline at end of file diff --git a/main/lang/finnish/exercice.inc.php b/main/lang/finnish/exercice.inc.php index 53ac52bb55..f424f2af85 100644 --- a/main/lang/finnish/exercice.inc.php +++ b/main/lang/finnish/exercice.inc.php @@ -209,6 +209,7 @@ $StudentEmail = "Sähköposti"; $CourseName = "Kurssin nimi"; $HotspotDescription = "Nyt klikkaa: (...)"; $ExamSheetVCC = "Tehtävä tarkistettu"; +$AttemptVCC = "Tehtäväsi on tarkistettu/kommentoitu."; $DearStudentEmailIntroduction = "Hyvä Opiskelija,"; $ExerciseFinished = "Harjoitus valmis"; $DisableResults = "Älä näytä tuloksia oppilaille"; diff --git a/main/lang/finnish/trad4all.inc.php b/main/lang/finnish/trad4all.inc.php index 8f99fddbe9..35160d69c8 100644 --- a/main/lang/finnish/trad4all.inc.php +++ b/main/lang/finnish/trad4all.inc.php @@ -830,7 +830,6 @@ $AllDone = "Kaikki tehty"; $Blogs = "Blogit"; $Postpone = "Lykkää"; $Saved = "Tallennettu"; -$GotoCourse = "Mene kurssille"; $NextBis = "Seuraava"; $Prev = "Edellinen"; $UserRoles = "Käyttäjä roolit"; diff --git a/main/lang/french/admin.inc.php b/main/lang/french/admin.inc.php index a3e4a7710a..06f59d8f2e 100644 --- a/main/lang/french/admin.inc.php +++ b/main/lang/french/admin.inc.php @@ -2,7 +2,7 @@ /* for more information: see languages.txt in the lang folder. */ -$CasMainActivateComment = "Activer l'authentification CAS permettra aux utilisateurs de s'identifier à l'aide de leur compte CAS
Vous trouverez dans les Plugin un bouton 'Login CAS', parametrable, qui s'ajoutera sur la page d'accueil de votre campus Chamilo."; +$CasMainActivateComment = "Activer l'authentification CAS permettra aux utilisateurs de s'identifier à l'aide de leur compte CAS"; $AdminBy = "Administration par"; $AdministrationTools = "Administration"; $State = "Etat du système"; @@ -1132,7 +1132,7 @@ $AssignCoursesToHumanResourcesManager = "Assigner des cours au directeur RH"; $TimezoneValueTitle = "Zone de temps"; $TimezoneValueComment = "Ceci est la zone de temps configurée pour ce portail. Si vous ne configurez pas de zone de temps, la zone de temps du serveur sera utilisée. Si vous configurez une zone de temps, tous les temps de cette plateforme seront basés sur cette zone de temps. Ce"; $UseUsersTimezoneTitle = "Utiliser les zones de temps utilisateurs"; -$UseUsersTimezoneComment = "Activer la possibilité pour les utilisateurs de sélectionner leur zone horaire. Le champ de zone horaire doit être rendu visible et modifiable dans les options de profiling du panneau d'administration avant que les utilisateurs ne puissent choisir leur propre zone. +$UseUsersTimezoneComment = "Activer la possibilité pour les utilisateurs de sélectionner leur zone horaire. Le champ de zone horaire doit être rendu visible et modifiable dans les options de profiling du panneau d'administration avant que les utilisateurs ne puissent choisir leur propre zone. Une fois configurée, les utilisateurs pourront voir toutes les heures du portail (heure de remise des travaux, évènements, etc) converties dans leur propre zone horaire."; $FieldTypeTimezone = "Zone horaire"; $AssignedSessionsHaveBeenUpdatedSuccessfully = "Les sessions assignées ont été mises à jour"; @@ -1304,9 +1304,9 @@ $EnabledImageMapsTitle = "Activer les cartes sur images"; $EnabledImageMapsComment = "Activer le bouton pour ajouter des cartes sur image. Ceci vous permettra d'associer des adresses URL à des zones d'une image, générant ainsi des zones interactives."; $CourseTool = "Outil de cours"; $BigBlueButtonEnableTitle = "Outil de vidéoconférence BigBlueButton"; -$BigBlueButtonEnableComment = "Choisissez si vous désirez activer l'outil de vidéoconférence BigBlueButton. Une fois activé, il apparaît comme un outil de cours additionnel dans toutes les pages d'accueil de cours, et les enseignants peuvent lancer une conférence à tout moment. Les étudiants ne peuvent pas lancer de conférence, seulement en rejoindre une. -Si vous n'avez pas de serveur BigBlueButton fonctionnel, veuillez en installer un ou vous adresser aux fournisseurs officiels de Chamilo pour pouvoir bénéficier de cette fonctionnalité. -BigBlueButton est un logiciel libre et gratuit. Son installation requiert des compétences techniques particulières, ce qui demande un travail considérable et peut résulter coûteux si vous ne disposez pas desdites compétences. +$BigBlueButtonEnableComment = "Choisissez si vous désirez activer l'outil de vidéoconférence BigBlueButton. Une fois activé, il apparaît comme un outil de cours additionnel dans toutes les pages d'accueil de cours, et les enseignants peuvent lancer une conférence à tout moment. Les étudiants ne peuvent pas lancer de conférence, seulement en rejoindre une. +Si vous n'avez pas de serveur BigBlueButton fonctionnel, veuillez en installer un ou vous adresser aux fournisseurs officiels de Chamilo pour pouvoir bénéficier de cette fonctionnalité. +BigBlueButton est un logiciel libre et gratuit. Son installation requiert des compétences techniques particulières, ce qui demande un travail considérable et peut résulter coûteux si vous ne disposez pas desdites compétences. Dans la logique du développement durable de notre projet, nous vous offrons la possibilité d'installer vous-même la solution ou de vous faire aider par des professionnels à l'expérience démontrée."; $BigBlueButtonHostTitle = "Adresse du serveur BigBlueButton"; $BigBlueButtonHostComment = "Veuillez indiquer l'adresse du serveur BigBlueButton. Ceci peut être localhost, une adresse IP (par exemple 192.168.13.54 ou un nom de domaine (par exemple my.video.com)."; @@ -1331,8 +1331,8 @@ $IncludeAsciiMathMlComment = "Activez ce paramètre si vous désirez pouvoir aff $CourseHideToolsTitle = "Cacher des outils par rapport aux enseignants"; $CourseHideToolsComment = "Sélectionnez les outils que vous désirez cacher des enseignants. Cette option interdira l'accès à l'outil."; $MoveUserStats = "Déplacer les résultats utilisateurs dans/vers une session"; -$CompareUserResultsBetweenCoursesAndCoursesInASession = "Cet outil avancé vous permet d'améliorer le suivi des résultats utilisateurs lorsque vous changez d'une méthodologie de purs cours ver une méthodologie de sessions (ou cycles de cours). Dans la plupart des cas, vous n'aurez pas besoin de cet outil.
-Sur cet écran, vous pouvez comparer les résultats des utilisateurs entre un contexte de cours isolé et un contexte de session.
+$CompareUserResultsBetweenCoursesAndCoursesInASession = "Cet outil avancé vous permet d'améliorer le suivi des résultats utilisateurs lorsque vous changez d'une méthodologie de purs cours ver une méthodologie de sessions (ou cycles de cours). Dans la plupart des cas, vous n'aurez pas besoin de cet outil.
+Sur cet écran, vous pouvez comparer les résultats des utilisateurs entre un contexte de cours isolé et un contexte de session.
Une fois que vous vous êtes décidé sur le meilleur contexte au sein duquel devrait exister le suivi des utilisateurs (score des exercices et suivi des parcours), vous pourrez déplacer ce suivi d'un cours vers une session."; $PDFExportWatermarkEnableTitle = "Activer les filigranes dans les exports PDF"; $PDFExportWatermarkEnableComment = "En activant cette fonctionnalité, vous pourrez utiliser une image ou un texte comme filigranne qui sera ajouté aux documents exportés en PDF."; @@ -1387,8 +1387,8 @@ $EnableAccessibilityFontResizeTitle = "Redimensionnement des caractères"; $EnableAccessibilityFontResizeComment = "Activer cette option montrera une série d'options de redimensionnement des caractères dans le coin supérieur-droit de votre campus. Celles-ci permettront aux personnes à déficience visuelle de lire leurs contenus de cours plus facilement."; $GlobalEvent = "Évènement global"; $SearchEnabledTitle = "Recherche full-text"; -$SearchEnabledComment = "Cette fonctionnalité vous permet d'indexer la plupart des documents envoyés sur votre portail, et ainsi fournir à vos utilisateurs une fonctionnalité complète de recherche de contenus.
-Cette fonctionnalité n'indexera pas les documents qui ont déjà été envoyés, c'est pourquoi il est important de l'activer au début d'une implémentarion.
+$SearchEnabledComment = "Cette fonctionnalité vous permet d'indexer la plupart des documents envoyés sur votre portail, et ainsi fournir à vos utilisateurs une fonctionnalité complète de recherche de contenus.
+Cette fonctionnalité n'indexera pas les documents qui ont déjà été envoyés, c'est pourquoi il est important de l'activer au début d'une implémentarion.
Une fois activée, une boîte de recherche apparaîtra dans la liste de cours des utilisateurs. La recherche sur un terme spécifique générera une liste des documents, exercices ou sujets de forum correspondants, filtrés selon la disponibilité de ces contenus pour les utilisateurs."; $SpecificSearchFieldsAvailable = "Champs de recherche personnalisables disponibles"; $XapianModuleInstalled = "Module Xapian installé"; @@ -1506,9 +1506,4 @@ $CasUserAddLastnameAttributeComment = "Enregistrer le nom de famille CAS de l'ut $ShowAdminToolbarTitle = "Afficher la barre d'administration"; $ShowAdminToolbarComment = "Affiche une barre d'outils globale au sommet de la page aux utilisateurs des rôles désignés. Cette barre d'outils, très similaire à celles de Wordpress et de Google, peut considérablement accélérer certaines opérations complexes et augmente l'espace disponible pour les contenus de cours, mais elle pourrait rendre certains utilisateurs confus."; $FirstLetterCourseTitle = "Première lettre (title)"; -$ShibbolethMainActivateTitle = "

Configuration de l'authentification Shibboleth

"; -$ShibbolethMainActivateComment = "

Vous devez, en premier lieu, configurer Shibboleth pour votre serveur web. Pour le configurer pour Chamilo.

éditez le fichier main/auth/shibboleth/config/aai.class.php

Modifiez les valeurs de l'objet $result avec les nom des attributs retourné par votre serveur Shibboleth.

Les valeurs à modifier sont
  • $result->unique_id = 'mail';
  • $result->firstname = 'cn';
  • $result->lastname = 'uid';
  • $result->email = 'mail';
  • $result->language = '-';
  • $result->gender = '-';
  • $result->address = '-';
  • $result->staff_category = '-';
  • $result->home_organization_type = '-';
  • $result->home_organization = '-';
  • $result->affiliation = '-';
  • $result->persistent_id = '-';
  • ...

Vous trouverez dans les Plugin un bouton 'Login Shibboleth', parametrable, qui s'ajoutera sur la page d'accueil de votre campus Chamilo."; -$FacebookMainActivateTitle = "

Configuration de l'authentification via Facebook

"; -$FacebookMainActivateComment = "

Vous devez, en premier lieu, créer une application Facebook (cf. https://developers.facebook.com/apps) avec votre compte Facebbok. Le paramètre de l'application Facebook 'URL du site' doit comporter 'action=fbconnect' comme paramètre en GET (exemple : http://mychamilo.com/?action=fbconnect)

Ensuite,
éditez le fichier main/auth/external_login/facebook.conf.php
et entrez les valeurs 'appId' et 'secret', fournies par Facebbok, pour la variable $facebook_config.
Vous trouverez dans les Plugin un bouton 'Login Facebook', parametrable, qui s'ajoutera à la page d'accueil de votre campus Chamilo."; - ?> \ No newline at end of file diff --git a/main/lang/french/trad4all.inc.php b/main/lang/french/trad4all.inc.php index b0d42f4ed2..7629d5c2af 100644 --- a/main/lang/french/trad4all.inc.php +++ b/main/lang/french/trad4all.inc.php @@ -1057,7 +1057,6 @@ $CourseCodeAlreadyExistExplained = "Lorsqu'un code de cours est dupliqué, le sy $CantDeleteReadonlyFiles = "Impossible de supprimer des fichiers qui sont en mode lecture seule."; $Uploaded = "Envoyé."; $Saved = "Sauvegardé."; -$GotoCourse = "Aller au cours"; $EmailSentFromDokeos = "E-mail envoyé depuis la plateforme"; $InfoAboutLastDoneAdvanceAndNextAdvanceNotDone = "Information au sujet de la dernière étape clôturée et de la suivante non clôturée."; $LatexCode = "Code LaTeX"; diff --git a/main/lang/galician/trad4all.inc.php b/main/lang/galician/trad4all.inc.php index 05b2b6c1f7..cdbd88f987 100644 --- a/main/lang/galician/trad4all.inc.php +++ b/main/lang/galician/trad4all.inc.php @@ -1063,7 +1063,6 @@ $CourseCodeAlreadyExistExplained = "Cando un código de curso se publica, o sist $CantDeleteReadonlyFiles = "Non se pode eliminar os arquivos que están configuraos en modo de só lectura."; $Uploaded = "Subido"; $Saved = "Gardado"; -$GotoCourse = "Ir ao curso"; $EmailSentFromDokeos = "Correo electrónico enviado desde a plataforma"; $InfoAboutLastDoneAdvanceAndNextAdvanceNotDone = "Información sobre o último paso terminado e o seguinte sen rematar."; $LatexCode = "Código LaTex"; diff --git a/main/lang/indonesian/admin.inc.php b/main/lang/indonesian/admin.inc.php index 574dbe8310..e4e0961cc3 100644 --- a/main/lang/indonesian/admin.inc.php +++ b/main/lang/indonesian/admin.inc.php @@ -416,3 +416,91 @@ $MakeAvailable = "Buat menjadi tersedia"; $MakeUnavailable = "Buat tidak tersedia"; $Stylesheets = "Style sheets"; $DefaultDokeosStyle = "Style Chamilo Default"; +$ShowIconsInNavigationsMenuComment = "Apakah menu navigasi menampilkan ikon tool yang berbeda?"; +$Plugin = "Plugin"; +$MainMenu = "Menu Utama"; +$MainMenuLogged = "Menu Utama setelah login"; +$Banner = "Banner"; +$ImageResizeTitle = "Resize gambar-gambar yang di-upload user"; +$ImageResizeComment = "Gambar-gambar user dapat di-resize pada saat di-upload jika PHP di-compiled dengan GD library. Jika GD tidak tersedia, setting ini akan diabaikan."; +$MaxImageWidthTitle = "Ukuran lebar maksimum gambar user"; +$MaxImageWidthComment = "Lebar maksimum dalam pixel gambarnya user. Setting ini berlaku jika gambar user di-set untuk di-resized pada saat di-upload."; +$MaxImageHeightTitle = "Ukuran tinggi maksimum gambar user"; +$MaxImageHeightComment = "Tinng maksimum (dalam pixel) ukuran gambarnya user. Setting ini berlaku jika gambar user di-set untuk di-resize pada saat di-upload."; +$YourVersionNotUpToDate = "Versi anda tidak up-to-date"; +$YourVersionIs = "Versi anda adalah"; +$PleaseVisitDokeos = "Silahkan kunjungi Chamilo"; +$VersionUpToDate = "Versi anda up-to-date"; +$ConnectSocketError = "Kesalahan koneksi soket"; +$SocketFunctionsDisabled = "Koneksi soket dimatikan"; +$ShowEmailAddresses = "Tampilkan alamat email"; +$ShowEmailAddressesComment = "Tampilkan alamat email ke user"; +$LatestVersionIs = "Versi terkini adalah"; +$langConfigureExtensions = "Konfigur layanan tersebut"; +$langActiveExtensions = "Aktivasi layanan ini"; +$langVisioconf = "Visio-conference"; +$langVisioconfDescription = "Chamilo Live Conferencing® merupakan alat standar untuk visioconfrence yang menawarkan: menampilkan diapos, whiteboard untuk menggambar dan menulis, audio/video duplex, dan chat. Ini membutuhkan Flash® player dan menyediakan 3 model : satu-ke-satu, satu-ke-banyak, dan banyak-ke-banyak."; +$langPpt2lp = "PowerPoint2LearningPath"; +$langPpt2lpDescription = "PowerPoint2LearningPath menyediakan alat transformasi presentasi Powerpoint ke suatu Learning Path dengan beberapa klik."; +$langBandWidthStatistics = "Statistik Bandwidth"; +$langBandWidthStatisticsDescription = "MRTG menyediakan statistik canggih tentang server selama 24 jam terakhir."; +$ServerStatistics = "Statistik server"; +$langServerStatisticsDescription = "AWStats menyediakan statistik platform anda: pengunjung, page views, referers ..."; +$SearchEngine = "Mesin Pencari Full Text"; +$langSearchEngineDescription = "Mesin Pencari Full Text menyediakan alat pencari kata ke dalam flatform. Peng-index-an konten harian akan menjamin kualitas pencarian."; +$langListSession = "Daftar Sesi"; +$AddSession = "Tambah sesi"; +$langImportSessionListXMLCSV = "Import sesi ke format XML/CSV"; +$ExportSessionListXMLCSV = "Eksport sesi dalam format XML/CSV"; +$SessionName = "Nama sesi"; +$langNbCourses = "Kode Mata Kuliah"; +$DateStart = "Tanggal Mulai"; +$DateEnd = "Tanggal Selesai"; +$CoachName = "Nama Pelatih"; +$SessionList = "Daftar Sesi"; +$SessionNameIsRequired = "Nama dibutuhkan untuk suatu sesi"; +$NextStep = "Langkah berikutnya"; +$keyword = "Kata Kunci"; +$Confirm = "Konfirmasi"; +$UnsubscribeUsersFromCourse = "Keluarkan user dari Mata Kuliah"; +$MissingClassName = "Nama klas hilang"; +$ClassNameExists = "Nama klas sudah ada"; +$ImportCSVFileLocation = "Lokasi impor file CSV"; +$ClassesCreated = "Klas telah dibuat"; +$ErrorsWhenImportingFile = "Error pada saat mengimport file"; +$ServiceActivated = "Layanan diaktivasi"; +$ActivateExtension = "Layanan aktif"; +$InvalidExtension = "Ektensi tidak syah"; +$VersionCheckExplanation = "Agar dimungkinkan pemeriksaan versi otomatis, anda harus mendaftarkan kampus anda ke chamilo.com. Informasi yang diperoleh dengan mengklik tombol ini adalah untuk penggunaan internal dan hnya data agregat yang tersedia bagi umum (jumlah total kampus, jumlah total mata kuliah chamilo, jumlah total siswa. ...) (Lihat http://www.chamilo.org/stats/. Jika mendaftar, maka institusi anda muncul dalam daftar dunia http://www.chamilo.org/community.php.. Jika institusi anda tidak ingin tampil dalam daftar anda dapat menconteng kotak cek di bawah ini. Pendaftaran mudah: anda hanya mengklik tombol ini
"; +$AfterApproval = "Setelah disetujui"; +$StudentViewEnabledTitle = "Bolehkan tampilan siswa"; +$StudentViewEnabledComment = "Bolehkan tampilan siswa yang memungkinkan pengajar atau admin melihat kuliah seperti yang dilihat siswa"; +$TimeLimitWhosonlineTitle = "Batas waktu di WhoIsOnline"; +$TimeLimitWhosonlineComment = "Batas waktu ini menentukan berapa lama (detik) setelah aksi terakhir pemakai akan dianggap *online*"; +$ExampleMaterialCourseCreationTitle = "Materi contoh tentang pembuatan kuliah"; +$ExampleMaterialCourseCreationComment = "Buat materi contoh otomatis saat membuat kuliah baru"; +$AccountValidDurationTitle = "Validitas akun"; +$AccountValidDurationComment = "Akun pemakai valid selama sekian hari ini setelah dibuat"; +$UseSessionModeTitle = "Gunakan mode sesi"; +$UseSessionModeComment = "Sesi memungkinkan cara penanganan kuliah yang berbeda; kuliah akan memiliki kreator, pelatih, dan siswa. Setiap pelatih memberikan kuliah selama jangka waktu tertentu, yang disebut *sesi*, kepada siswa"; +$HomepageViewActivity = "Tampilan aktivitas"; +$HomepageView2column = "Tampilan dua kolom"; +$HomepageView3column = "Tampilan tiga kolom"; +$AllowUserHeadings = "Bolehkan kop pemakai"; +$IconsOnly = "Ikon saja"; +$TextOnly = "Teks saja"; +$IconsText = "Ikon dan teks"; +$EnableToolIntroductionTitle = "Bolehkan memakai tool"; +$EnableToolIntroductionComment = "Bolehkan pengantar pada setiap laman tool"; +$BreadCrumbsCourseHomepageTitle = "Navigasi laman kuliah"; +$BreadCrumbsCourseHomepageComment = "Navigasi (breadcrumb) adalah sistem navigasi tautan horizontal yang biasanya muncul di kiri atas halaman Anda. Opsi ini memilih apa yang Anda inginkan muncul di breadcrumb pada laman kuliah"; +$Comment = "Komentar"; +$Version = "Versi"; +$LoginPageMainArea = "Area utama halaman login"; +$LoginPageMenu = "Menu halaman login"; +$CampusHomepageMainArea = "Area utama laman kampus"; +$CampusHomepageMenu = "Menu laman kampus"; +$MyCoursesMainArea = "Area utama kuliah"; +$MyCoursesMenu = "Menu kuliah"; +$Header = "Kop"; +?> \ No newline at end of file diff --git a/main/lang/italian/trad4all.inc.php b/main/lang/italian/trad4all.inc.php index 0b65e1db0c..3d370be62f 100644 --- a/main/lang/italian/trad4all.inc.php +++ b/main/lang/italian/trad4all.inc.php @@ -1064,7 +1064,6 @@ $CourseCodeAlreadyExistExplained = "I codici di corso duplicati saranno bloccati $CantDeleteReadonlyFiles = "I file marcati come di sola lettura non possono essere eliminati"; $Uploaded = "Caricato"; $Saved = "Salvato"; -$GotoCourse = "Vai al corso"; $EmailSentFromDokeos = "email inviata dalla piattaforma"; $InfoAboutLastDoneAdvanceAndNextAdvanceNotDone = "Informazioni su passi completati e sul primo da completare"; $LatexCode = "Codice LaTeX"; diff --git a/main/lang/latvian/trad4all.inc.php b/main/lang/latvian/trad4all.inc.php index c42ef5cc56..ed36e9c71f 100644 --- a/main/lang/latvian/trad4all.inc.php +++ b/main/lang/latvian/trad4all.inc.php @@ -1062,7 +1062,6 @@ $CourseCodeAlreadyExistExplained = "Datu bÄzes sistÄ“ma pÄrbauda kursa kodu, v $CantDeleteReadonlyFiles = "Nevar izdzÄ“st failu, kas konfigurÄ“ts tikai lasÄ«Å¡anas režīmÄ"; $Uploaded = "AugÅ¡upielÄdÄ“ts"; $Saved = "SaglabÄts"; -$GotoCourse = "Doties uz Kursu"; $EmailSentFromDokeos = "E - vÄ“stule, no platformas ir nosÅ«tÄ«ta"; $InfoAboutLastDoneAdvanceAndNextAdvanceNotDone = "InformÄcija par pÄ“dÄ“jo pabeigto soli un nÄkoÅ¡o nepabeigto soli"; $LatexCode = "LaTEX kods"; diff --git a/main/lang/slovenian/admin.inc.php b/main/lang/slovenian/admin.inc.php index 9b7e1e17e6..c7606165fd 100644 --- a/main/lang/slovenian/admin.inc.php +++ b/main/lang/slovenian/admin.inc.php @@ -1471,6 +1471,8 @@ $AllowTeacherChangeGradebookGradingModelTitle = "Dovoli uÄitelju spremembo ocen $AllowTeacherChangeGradebookGradingModelComment = "Z dovoljenjem dovoljujete uÄitelju izbiro modela ocenjevanja, ki ga uporabi v svojem teÄaju. Spremembe uveljavlja uÄitelj znotraj orodja redovalnice teÄaja."; $NumberOfSubEvaluations = "Å tevilo pod-ocenjevanj"; $AddNewModel = "Dodaj nov model"; +$GroupParentship = "StarÅ¡evstvo skupine"; +$NoParentship = "Brez starÅ¡evstva"; $NoCertificate = "Ni certifikatov"; $ShowDocumentPreviewTitle = "Prikaži predogled dokumenta"; $ShowDocumentPreviewComment = "Prikaz predogleda dokumentov v orodju dokumentov omogoÄa vpogled v njegovo vsebino brez nalaganja nove strani. Uporaba predogleda lahko, pri majhnih zaslonskih resolucijah in pri uporabi starejÅ¡ih brskalnikov, rezultira v nestabilnemu delovanju."; @@ -1498,4 +1500,37 @@ $CasUserAddLastnameAttributeTitle = "Dodaj CAS priimek"; $CasUserAddLastnameAttributeComment = "Dodaj CAS priimek pri registracij novega uporabnika"; $ShowAdminToolbarTitle = "Prikaži administratorjevo orodno vrstico"; $ShowAdminToolbarComment = "Prikaže globalno orodno vrstico na vrhu strani za izbrane vloge uporabnikov.Ta orodna vrstica, podobna orodni vrstici, znani iz storitev Wordpress in Google, omogoÄa pohitritev dostopa za izvedbo doloÄenih opravil in prihranek pri prostoru, sicer namenjenu uÄnim vsebinam."; +$AddInMenu = "Dodaj v meni"; +$AllowUsersToChangeEmailWithNoPasswordTitle = "Dovoli uporabnikom spremembo e-poÅ¡tnega naslova brez uporabe gesla"; +$AllowUsersToChangeEmailWithNoPasswordComment = "V primeru spreminjanja informacije o uporabniÅ¡kem raÄunu"; +$EnableHelpLinkTitle = "OmogoÄi povezavo na pomoÄ"; +$EnableHelpLinkComment = "Povezava na pomoÄ se nahaja v desnem zgornjem robu zaslona"; +$BackToAdmin = "Nazaj na upravljanje"; +$AllowGlobalChatTitle = "OmogoÄi globalni klepet"; +$HeaderExtraContentTitle = "Dodatna vsebina v glavi strani"; +$HeaderExtraContentComment = "Dodate lahko lastno HTML kodo, kot so npr. meta oznake, ..."; +$FooterExtraContentTitle = "Dodatna vsebina v nogi strani"; +$AllowGlobalChatComment = "Klepet je omogoÄen za vse aktivne uporabnike platforme"; +$FooterExtraContentComment = "Dodate lahko lastno HTML kodo, kot so npr. meta oznake, ..."; +$CopyOnlySessionItems = "Kopiraj zgolj elemente seje"; +$FirstLetterCourseTitle = "Prva Ärka naziva teÄaja"; +$UsersFoundInOtherPortals = "Uporabniki najdeni v drugih portalih"; +$AddUserToMyURL = "Dodaj uporabnika v moj portal"; +$UsersDeleted = "Uporabniki so bili odstranjeni"; +$UsersAdded = "Uporabniki so bili dodani"; +$PluginArea = "VtiÄi"; +$NoConfigurationSettingsForThisPlugin = "Za ta vtiÄ nastavitve niso na voljo"; +$Regions = "Regije"; +$CoursesDefaultCreationVisibilityTitle = "Privzeta vidnost teÄajev"; +$CoursesDefaultCreationVisibilityComment = "Privzeta vidnost/dostopnost do teÄaja pri kreiranju novega teÄaja"; +$YouHaveEnteredTheCourseXInY = "Vstopil si v teÄaj %s v %s"; +$LoginIsEmailTitle = "Uporabi e-poÅ¡tni naslov kot uporabniÅ¡ko ime"; +$LoginIsEmailComment = "OmogoÄi uporabo e-poÅ¡tnega naslova za prijavo v sistem"; +$AllowBrowserSnifferTitle = "Aktiviraj vohljaÄa (sniffer) brskalnika"; +$AllowBrowserSnifferComment = "Možnost omogoÄi preiskavovalca zmožnosti brskalnikov, ki se povezujejo s Chamilo platformo. S tem omogoÄa izboljÅ¡avo uporabniÅ¡ke izkuÅ¡nje s prilagoditvijo odziva vrsti brskalnika, vendar njegova uporaba upoÄasni zaÄetno nalaganje strani vsakokrat, ko uporabnik vstopi v platformo."; +$EnableWamiRecordTitle = "Aktiviraj Wami-recorder"; +$EnableWamiRecordComment = "Wami-recorder je snemalnik zvoka, ki bazira na Flash tehnologiji"; +$ChangeSharedSetting = "Spremeni nastavitev vidnosti drugih portalov"; +$GradebookDefaultWeightTitle = "Privzeta utež v redovalnici"; +$GradebookDefaultWeightComment = "Ta utež bo uporabljena privzeto v vseh teÄajih"; ?> \ No newline at end of file diff --git a/main/lang/slovenian/course_description.inc.php b/main/lang/slovenian/course_description.inc.php index 414403c6e0..9b0cb4d2fc 100644 --- a/main/lang/slovenian/course_description.inc.php +++ b/main/lang/slovenian/course_description.inc.php @@ -17,4 +17,5 @@ $CourseDescriptionUpdated = "Opis teÄaja je bil ažuriran"; $CourseDescriptionDeleted = "Opis teÄaja je bil odstranjen"; $CourseDescriptionIntro = "Da bi opisali teÄaj, kliknite na ustrezen naslov in vnesite želene podatke v vnosna polja.

ZakljuÄite s klikom na OK, nato ponovite za naslednji želen naslov."; $langSaveDescription = "Shrani opis"; +$AddCourseDescription = "Dodaj opis teÄaja"; ?> \ No newline at end of file diff --git a/main/lang/slovenian/courses.inc.php b/main/lang/slovenian/courses.inc.php index 31a2ebb43f..08b030bf9d 100644 --- a/main/lang/slovenian/courses.inc.php +++ b/main/lang/slovenian/courses.inc.php @@ -4,20 +4,20 @@ for more information: see languages.txt in the lang folder. */ $lang_already_enrolled = "že vpisan"; $lang_my_personnal_course_list = "Osebni seznam teÄajev"; -$lang_course_enrollment = "Uporabnikov teÄaj"; +$lang_course_enrollment = "Uporabnik teÄaja"; $lang_course_not_available = "TeÄaj ni na voljo..."; $lang_enroll = "Vpis"; $lang_enroll_to_a_new_course = "Vpis v nov teÄaj"; -$lang_my_present_course_list = "Seznam mojih trenutnih teÄajev"; +$lang_my_present_course_list = "Moji teÄaji"; $lang_no_course_to_enroll_in_this_category = "V tej kategoriji ni nobenega teÄaja za vpis...\n"; $lang_or_search_from_the_course_code = " ali iskanje s pomoÄjo kode teÄaja"; $lang_search = "Iskanje"; -$lang_select_course_among_categories = "Izberi teÄaj izmed kategorij"; +$lang_select_course_among_categories = "Izberi teÄaj v želeni kategoriji"; $lang_select_course_in = "Izberi teÄaj v"; $lang_select_course_in_search_results = "Izberi teÄaj iz rezultata iskanja"; $lang_unsubscribe = "Izpis"; $lang_back_to_my_home_page = "Povratek na mojo domaÄo stran"; -$lang_back_to_my_personnal_course_list = "Povratek na moj osebni seznam teÄajev"; +$lang_back_to_my_personnal_course_list = "Povratek na seznam mojih teÄajev"; $langTitular = "Vodja"; $langBackToListOfThisUser = "Povratek na seznam teÄajev"; $langAdministrationTools = "Orodja upravitelja"; @@ -47,11 +47,11 @@ $langEnrollToCourseSuccessful = "Vpisan si v teÄaj"; $langSubCat = "podkategorije"; $langUnsubscribeNotAllowed = "Izpis za ta teÄaj ni dovoljen."; $langCourseAdminUnsubscribeNotAllowed = "Si upravitelj tega teÄaja."; -$CourseManagement = "Upravljanje teÄajev"; -$SortMyCourses = "Razvrsti moje teÄaje"; +$CourseManagement = "Katalog teÄajev"; +$SortMyCourses = "Razvrsti teÄaje"; $SubscribeToCourse = "VpiÅ¡i se v teÄaj"; $UnsubscribeFromCourse = "IzpiÅ¡i se iz teÄaja"; -$CreateCourseCategory = "Ustvari kategorijo teÄaja"; +$CreateCourseCategory = "Ustvari osebno kategorijo teÄajev"; $CourseCategoryAbout2bedeleted = "Si prepriÄan, da želiÅ¡ odstraniti to kategorijo teÄajev? Preostali teÄaji te kategorije bodo prestavljeni izven obstojeÄih kategorij."; $CourseCategories = "Kategorije teÄajev"; $CoursesInCategory = "TeÄaji v kategoriji"; diff --git a/main/lang/slovenian/document.inc.php b/main/lang/slovenian/document.inc.php index f940bb2813..11f0a15a3e 100644 --- a/main/lang/slovenian/document.inc.php +++ b/main/lang/slovenian/document.inc.php @@ -267,4 +267,5 @@ $DirExists = "Operacija ni možna. Mapa z istim imenom že obstaja."; $DocMv = "Dokument je bil premaknjen"; $NoSVGImagesInImagesGalleryPath = "V vaÅ¡i galeriji slik ni SVG slik"; $NoSVGImages = "Ni SVG slik"; +$WamiNeedFilename = "Pred aktivacijo snemanja je potrebno doloÄiti ime datoteke."; ?> \ No newline at end of file diff --git a/main/lang/slovenian/exercice.inc.php b/main/lang/slovenian/exercice.inc.php index 733dc0bd25..2e349ddfee 100644 --- a/main/lang/slovenian/exercice.inc.php +++ b/main/lang/slovenian/exercice.inc.php @@ -468,7 +468,7 @@ $NumberOfStudentsWhoTryTheExercise = "Å t. teÄajnikov s poskusom testa"; $LowestScore = "Najnižji dosežen rezultat"; $HighestScore = "NajviÅ¡ji dosežen rezultat"; $MaximumScore = "NajveÄji možen rezultat"; -$NotRevised = "Nepregledani"; +$NotRevised = "Nepregledano"; $PreviousQuestion = "Predhodno vpraÅ¡anje"; $Options = "Možnosti"; $RandomQuestionByCategory = "NakljuÄna vpraÅ¡anja po kategorijah"; @@ -477,7 +477,7 @@ $ReviewAnswers = "Preglej moje rezultate"; $TextWhenFinished = "Besedilo ob koncu testa"; $Validated = "Pregledan"; $NotValidated = "Ni pregledan"; -$Revised = "Pregledani"; +$Revised = "Pregledano"; $SelectAQuestionToReview = "Izberi vpraÅ¡anje za pregled"; $ReviewQuestionLater = "Preglej vpraÅ¡anje kasneje"; $NumberStudentWhoSelectedIt = "Å t. teÄajnikov, ki so ga izbrali"; @@ -485,4 +485,12 @@ $QuestionsAlreadyAnswered = "VpraÅ¡anje je že bilo odgovorjeno"; $StudentsWhoAreTakingTheExerciseRightNow = "TeÄajniki, ki pravkar izvajajo test"; $ReportByQuestion = "PoroÄilo po vpraÅ¡anjih"; $LiveResults = "Reultati v živo"; +$RecordAnswer = "Posnemi odgovor"; +$UseTheMessageBelowToAddSomeComments = "Uporabite spodnje sporoÄilo za dodajanje komentarja"; +$SendRecord = "PoÅ¡lji posnetek"; +$DownloadLatestRecord = "Prenesi posnetek"; +$OralExpression = "Ustno (govorno) izražanje"; +$CongratulationsYouPassedTheTest = "ÄŒestitam. Tvoj test je bil uspeÅ¡no zakljuÄen."; +$YouDidNotReachTheMinimumScore = "Nisi dosegel minimalnega zahtevanega rezultata."; +$EndTest = "KonÄaj test"; ?> \ No newline at end of file diff --git a/main/lang/slovenian/gradebook.inc.php b/main/lang/slovenian/gradebook.inc.php index 942c6fd514..e6b77d42dc 100644 --- a/main/lang/slovenian/gradebook.inc.php +++ b/main/lang/slovenian/gradebook.inc.php @@ -228,4 +228,8 @@ $SelectGradebook = "Izberi ocenjevanje"; $CheckYourGradingModelValues = "Preverite vrednosti modela ocenjevanja"; $SkillsAchievedWhenAchievingThisGradebook = "Spretnosti pridobljene s tem ocenjevanjem"; $AddGradebook = "Dodaj ocenjevanje"; +$SelectGradeModel = "Izberi model ocenjevanja"; +$AllMustWeight100 = "Vsota vseh vrednosti mora biti 100"; +$Components = "Komponente"; +$OnlyActiveWhenThereAreAnyComponents = "Ta možnost je omogoÄena v primeru, da imate kakrÅ¡nokoli ocenjevanje ali kategorije"; ?> \ No newline at end of file diff --git a/main/lang/slovenian/index.inc.php b/main/lang/slovenian/index.inc.php index d4ab8d2017..3104e74334 100644 --- a/main/lang/slovenian/index.inc.php +++ b/main/lang/slovenian/index.inc.php @@ -5,7 +5,7 @@ for more information: see languages.txt in the lang folder. $langInvalidId = "Vstop ni uspel. NapaÄno uporabniÅ¡ko ime ali geslo"; $langWelcome = "DobrodoÅ¡li !"; $langPass = "Geslo"; -$langEnter = "Povratek na seznam mojih teÄajev"; +$langEnter = "Povratek na seznam teÄajev"; $langReg = "Registracija"; $langMenu = "Menu"; $langAdvises = "Nasveti"; @@ -14,10 +14,10 @@ $langGetCourseFromOldPortal = "kliknite tukaj za prenos teÄaja iz starega porta $langOtherCourses = "ostali teÄaji"; $langSupportForum = "Forum podpore"; $langCategories = "kategorije"; -$langBackToHomePage = "Povratek na domaÄo stran"; +$langBackToHomePage = "Pregled kategorij"; $lang_No_course_publicly_available = "Trenutno ni javno dostopnih teÄajev."; $langLostPassword = "Izgubljeno geslo"; -$lang_edit_my_course_list = "Uredi seznam mojih teÄajev"; +$lang_edit_my_course_list = "Uredi seznam teÄajev"; $langAgenda = "Agenda"; $langValvas = "Zadnja obvestila"; $langUp = "Gor"; @@ -31,22 +31,22 @@ $Intranet = "Intranet"; $Englin = "English"; $langInvalidForSelfRegistration = "Vstop ni uspel - Äe nisi registriran, lahko to storiÅ¡ s pomoÄjo registracijskega obrazca"; $langSubCat = "podkategorije"; -$langMenuGeneral = "SploÅ¡no"; -$langMenuUser = "Uporabnik"; +$langMenuGeneral = "PomoÄ"; +$langMenuUser = "Moj raÄun"; $langMenuAdmin = "Admin. portala"; $langUsersOnLineList = "Seznam aktivnih uporabnikov"; $langTotalOnLine = "Skupaj aktivnih"; $langRefresh = "Osveži"; -$langMe = "*"; +$langMe = "jaz"; $langSystemAnnouncements = "Obvestila sistema"; $langHelpMaj = "PomoÄ"; $langNotRegistered = "Ni vpisan"; $langAdmin = "Admin platforme"; $Login = "UporabniÅ¡ko ime"; -$langRegisterForCourse = "Vpis v nov teÄaj"; -$langUnregisterForCourse = "Izpis iz teÄajev"; +$langRegisterForCourse = "Vpis v teÄaj"; +$langUnregisterForCourse = "Izpis iz teÄaja"; $langCombinedCourse = "Združeni teÄaji"; -$Platform = "Platforma"; +$Platform = "Portal"; $Refresh = "Osveži"; $TotalOnLine = "Skupaj aktivnih"; $langCourseClosed = "(teÄaj je trenutno zaprt)"; @@ -63,16 +63,16 @@ $CourseView = "Prikaži popoln seznam teÄajev"; $DropboxFileAdded = "V nabiralnik je bila dodana nova datoteka"; $NewMessageInForum = "Novo sporoÄilo je bilo objavljeno v forumu"; $FolderCreated = "Nova mapa je bila ustvarjena"; -$LinkAdded = "Povezava dodana"; +$LinkAdded = "Povezava je bila dodana"; $AnnouncementAdded = "Obvestilo je bilo dodano"; -$AgendaAdded = "Zapis agende je bil dodan"; +$AgendaAdded = "Dogodek je bil dodan"; $LoginEnter = "Prijava"; $Messages = "SporoÄila"; $Inbox = "Prejeto"; -$Comppose = "Sestavi novo"; +$Comppose = "Sestavi"; $PendingInvitations = "ÄŒakajoÄa povabila"; $YouDoNotHaveAnySessionInItsHistory = "V zgodovini nimate beležene nobene seje teÄaja"; -$PortalHomepageDefaultIntroduction = "

ÄŒestitke! VaÅ¡ portal je uspeÅ¡no nameÅ¡Äen!

Namestitev lahko sedaj zakljuÄite z izvedbo naslednjih treh korakov:

  1. Prilagodite ali spremenite nastavitve portala v upraviteljevem podroÄju; izberite Portal -> Configuration settings.
  2. Dodajte nekaj življenja vaÅ¡emu portalu s tem, da ustvarite nekaj uporabnikov in/ali nekaj teÄajev. To lahko izvedete z vabilom izbranim osebam, kjer jih pozovete k registraciji v portal, ali pa uporabniÅ¡ke raÄune zanje kreirate sami preko upraviteljevega razdelka Uporabniki oz. teÄaje preko razdelka TeÄaji.
  3. Uredite in spremenite to stran preko Nastavitev domaÄe strani portala.

Vedno in ob vsakem Äasu lahko veÄ informacij o tej programski opremi najdete na naÅ¡i spletni strani: http://www.chamilo.org.

Želimo vam veliko uspeha, in ne oklevajte se pridružiti naši skupnosti in/ali nam posredovati povratne informacije preko našega foruma.

"; +$PortalHomepageDefaultIntroduction = "

ÄŒestitke! VaÅ¡ portal je uspeÅ¡no nameÅ¡Äen!

Namestitev lahko sedaj zakljuÄite z izvedbo naslednjih treh korakov:

  1. Prilagodite ali spremenite nastavitve portala v upraviteljevem podroÄju; izberite Portal -> Nastavitve Chamilo platforme.
  2. Dodajte nekaj življenja vaÅ¡emu portalu s tem, da ustvarite nekaj uporabnikov in/ali nekaj teÄajev. To lahko izvedete z vabilom izbranim osebam, kjer jih pozovete k registraciji v portal, ali pa uporabniÅ¡ke raÄune zanje kreirate sami preko upraviteljevega razdelka Uporabniki oz. teÄaje preko razdelka TeÄaji.
  3. Uredite in spremenite to stran preko Nastavitev domaÄe strani portala.

Vedno in ob vsakem Äasu lahko veÄ informacij o tej programski opremi najdete na naÅ¡i spletni strani: http://www.chamilo.org.

Želimo vam veliko uspeha, in ne oklevajte se pridružiti naši skupnosti in/ali nam posredovati povratne informacije preko našega foruma.

"; $Username = "UporabniÅ¡ko ime"; $Profile = "Profil"; ?> \ No newline at end of file diff --git a/main/lang/slovenian/registration.inc.php b/main/lang/slovenian/registration.inc.php index 04cf88aef0..af00245c22 100644 --- a/main/lang/slovenian/registration.inc.php +++ b/main/lang/slovenian/registration.inc.php @@ -133,10 +133,10 @@ $AccountExternalAuthSource = "Chamilo ne more te zahteve servisirati avtomatiÄn $AccountsExternalAuthSource = "Chamilo ne more servisirati te izjeme avtomatiÄno, ker je vsaj eden od uporabniÅ¡kih raÄunov avtoriziran preko zunanjega izvora. Izvedite odgovarjajoÄe mere za vse uporabniÅ¡ke raÄune (vkljuÄno s tistimi, ki jih avtorizira platforma) in ibvestite uporabnike."; $RequestSentToPlatformAdmin = "Chamilo ne more servisirati zahteve avtomatiÄno za to vrsto uporabniÅ¡kega raÄuna. VaÅ¡a zahteva je bila posredovana upravitelju platforme, ki bo izvedel odgovarjajoÄe mere in vas naknadno obvestil o rezultatih izvedbe zahteve."; $langphone = "Telefonska Å¡t."; -$Unreg = "Odjavi"; -$MyProgress = "Moj napredek"; +$Unreg = "IzpiÅ¡i"; +$MyProgress = "Napredek"; $ProgressIntroduction = "PriÄni z izbiro teÄaja seje spodaj.
Napredek je viden za vsak teÄaj v katerega je teÄajnik vpisan."; -$Select = "Izberi"; +$Select = "Oceni"; $NeverExpires = "Nikoli ne poteÄe"; $On = "On"; $ExpirationDate = "Datum poteka"; diff --git a/main/lang/slovenian/tracking.inc.php b/main/lang/slovenian/tracking.inc.php index 4dcf6c85dc..9041d9276c 100644 --- a/main/lang/slovenian/tracking.inc.php +++ b/main/lang/slovenian/tracking.inc.php @@ -315,4 +315,7 @@ $NumberOfForumsInLearnpath = "Å t. forumov v uÄni poti"; $NumberOfAssignmentsInLearnpath = "Å t. nalog v uÄni poti"; $NumberOfAnnouncementsInCourse = "Å t. obvestil v teÄaju"; $CurrentCoursesReport = "PoroÄilo o trenutnih teÄajih"; +$NumberOfPublishedExercises = "Å¡t. objavljenih vaj/testov"; +$NumberOfPublishedLps = "Å¡t. objavljenih uÄnih poti"; +$EventType = "Vrsta dogodka"; ?> \ No newline at end of file diff --git a/main/lang/slovenian/trad4all.inc.php b/main/lang/slovenian/trad4all.inc.php index bc9d7c4bd9..a990dc3023 100644 --- a/main/lang/slovenian/trad4all.inc.php +++ b/main/lang/slovenian/trad4all.inc.php @@ -55,7 +55,7 @@ $langNoDescription = "Brez opisa"; $langOfficialCode = "Koda"; $FirstName = "Ime"; $LastName = "Priimek"; -$Status = "Profil"; +$Status = "Status"; $langEmail = "E-poÅ¡ta"; $SlideshowConversion = "Pretvorba prosojnic"; $UploadFile = "Naloži datoteko"; @@ -513,7 +513,7 @@ $Directories = "mape"; $UserAge = "Starost"; $UserBirthday = "Rojstni datum"; $Course = "TeÄaj"; -$FilesUpload = "Nalaganje datotek"; +$FilesUpload = "datotek"; $ExerciseFinished = "Test je bil dokonÄan"; $UserSex = "Spol"; $UserNativeLanguage = "Materni jezik"; @@ -535,7 +535,7 @@ $FieldMadeUnchangeable = "Polje je sedaj nespremenljivo: uporabniki ga ne morejo $CannotMakeFieldUnchangeable = "Polje ne more biti nespremenljivo"; $Folder = "Mapa"; $CloseOtherSession = "Klepet ni na voljo, ker je neka druga stran teÄaja že odprta; poskusite ponovno naložiti to stran"; -$FileUploadSucces = "Datoteka je bila uspeÅ¡no preneÅ¡ena."; +$FileUploadSucces = "Datoteka je bila uspeÅ¡no naložena."; $Yesterday = "VÄeraj"; $Submit = "Uveljavi"; $Department = "Oddelek"; @@ -709,7 +709,7 @@ $Menu = "Meni"; $BackToUserList = "Nazaj na seznam uporabnikov"; $GraphicNotAvailable = "Slika ni na voljo"; $BackTo = "Nazaj na"; -$HistoryTrainingSessions = "Zgodovina pouÄevanja - seje"; +$HistoryTrainingSessions = "Zgodovina teÄajev sej"; $ConversionFailled = "Pretvorba je bila neuspeÅ¡na"; $AlreadyExists = "Že obstaja"; $TheNewWordHasBeenAdded = "Nova beseda je bila dodana"; @@ -1060,7 +1060,6 @@ $CourseCodeAlreadyExistExplained = "V primeru podvojitve kode teÄaja sistem pre $CantDeleteReadonlyFiles = "Ne morem odstraniti datoteke, ki je opredeljena kot zgolj bralna."; $Uploaded = "Naloženo."; $Saved = "Shranjeno."; -$GotoCourse = "Pojdi v teÄaj"; $EmailSentFromDokeos = "E-poÅ¡ta poslana s platforme"; $InfoAboutLastDoneAdvanceAndNextAdvanceNotDone = "Informacija o zadnjem dokonÄanem in naslednjem nedokonÄanem koraku."; $LatexCode = "LaTeX koda"; @@ -1133,15 +1132,21 @@ $MyAverage = "Moje povpreÄje"; $AllAttempts = "Vsi poskusi"; $Attempt = "Poizkus"; $SaveForNow = "Shrani in nadaljuj kasneje"; +$NoQuicktime = "V vaÅ¡em brskalniku ni nameÅ¡Äena QuickTime razÅ¡iritev. Platformo lahko kljub temu uporabljate, vendar boste izgubili podporo za predvajanje naketerih multimedijskih formatov. Svetujemo, da brskalnikovo razÅ¡iritev QuickTime namestite."; $NoJavaSun = "V vaÅ¡em brskalniku ni nameÅ¡Äen Java vtiÄ. Platformo lahko kljub temu uporabljate, vendar boste izgubili nekatere funkcionalnosti."; $NoJava = "Java ni podprta v vaÅ¡em brskalniku"; $JavaSun24 = "RazliÄica Java, ki jo uporabljate, ni podprta s tem orodjem. Da bi ga uporabili, morate namestiti Java SUN razliÄico viÅ¡jo od 24."; +$NoMessageAnywere = "V primeru, da tega obvestila med to sejo ne želite veÄ videti, kliknite tule"; $Attempts = "Poizkusi"; $SeeResults = "Poglej rezultate"; $Loading = "Nalaganje"; $AreYouSureToRestore = "Ste prepriÄani, da želite povrniti ta element?"; $ThisIsAutomaticEmailNoReply = "To je avtomatiÄno generirano e-poÅ¡tno sporoÄilo. Prosimo, da nanj ne odgovarjate."; $PersonalCalendar = "Osebni koledar"; +$SkillsTree = "KompetenÄno drevo"; +$Skills = "Kompetence"; +$SkillsProfile = "KompetenÄni profil"; +$WithCertificate = "S certifikatom"; $AdminCalendar = "Koledar upravitelja"; $CourseCalendar = "Koledar teÄaja"; $Reports = "PoroÄila"; @@ -1150,26 +1155,62 @@ $dateTimeFormatLong24H = "%d %B %Y ob %H:%M"; $GradingModelTitle = "Model ocenjevanja"; $Discussions = "Diskusije"; $GradeModel = "Model ocenjevanja"; +$ViewSkillsTree = "Poglej kompetenÄno drevo"; +$MySkills = "Moje kompetence"; $SeeFile = "Poglej datoteko"; $UserList = "Seznam uporabnikov"; $SearchUsers = "IÅ¡Äi uporabnike"; $Administration = "Upravljanje"; +$SkillsAndGradebooks = "Kompetence in ocene"; +$AddSkill = "Dodaj kompetenco"; $AcceptLegal = "Sprejmi pogoje rabe"; $CourseLegalAgreement = "Pogoji rabe za ta teÄaj"; +$SkillDoesNotExist = "Tu ni take kompetence"; +$SkillRootName = "ABsolutna kompetenca"; +$Option = "Opcija"; +$Updates = "Posodobitve"; $Teaching = "PouÄevanje"; $CoursesReporting = "PoroÄila teÄajev"; $AdminReports = "Upraviteljeva poroÄila"; $ExamsReporting = "PoroÄila preverjanj"; $MyReporting = "Moja poroÄila"; +$SearchSkills = "IÅ¡Äi kompetence"; $SaveThisSearch = "Shrani to iskanje"; +$SkillProfiles = "Shranjeni kompetenÄni profili"; +$Matches = "Ustreza"; $WelcomeUserXToTheSiteX = "%s, dobrodoÅ¡li k %s"; +$CheckUsersWithId = "Za vpis uporabnika uporabi uporabnikov ID iz datoteke"; +$MB = "MiB"; $SessionList = "Seznam sej"; $StudentList = "Seznam teÄajnikov"; +$GroupReply = "Odgovor"; +$GroupReplies = "Odgovori"; +$SkillNotFound = "Kompetence ni mogoÄe najti"; +$IHaveThisSkill = "Jaz imam to kompetenco"; +$Me = "Jaz"; $Vote = "Glas"; $Votes = "Glasov"; $XStarsOutOf5 = "%s zvezdic od 5"; $Visit = "Obisk"; $Visits = "Obiskov"; -$YourVote = "Tvoje glasovanje"; -$HottestCourses = "Najbolj vroÄi"; +$YourVote = "Tvoja ocena"; +$HottestCourses = "VroÄi teÄaji"; +$SentAtX = "Poslano na: %s"; +$LoginToVote = "Za glasovanje se prijavi"; +$DoNotShow = "Ne prikaži"; +$ShowToAdminsOnly = "Prikaži zgolj upraviteljem"; +$ShowToAdminsAndTeachers = "Prikaži upraviteljem in uÄiteljem"; +$ShowToAllUsers = "Prikaži vsem uporabnikom"; +$SelectAnAction = "Izberi dejanje"; +$LoginX = "Å t.uporabnikov: %s"; +$ChatConnected = "Klepet(povezan)"; +$ChatDisconnected = "Klepet(nepovezan)"; +$ThingsToDo = "Dejanja, ki jih je potrebno opraviti v nadaljevanju"; +$WamiFlashDialog = "Prikaže dialog, ki vas vpraÅ¡a po dovoljenju za dostop do mikrofona. Odgovorite z da in zaprite dialog, V primeru, da obvestila ne želite veÄ prikazovati, izberite pomnenje nastavitev pred zapiranjem dialoga."; +$WamiStartRecorder = "PriÄni s snemanjem s pritiskom na mikrofon in ustavi s ponovnim pritiskom nanj. Vsak priÄetek snemanja bo generiral lastno datoteko."; +$InputNameHere = "VpiÅ¡ite ime"; +$Reload = "Osveži"; +$TimeSpentLastXDays = "Porabljen Äas v zadnjih %s dneh"; +$TimeSpentBetweenXAndY = "ÄŒas porabljen med %s in %s"; +$GoToCourse = "Vstopi"; ?> \ No newline at end of file diff --git a/main/lang/slovenian/wiki.inc.php b/main/lang/slovenian/wiki.inc.php index 7a694b4995..0cf31bb756 100644 --- a/main/lang/slovenian/wiki.inc.php +++ b/main/lang/slovenian/wiki.inc.php @@ -192,28 +192,45 @@ $MProgressPages = "Strani z najviÅ¡jim napredkom"; $MostDiscussUsers = "NajveÄkrat diskutirani uporabniki"; $RandomPage = "NakljuÄna stran"; $ProtectedPages = "ZaÅ¡Äitene strani"; +$IncludeAllVersions = "IÅ¡Äi tudi po starejÅ¡ih razzliÄicah vseh strani"; $TotalHiddenPages = "Skupaj skritih strani"; +$TotalPagesEditedAtThisTime = "Skupaj strani urejanih v tem trenutku"; +$TotalWikiUsers = "Skupno Å¡t. uporabnikov, ki sodelujejo v tem wiki-ju"; $StudentAddNewPages = "TeÄajniki lahko dodajo stran v Wiki"; +$DateCreateOldestWikiPage = "Datum nastanka najstarejÅ¡e wiki strani"; $DateEditLatestWikiVersion = "Datum najnovejÅ¡ega urejanja v Wiki"; $AverageScoreAllPages = "PovpreÄna ocena vseh strani"; +$AverageMediaUserProgress = "PovpreÄna ocena napredka uporabnika na njegovih straneh"; +$TotalIpAdress = "Å t. razliÄnih IP naslovov prispevajoÄih v ta wiki"; $Pages = "Strani"; $Versions = "RazliÄice"; $EmptyPages = "Skupaj praznih strani"; +$LockedDiscussPages = "Å t. blokiranih diskusijskih strani"; +$HiddenDiscussPages = "Å t. skritih diskusijskih strani"; +$TotalComments = "SKupno Å¡t. komentarjev v okviru razliÄic istih strani"; +$TotalOnlyRatingByTeacher = "Skupno Å¡t. strani, ki jih lahko ocenjuje zgolj uÄitelj"; +$TotalRatingPeers = "Skupno Å¡t, strani, ki jih lahko ocenjujejo drugi teÄajniki"; +$TotalTeacherAssignments = "Å t. strani s strani uÄitelja podanih kot zadolžitev"; +$TotalStudentAssignments = "Å t. strani, opredeljenih kot individualna zadolžitev teÄajnika"; $TotalTask = "Å tevilo opravil"; $PortfolioMode = "NaÄin portfelja"; $StandardMode = "ObiÄajni opravilni naÄin"; +$ContentPagesInfo = "Informacija o vsebini strani"; $InTheLastVersion = "V zadnji razliÄici"; $InAllVersions = "V vseh razliÄicah"; $NumContributions = "Å tevilo prispevkov"; $NumAccess = "Å tevilo obiskov"; $NumWords = "Å tevilo besed"; +$NumlinksHtmlImagMedia = "Å t. vstavljenih zunanjih povezav(besedil, slik, ...)"; $NumWikilinks = "Å tevilo wiki povezav"; $NumImages = "Å tevilo vstavljenih slik"; $NumFlash = "Å tevilo vstavljenih flash datotek"; $NumMp3 = "Å t. mp3 zvokovnih datotek"; $NumFlvVideo = "Å t. vstavljenih FLV video datotek"; $NumYoutubeVideo = "Å t. vkljuÄenih Youtube videov"; +$NumOtherAudioVideo = "Å t. vstavljenih zvoÄnih in video datotek(razen mp3 in flv)"; $NumTables = "Å tevilo vstavljenih tabel"; +$Anchors = "Å t. hiper-besedilnih povezav (anchors)"; $NumProtectedPages = "Å tevilo zaÅ¡Äitenih strani"; $WhoAndWhere = "Kdo in kje"; ?> \ No newline at end of file diff --git a/main/lang/slovenian/work.inc.php b/main/lang/slovenian/work.inc.php index dc9a5429c0..7141b47de1 100644 --- a/main/lang/slovenian/work.inc.php +++ b/main/lang/slovenian/work.inc.php @@ -36,7 +36,7 @@ $ValidateChanges = "Uveljavi spremembe"; $FolderUpdated = "Mapa je bila ažurirana"; $EndsAt = "KonÄa (popolnoma zaprta)"; $QualificationOfAssignment = "Ocenjevanje nalog/izdelkov"; -$MakeQualifiable = "OmogoÄi ocenjevanje"; +$MakeQualifiable = "Dodaj v redovalnico"; $QualificationNumberOver = "Ocena"; $WeightInTheGradebook = "Utež v kompetenÄnem poroÄilu"; $DatesAvailables = "Razpoložljivi datumi"; @@ -97,5 +97,5 @@ $MaxWeightNeedToBeProvided = "NajveÄja vrednost uteži mora biti podana"; $ContainsAfile = "Vsebuje datoteko"; $AllowTextAssignments = "Dovoli izdelku, da je upravljan preko spletnega urejevalnika"; $YouAlreadySentAPaperYouCantUpload = "Nalogo ste že odposlali. Ne morete naložiti nove."; -$CantUploadDeleteYourPaperFirst = "Te naloge ne morete naložiti. Najprej morate odstraniti predhodno naloženo nalogo."; +$CantUploadDeleteYourPaperFirst = "Ta naloga/izdelek je predhodno že bila oddana in je ne morete ponovno naložiti. ÄŒe to vseeno želite storiti, najprej odstranite že oddano nalogo."; ?> \ No newline at end of file diff --git a/main/lang/somali/accessibility.inc.php b/main/lang/somali/accessibility.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/accessibility.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/admin.inc.php b/main/lang/somali/admin.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/admin.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/agenda.inc.php b/main/lang/somali/agenda.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/agenda.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/announcements.inc.php b/main/lang/somali/announcements.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/announcements.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/blog.inc.php b/main/lang/somali/blog.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/blog.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/chat.inc.php b/main/lang/somali/chat.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/chat.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/course_description.inc.php b/main/lang/somali/course_description.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/course_description.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/course_home.inc.php b/main/lang/somali/course_home.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/course_home.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/course_info.inc.php b/main/lang/somali/course_info.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/course_info.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/coursebackup.inc.php b/main/lang/somali/coursebackup.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/coursebackup.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/courses.inc.php b/main/lang/somali/courses.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/courses.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/create_course.inc.php b/main/lang/somali/create_course.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/create_course.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/document.inc.php b/main/lang/somali/document.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/document.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/dropbox.inc.php b/main/lang/somali/dropbox.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/dropbox.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/exercice.inc.php b/main/lang/somali/exercice.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/exercice.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/external_module.inc.php b/main/lang/somali/external_module.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/external_module.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/forum.inc.php b/main/lang/somali/forum.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/forum.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/glossary.inc.php b/main/lang/somali/glossary.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/glossary.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/gradebook.inc.php b/main/lang/somali/gradebook.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/gradebook.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/group.inc.php b/main/lang/somali/group.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/group.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/help.inc.php b/main/lang/somali/help.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/help.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/hotspot.inc.php b/main/lang/somali/hotspot.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/hotspot.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/import.inc.php b/main/lang/somali/import.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/import.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/index.inc.php b/main/lang/somali/index.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/index.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/install.inc.php b/main/lang/somali/install.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/install.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/learnpath.inc.php b/main/lang/somali/learnpath.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/learnpath.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/link.inc.php b/main/lang/somali/link.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/link.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/md_document.inc.php b/main/lang/somali/md_document.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/md_document.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/md_link.inc.php b/main/lang/somali/md_link.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/md_link.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/md_mix.inc.php b/main/lang/somali/md_mix.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/md_mix.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/md_scorm.inc.php b/main/lang/somali/md_scorm.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/md_scorm.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/messages.inc.php b/main/lang/somali/messages.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/messages.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/myagenda.inc.php b/main/lang/somali/myagenda.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/myagenda.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/notebook.inc.php b/main/lang/somali/notebook.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/notebook.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/notification.inc.php b/main/lang/somali/notification.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/notification.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/pedaSuggest.inc.php b/main/lang/somali/pedaSuggest.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/pedaSuggest.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/registration.inc.php b/main/lang/somali/registration.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/registration.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/reservation.inc.php b/main/lang/somali/reservation.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/reservation.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/resourcelinker.inc.php b/main/lang/somali/resourcelinker.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/resourcelinker.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/scorm.inc.php b/main/lang/somali/scorm.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/scorm.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/scormbuilder.inc.php b/main/lang/somali/scormbuilder.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/scormbuilder.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/scormdocument.inc.php b/main/lang/somali/scormdocument.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/scormdocument.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/slideshow.inc.php b/main/lang/somali/slideshow.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/slideshow.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/survey.inc.php b/main/lang/somali/survey.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/survey.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/tracking.inc.php b/main/lang/somali/tracking.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/tracking.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/trad4all.inc.php b/main/lang/somali/trad4all.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/trad4all.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/userInfo.inc.php b/main/lang/somali/userInfo.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/userInfo.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/videoconf.inc.php b/main/lang/somali/videoconf.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/videoconf.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/wiki.inc.php b/main/lang/somali/wiki.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/wiki.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/somali/work.inc.php b/main/lang/somali/work.inc.php new file mode 100644 index 0000000000..fdfb06ff3d --- /dev/null +++ b/main/lang/somali/work.inc.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/main/lang/turkce/admin.inc.php b/main/lang/turkce/admin.inc.php index 670ccf189d..6f529942a1 100644 --- a/main/lang/turkce/admin.inc.php +++ b/main/lang/turkce/admin.inc.php @@ -241,7 +241,7 @@ $OriginalName = "Orijinal adı"; $EnglishName = "Ä°ngilizce adı"; $DokeosFolder = "Chamilo klasörü"; $Properties = "Özellikler"; -$DokeosConfigSettings = "Sistem Ayarları"; +$PlatformConfigSettings = "Sistem Ayarları"; $SettingsStored = "Ayarlar kaydedildi."; $InstitutionTitle = "Sitenin ismi"; $InstitutionComment = "Ãœst baÅŸlıkta, saÄŸ tarafta gözükecek olan site ismi"; @@ -663,7 +663,7 @@ $NoticeWillBeNotDisplayed = "Ä°kazı baÅŸlangıç sayfasında görüntülenmeyec $LetThoseFieldsEmptyToHideTheNotice = "Ä°kazı gizlemek için ÅŸu alanları boÅŸ bırakmasına izin ver"; $Ppt2lpVoiceRecordingNeedsRed5 = "Öğrenme düzenleyicisindeki ses kayıt özelliÄŸi Red5 akış sunucusuna baÄŸlıdır. Bu sunucunun parametereleri mevcut sayfadaki videokonferans bölümünden yapılandırılabilir"; $PlatformCharsetTitle = "Karakter seti"; -$PlatformCharsetComment = "Karakter seti Chamilo ta kullanılan dillerin nasıl gösterileceÄŸinin tanımlandığı yerdir. ÖrneÄŸin Rus yada Japon harfleri kullanırsanız, bu seti deÄŸiÅŸtirmek isteyebilirsiniz. Tüm ingilizce, latince ve batı avrupa dilleri için ön tanımlı set iso-8859-15 olarak tanımlanabilir."; +$PlatformCharsetComment = "Karakter seti Chamilo ta kullanılan dillerin nasıl gösterileceÄŸinin tanımlandığı yerdir. ÖrneÄŸin Rus yada Japon harfleri kullanırsanız, bu seti deÄŸiÅŸtirmek isteyebilirsiniz. Tüm ingilizce, latince ve batı avrupa dilleri için ön tanımlı set UTF-8 olarak tanımlanabilir."; $ExtendedProfileRegistrationTitle = "Kayıtta geniÅŸletilmiÅŸ profil alanları"; $ExtendedProfileRegistrationComment = "Kullanıcı kayıt iÅŸleminde aÅŸağıdaki geniÅŸletilmiÅŸ profil alanlarından hangilerinin bulunması zorunludur? GeniÅŸletilmiÅŸ profilin aktifleÅŸtirilmiÅŸ olmasını gerektirir (Yukarı bakınız)"; $ExtendedProfileRegistrationRequiredTitle = "Kayıtta gerekli geniÅŸletilmiÅŸ profil alanları"; diff --git a/main/lang/turkce/import.inc.php b/main/lang/turkce/import.inc.php index 516fd54a12..ca465592e5 100644 --- a/main/lang/turkce/import.inc.php +++ b/main/lang/turkce/import.inc.php @@ -6,7 +6,6 @@ $langPgTitle = "Sayfa ismi"; $langExplanation = "OK tıkladığınızda, Forum, Gündem, Belge Yönetimi vs. araçlarla birlikte bu dersin sitesi yaratılır. Kullanıcı adınız ve ÅŸifrenizle giriÅŸ yaparak siteyi isteÄŸiniz ÅŸekilde düzenleyebilirsiniz."; $langTooBig = "Gönderilecek dosyayı seçmediniz veya dosya boyutu çok büyük"; $langCouldNot = "Dosya gönderilemedi"; -$langNotAllowed = "Ä°zin verilmiyor"; $langAddPageToSite = "Siteye sayfa ekle"; $langCouldNotSendPage = "Bu sayfa HTML formatýnda deðil bu nedenle gönderilemez. Eðer HTML olmayan bir dosya göndermek istiyorsanýz (PDF, Word, Power Point, Video, etc.) Belge Araçlarýný kullanýnýz"; $langSendPage = "Gönderilecek sayfa"; diff --git a/main/lang/turkce/trad4all.inc.php b/main/lang/turkce/trad4all.inc.php index 1782b9cfce..d31340dab8 100644 --- a/main/lang/turkce/trad4all.inc.php +++ b/main/lang/turkce/trad4all.inc.php @@ -272,7 +272,6 @@ $DocumentAdded = "Belge eklendi"; $DocumentUpdated = "Belge güncellendi"; $DocumentInFolderUpdated = "Belgenin güncellendiÄŸi klasör"; $Course_description = "Ders açıklaması"; -$Calendar_event = "Ajanda"; $Document = "Belge"; $Learnpath = "Dersler"; $Link = "BaÄŸlantı"; From 1d74184c9fac738f17e4fc97d2c420d8ddba7594 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Mon, 7 May 2012 17:03:14 -0500 Subject: [PATCH 059/128] Added Somali and Bengali to list of languages - although not yet useful --- main/install/db_main.sql | 6 ++++-- main/install/migrate-db-1.8.8-1.9.0-pre.sql | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/main/install/db_main.sql b/main/install/db_main.sql index aba5a49b3a..d0e62e1ec4 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -374,6 +374,7 @@ LOCK TABLES language WRITE; INSERT INTO language (original_name, english_name, isocode, dokeos_folder, available) VALUES ('العربية','arabic','ar','arabic',0), ('Asturianu','asturian','ast','asturian',0), +('বাংলা','bengali','bn','bengali',0), ('Български','bulgarian','bg','bulgarian',1), ('Bosanski','bosnian','bs','bosnian',1), ('Català','catalan','ca','catalan',0), @@ -417,6 +418,7 @@ INSERT INTO language (original_name, english_name, isocode, dokeos_folder, avail ('Русский','russian','ru','russian',0), ('Slovenčina','slovak','sk','slovak',0), ('Slovenščina','slovenian','sl','slovenian',1), +('الصومالية','somali','so','somali',0), ('Srpski','serbian','sr','serbian',0), ('Suomi','finnish','fi','finnish',0), ('Svenska','swedish','sv','swedish',0), @@ -856,7 +858,7 @@ VALUES ('teachers_can_change_grade_model_settings', NULL, 'radio', 'Gradebook', 'true', 'TeachersCanChangeGradeModelSettingsTitle', 'TeachersCanChangeGradeModelSettingsComment', NULL, NULL, 1), ('shibboleth_description', NULL, 'radio', 'Shibboleth', 'false', 'ShibbolethMainActivateTitle', 'ShibbolethMainActivateComment', NULL, NULL, 0), ('facebook_description', NULL, 'radio', 'Facebook', 'false', 'FacebookMainActivateTitle', 'FacebookMainActivateComment', NULL, NULL, 0), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17759','DatabaseVersion','', NULL, NULL, 0); +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17763','DatabaseVersion','', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), @@ -2980,4 +2982,4 @@ CREATE TABLE grade_components ( PRIMARY KEY (id) ); -ALTER TABLE gradebook_category ADD COLUMN grade_model_id INT DEFAULT 0; \ No newline at end of file +ALTER TABLE gradebook_category ADD COLUMN grade_model_id INT DEFAULT 0; diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index 1d89882058..ed2ed2a3b9 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -152,6 +152,8 @@ INSERT INTO settings_options (variable, value, display_text) VALUES ('enable_wam INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_default_weight', NULL, 'textfield', 'Gradebook', '100', 'GradebookDefaultWeightTitle', 'GradebookDefaultWeightComment', NULL, NULL, 1); +INSERT INTO language (original_name, english_name, isocode, dokeos_folder, available) VALUES ('বাংলা','bengali','bn','bengali',0), ('الصومالية','somali','so','somali',0); + -- Course ranking CREATE TABLE track_course_ranking (id int unsigned not null PRIMARY KEY AUTO_INCREMENT, c_id int unsigned not null, session_id int unsigned not null default 0, url_id int unsigned not null default 0, accesses int unsigned not null default 0, total_score int unsigned not null default 0, users int unsigned not null default 0, creation_date datetime not null); @@ -188,7 +190,7 @@ DELETE FROM settings_current WHERE variable = 'use_document_title'; DELETE FROM settings_options WHERE variable = 'use_document_title'; -- Do not move this query -UPDATE settings_current SET selected_value = '1.9.0.17759' WHERE variable = 'chamilo_database_version'; +UPDATE settings_current SET selected_value = '1.9.0.17763' WHERE variable = 'chamilo_database_version'; -- xxSTATSxx ALTER TABLE track_e_exercices ADD COLUMN questions_to_check TEXT NOT NULL DEFAULT ''; From 7e34ed3d71be47c34bd56b8f0698b292f7bb5fb7 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 08:43:45 +0200 Subject: [PATCH 060/128] #4712 remove warnings undefined variable --- main/install/index.php | 4 ++-- main/install/install.lib.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main/install/index.php b/main/install/index.php index 5a4e725ba2..614200e933 100644 --- a/main/install/index.php +++ b/main/install/index.php @@ -37,6 +37,7 @@ if (!function_exists('version_compare') || version_compare( phpversion(), REQUIR /* INITIALIZATION SECTION */ +ob_implicit_flush(true); session_start(); // Including necessary libraries. @@ -824,8 +825,7 @@ if (@$_POST['step2']) { include 'install_files.inc.php'; } $current_step = 7; - $nbr_courses = isset($nbr_courses) ? $nbr_courses : null; - display_after_install_message($installType, $nbr_courses); + display_after_install_message($installType); } elseif ($_POST['step1'] || $badUpdatePath) { //STEP 1 : REQUIREMENTS diff --git a/main/install/install.lib.php b/main/install/install.lib.php index 9ee31881cc..654ba39668 100755 --- a/main/install/install.lib.php +++ b/main/install/install.lib.php @@ -1942,7 +1942,7 @@ function display_configuration_settings_form($installType, $urlForm, $languageFo /** * After installation is completed (step 6), this message is displayed. */ -function display_after_install_message($installType, $nbr_courses) { +function display_after_install_message($installType) { ?>

From c8c8572b3c570c62cbb1cc3e0b6d0ca89255aa25 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 08:59:07 +0200 Subject: [PATCH 061/128] #4694 add feedback during installation --- main/install/update-configuration.inc.php | 116 +- main/install/update-db-1.6.x-1.8.0.inc.php | 997 +++++++++--------- main/install/update-db-1.8.0-1.8.2.inc.php | 366 +++---- main/install/update-db-1.8.2-1.8.3.inc.php | 1 + main/install/update-db-1.8.3-1.8.4.inc.php | 1 + main/install/update-db-1.8.4-1.8.5.inc.php | 1 + main/install/update-db-1.8.5-1.8.6.inc.php | 3 +- main/install/update-db-1.8.6-1.8.6.1.inc.php | 3 +- .../install/update-db-1.8.6.1-1.8.6.2.inc.php | 3 +- main/install/update-db-1.8.6.2-1.8.7.inc.php | 3 +- main/install/update-db-1.8.7-1.8.8.inc.php | 3 +- main/install/update-db-1.8.8-1.9.0.inc.php | 3 +- .../update-db-scorm-1.6.x-1.8.0.inc.php | 2 + 13 files changed, 757 insertions(+), 745 deletions(-) mode change 100644 => 100755 main/install/update-configuration.inc.php mode change 100755 => 100644 main/install/update-db-1.8.2-1.8.3.inc.php mode change 100755 => 100644 main/install/update-db-1.8.3-1.8.4.inc.php mode change 100755 => 100644 main/install/update-db-1.8.4-1.8.5.inc.php mode change 100755 => 100644 main/install/update-db-scorm-1.6.x-1.8.0.inc.php diff --git a/main/install/update-configuration.inc.php b/main/install/update-configuration.inc.php old mode 100644 new mode 100755 index 52c0d1f0bd..584682bbab --- a/main/install/update-configuration.inc.php +++ b/main/install/update-configuration.inc.php @@ -1,4 +1,5 @@ ') !== false) { - $ignore = true; - } - if (!$ignore) { - fwrite($fh, $line); - } - } - if (!$found_version) { - fwrite($fh, '$_configuration[\'system_version\'] = \''.$new_version.'\';'."\r\n"); - } - if (!$found_stable) { - fwrite($fh, '$_configuration[\'system_stable\'] = '.($new_version_stable?'true':'false').';'."\r\n"); - } - if (!$found_software_name) { - fwrite($fh, '$_configuration[\'software_name\'] = \''.$software_name.'\';'."\r\n"); - } - if (!$found_software_url) { - fwrite($fh, '$_configuration[\'software_url\'] = \''.$software_url.'\';'."\r\n"); - } - fwrite($fh, '?>'); - fclose($fh); + Log::notice("Starting " . basename(__FILE__)); + + // Edit the configuration file + $file = file(api_get_path(CONFIGURATION_PATH) . 'configuration.php'); + $fh = fopen(api_get_path(CONFIGURATION_PATH) . 'configuration.php', 'w'); + $found_version_old = false; + $found_stable_old = false; + $found_version = false; + $found_stable = false; + $found_software_name = false; + $found_software_url = false; + + foreach ($file as $line) { + $ignore = false; + if (stripos($line, '$_configuration[\'dokeos_version\']') !== false) { + $found_version_old = true; + $line = '$_configuration[\'dokeos_version\'] = \'' . $new_version . '\';' . "\r\n"; + $ignore = true; + } elseif (stripos($line, '$_configuration[\'system_version\']') !== false) { + $found_version = true; + $line = '$_configuration[\'system_version\'] = \'' . $new_version . '\';' . "\r\n"; + } elseif (stripos($line, '$_configuration[\'dokeos_stable\']') !== false) { + $found_stable_old = true; + $line = '$_configuration[\'dokeos_stable\'] = ' . ($new_version_stable ? 'true' : 'false') . ';' . "\r\n"; + $ignore = true; + } elseif (stripos($line, '$_configuration[\'system_stable\']') !== false) { + $found_stable = true; + $line = '$_configuration[\'system_stable\'] = ' . ($new_version_stable ? 'true' : 'false') . ';' . "\r\n"; + } elseif (stripos($line, '$_configuration[\'software_name\']') !== false) { + $found_software_name = true; + $line = '$_configuration[\'software_name\'] = \'' . $software_name . '\';' . "\r\n"; + } elseif (stripos($line, '$_configuration[\'software_url\']') !== false) { + $found_software_url = true; + $line = '$_configuration[\'software_url\'] = \'' . $software_url . '\';' . "\r\n"; + } elseif (stripos($line, '$userPasswordCrypted') !== false) { + $line = '$userPasswordCrypted = \'' . ($userPasswordCrypted) . '\';' . "\r\n"; + } elseif (stripos($line, '?>') !== false) { + $ignore = true; + } + if (!$ignore) { + fwrite($fh, $line); + } + } + if (!$found_version) { + fwrite($fh, '$_configuration[\'system_version\'] = \'' . $new_version . '\';' . "\r\n"); + } + if (!$found_stable) { + fwrite($fh, '$_configuration[\'system_stable\'] = ' . ($new_version_stable ? 'true' : 'false') . ';' . "\r\n"); + } + if (!$found_software_name) { + fwrite($fh, '$_configuration[\'software_name\'] = \'' . $software_name . '\';' . "\r\n"); + } + if (!$found_software_url) { + fwrite($fh, '$_configuration[\'software_url\'] = \'' . $software_url . '\';' . "\r\n"); + } + fwrite($fh, '?>'); + fclose($fh); } else { - echo 'You are not allowed here !'; + echo 'You are not allowed here !'; } \ No newline at end of file diff --git a/main/install/update-db-1.6.x-1.8.0.inc.php b/main/install/update-db-1.6.x-1.8.0.inc.php index a67f3d630a..cb48ffb95a 100644 --- a/main/install/update-db-1.6.x-1.8.0.inc.php +++ b/main/install/update-db-1.6.x-1.8.0.inc.php @@ -1,4 +1,5 @@ '.get_lang('Error').' ! Dokeos '.implode('|', $updateFromVersion).' '.get_lang('HasNotBeenFound').'.

- '.get_lang('PleasGoBackToStep1').'. -

+ echo '' . get_lang('Error') . ' ! Dokeos ' . implode('|', $updateFromVersion) . ' ' . get_lang('HasNotBeenFound') . '.

+ ' . get_lang('PleasGoBackToStep1') . '. +

'; - exit (); - } - - $_configuration['db_glue'] = get_config_param('dbGlu'); - - if ($singleDbForm) { - $_configuration['table_prefix'] = get_config_param('courseTablePrefix'); - $_configuration['main_database'] = get_config_param('mainDbName'); - $_configuration['db_prefix'] = get_config_param('dbNamePrefix'); - } - - $dbScormForm = preg_replace('/[^a-zA-Z0-9_\-]/', '', $dbScormForm); - - if (!empty($dbPrefixForm) && strpos($dbScormForm, $dbPrefixForm) !== 0) { - $dbScormForm = $dbPrefixForm.$dbScormForm; - } - - if (empty($dbScormForm) || $dbScormForm == 'mysql' || $dbScormForm == $dbPrefixForm) { - $dbScormForm = $dbPrefixForm.'scorm'; - } - - /* Normal upgrade procedure: start by updating main, statistic, user databases */ - - // If this script has been included by index.php, not update_courses.php, so - // that we want to change the main databases as well... - $only_test = false; - $log = 0; - - if (defined('SYSTEM_INSTALLATION')) { - - if ($singleDbForm) { - if (empty($dbStatsForm)) $dbStatsForm = $dbNameForm; - if (empty($dbScormForm)) $dbScormForm = $dbNameForm; - if (empty($dbUserForm)) $dbUserForm = $dbNameForm; - } - /** - * Update the databases "pre" migration - */ - include '../lang/english/create_course.inc.php'; - - if ($languageForm != 'english') { - // languageForm has been escaped in index.php - include '../lang/'.$languageForm.'/create_course.inc.php'; - } - - //get the main queries list (m_q_list) - $m_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-pre.sql', 'main'); - if (count($m_q_list) > 0) { - // Now use the $m_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (strlen($dbNameForm) > 40) { - error_log('Database name '.$dbNameForm.' is too long, skipping', 0); - } elseif (!in_array($dbNameForm, $dblist)) { - error_log('Database '.$dbNameForm.' was not found, skipping', 0); - } else { - Database::select_db($dbNameForm); - foreach ($m_q_list as $query) { - if ($only_test) { - error_log("Database::query($dbNameForm,$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In $dbNameForm, executed: $query", 0); - } - } - } - } - } - - // Get the stats queries list (s_q_list) - $s_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-pre.sql', 'stats'); - if (count($s_q_list) > 0) { - // Now use the $s_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (strlen($dbStatsForm) > 40) { - error_log('Database name '.$dbStatsForm.' is too long, skipping', 0); - } elseif (!in_array($dbStatsForm, $dblist)) { - error_log('Database '.$dbStatsForm.' was not found, skipping', 0); - } else { - Database::select_db($dbStatsForm); - foreach ($s_q_list as $query) { - if ($only_test) { - error_log("Database::query($dbStatsForm,$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In $dbStatsForm, executed: $query", 0); - } - } - } - } - } - - // Get the user queries list (u_q_list) - $u_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-pre.sql', 'user'); - if (count($u_q_list) > 0) { - // Now use the $u_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (strlen($dbUserForm) > 40) { - error_log('Database name '.$dbUserForm.' is too long, skipping', 0); - } elseif (!in_array($dbUserForm, $dblist)) { - error_log('Database '.$dbUserForm.' was not found, skipping', 0); - } else { - Database::select_db($dbUserForm); - foreach ($u_q_list as $query) { - if ($only_test) { - error_log("Database::query($dbUserForm,$query)", 0); - error_log("In $dbUserForm, executed: $query", 0); - } else { - $res = Database::query($query); - } - } - } - } - // The SCORM database doesn't need a change in the pre-migrate part - ignore. - } - - $prefix = ''; - if ($singleDbForm) { - $prefix = $_configuration['table_prefix']; - } - - // Get the courses databases queries list (c_q_list) - $c_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-pre.sql', 'course'); - if (count($c_q_list) > 0) { - - // Get the courses list - if (strlen($dbNameForm) > 40) { - error_log('Database name '.$dbNameForm.' is too long, skipping', 0); - } elseif (!in_array($dbNameForm, $dblist)) { - error_log('Database '.$dbNameForm.' was not found, skipping', 0); - } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); - if ($res === false) { die('Error while querying the courses list in update_db-1.6.x-1.8.0.inc.php'); } - if (Database::num_rows($res) > 0) { - $i = 0; + exit(); + } + + $_configuration['db_glue'] = get_config_param('dbGlu'); + + if ($singleDbForm) { + $_configuration['table_prefix'] = get_config_param('courseTablePrefix'); + $_configuration['main_database'] = get_config_param('mainDbName'); + $_configuration['db_prefix'] = get_config_param('dbNamePrefix'); + } + + $dbScormForm = preg_replace('/[^a-zA-Z0-9_\-]/', '', $dbScormForm); + + if (!empty($dbPrefixForm) && strpos($dbScormForm, $dbPrefixForm) !== 0) { + $dbScormForm = $dbPrefixForm . $dbScormForm; + } + + if (empty($dbScormForm) || $dbScormForm == 'mysql' || $dbScormForm == $dbPrefixForm) { + $dbScormForm = $dbPrefixForm . 'scorm'; + } + + /* Normal upgrade procedure: start by updating main, statistic, user databases */ + + // If this script has been included by index.php, not update_courses.php, so + // that we want to change the main databases as well... + $only_test = false; + $log = 0; + + if (defined('SYSTEM_INSTALLATION')) { + + if ($singleDbForm) { + if (empty($dbStatsForm)) + $dbStatsForm = $dbNameForm; + if (empty($dbScormForm)) + $dbScormForm = $dbNameForm; + if (empty($dbUserForm)) + $dbUserForm = $dbNameForm; + } + /** + * Update the databases "pre" migration + */ + include '../lang/english/create_course.inc.php'; + + if ($languageForm != 'english') { + // languageForm has been escaped in index.php + include '../lang/' . $languageForm . '/create_course.inc.php'; + } + + //get the main queries list (m_q_list) + $m_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-pre.sql', 'main'); + if (count($m_q_list) > 0) { + // Now use the $m_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (strlen($dbNameForm) > 40) { + error_log('Database name ' . $dbNameForm . ' is too long, skipping', 0); + } elseif (!in_array($dbNameForm, $dblist)) { + error_log('Database ' . $dbNameForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbNameForm); + foreach ($m_q_list as $query) { + if ($only_test) { + error_log("Database::query($dbNameForm,$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In $dbNameForm, executed: $query", 0); + } + } + } + } + } + + // Get the stats queries list (s_q_list) + $s_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-pre.sql', 'stats'); + if (count($s_q_list) > 0) { + // Now use the $s_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (strlen($dbStatsForm) > 40) { + error_log('Database name ' . $dbStatsForm . ' is too long, skipping', 0); + } elseif (!in_array($dbStatsForm, $dblist)) { + error_log('Database ' . $dbStatsForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbStatsForm); + foreach ($s_q_list as $query) { + if ($only_test) { + error_log("Database::query($dbStatsForm,$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In $dbStatsForm, executed: $query", 0); + } + } + } + } + } + + // Get the user queries list (u_q_list) + $u_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-pre.sql', 'user'); + if (count($u_q_list) > 0) { + // Now use the $u_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (strlen($dbUserForm) > 40) { + error_log('Database name ' . $dbUserForm . ' is too long, skipping', 0); + } elseif (!in_array($dbUserForm, $dblist)) { + error_log('Database ' . $dbUserForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbUserForm); + foreach ($u_q_list as $query) { + if ($only_test) { + error_log("Database::query($dbUserForm,$query)", 0); + error_log("In $dbUserForm, executed: $query", 0); + } else { + $res = Database::query($query); + } + } + } + } + // The SCORM database doesn't need a change in the pre-migrate part - ignore. + } + + $prefix = ''; + if ($singleDbForm) { + $prefix = $_configuration['table_prefix']; + } + + // Get the courses databases queries list (c_q_list) + $c_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-pre.sql', 'course'); + if (count($c_q_list) > 0) { + + // Get the courses list + if (strlen($dbNameForm) > 40) { + error_log('Database name ' . $dbNameForm . ' is too long, skipping', 0); + } elseif (!in_array($dbNameForm, $dblist)) { + error_log('Database ' . $dbNameForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbNameForm); + $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); + if ($res === false) { + die('Error while querying the courses list in update_db-1.6.x-1.8.0.inc.php'); + } + if (Database::num_rows($res) > 0) { + $i = 0; $list = array(); - while ($row = Database::fetch_array($res)) { - $list[] = $row; - $i++; - } - foreach ($list as $row_course) { - // Now use the $c_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (!$singleDbForm) { // otherwise just use the main one - Database::select_db($row_course['db_name']); - } - - foreach ($c_q_list as $query) { - if ($singleDbForm) { - $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix{$row_course['db_name']}_$2$3", $query); - } - - if ($only_test) { - error_log("Database::query(".$row_course['db_name'].",$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In ".$row_course['db_name'].", executed: $query", 0); - } - } - } - - // Prepare reusable users list to avoid repetition of the SQL query, but only select - // users from the current course to avoid blowing the memory limit - $users_list = array(); - $sql_uc = "SELECT u.user_id as ui, u.firstname as fn, u.lastname as ln " . - " FROM $dbNameForm.user u, $dbNameForm.course_rel_user cu " . - " WHERE cu.course_code = '".$row_course['code']."' " . - " AND u.user_id = cu.user_id"; - $res_uc = Database::query($sql_uc); - while ($user_row = Database::fetch_array($res_uc)) { - $users_list[$user_row['fn'].' '.$user_row['ln']] = $user_row['ui']; - } - - // Update course manually - // Update group_category.forum_state ? - // Update group_info.tutor_id (put it in group_tutor table?) ? - // Update group_info.forum_state, forum_id ? - - // Update forum tables (migrate from bb_ tables to forum_ tables) - // Migrate categories - $prefix_course = $prefix; - if ($singleDbForm) { - $prefix_course = $prefix.$row_course['db_name']."_"; - } - - $sql_orig = "SELECT * FROM ".$prefix_course."bb_categories"; - $res_orig = Database::query($sql_orig); - $order = 1; - while ($row = Database::fetch_array($res_orig)) { - $myorder = (empty($row['cat_order']) ? $order : $row['cat_order']); - $sql = "INSERT INTO ".$prefix_course."forum_category " . - "(cat_id,cat_title,cat_comment,cat_order,locked) VALUES " . - "('".$row['cat_id']."','".Database::escape_string($row['cat_title'])."','','".$myorder."',0)"; - $res = Database::query($sql); - $lastcatid = Database::insert_id(); - //error_log($sql,0); - $order ++; - // Add item_property - forum categories were not put into item_properties before - $sql = "INSERT INTO ".$prefix_course."item_property (tool,insert_user_id,ref,lastedit_type,lastedit_user_id,visibility) " . - "VALUES ('forum_category','1','$lastcatid','ForumCategoryAdded','1','1')"; - $res = Database::query($sql); - //error_log($sql,0); - } - - $sql_orig = "SELECT * FROM ".$prefix_course."bb_forums ORDER BY forum_last_post_id desc"; - $res_orig = Database::query($sql_orig); - $order = 1; - while ($row = Database::fetch_array($res_orig)) { - $sql = "INSERT INTO ".$prefix_course."forum_forum " . - "(forum_id,forum_category,allow_edit,forum_comment," . - "forum_title," . - "forum_last_post, forum_threads," . - "locked, forum_posts, " . - "allow_new_threads, forum_order) VALUES " . - "('".$row['forum_id']."','".$row['cat_id']."',1,'".Database::escape_string($row['forum_desc'])."'," . - "'".Database::escape_string($row['forum_name'])."'," . - "'".$row['forum_last_post_id']."','".$row['forum_topics']."'," . - "0,'".$row['forum_posts']."'," . - "1,$order)"; - //error_log($sql,0); - $res = Database::query($sql); - $lastforumid = Database::insert_id(); - $order++; - - // Add item_property - forums were not put into item_properties before - $sql = "INSERT INTO ".$prefix_course."item_property (tool,insert_user_id,ref,lastedit_type,lastedit_user_id,visibility) " . - "VALUES ('forum','1','$lastforumid','ForumAdded','1','1')"; - $res = Database::query($sql); - //error_log($sql,0); - } - - $sql_orig = "SELECT * FROM ".$prefix_course."bb_topics"; - $res_orig = Database::query($sql_orig); - while ($row = Database::fetch_array($res_orig)) { - $name = $row['prenom'].' '.$row['nom']; - // Check whether user id is reusable - if ($row['topic_poster'] <= 1) { - if (isset($users_list[$name])) { - $poster_id = $users_list[$name]; - } else { - $poster_id = $row['topic_poster']; - } - } - // Convert time from varchar to datetime - $time = $row['topic_time']; - $name = Database::escape_string($name); - $sql = "INSERT INTO ".$prefix_course."forum_thread " . - "(thread_id,forum_id,thread_poster_id," . - "locked,thread_replies,thread_sticky,thread_title," . - "thread_poster_name, thread_date, thread_last_post," . - "thread_views) VALUES " . - "('".$row['topic_id']."','".$row['forum_id']."','".$poster_id."'," . - "0,'".$row['topic_replies']."',0,'".Database::escape_string($row['topic_title'])."'," . - "'$name','$time','".$row['topic_last_post_id']."'," . - "'".$row['topic_views']."')"; - //error_log($sql,0); - $res = Database::query($sql); - $lastthreadid = Database::insert_id(); - - // Add item_property - forum threads were not put into item_properties before - $sql = "INSERT INTO ".$prefix_course."item_property (tool,insert_user_id,ref,lastedit_type,lastedit_user_id,visibility) " . - "VALUES ('forum_thread','1','$lastthreadid','ForumThreadAdded','1','1')"; - $res = Database::query($sql); - //error_log($sql,0); - } - - $sql_orig = "SELECT * FROM ".$prefix_course."bb_posts bp, ".$prefix_course."bb_posts_text bpt WHERE bp.post_id = bpt.post_id"; - $res_orig = Database::query($sql_orig); - while ($row = Database::fetch_array($res_orig)) { - $name = $row['prenom'].' '.$row['nom']; - // Check whether user id is reusable - if ($row['poster_id'] <= 0 ) { - if (isset($users_list[$name])) { - $poster_id = $users_list[$name]; - } else { - $poster_id = $row['poster_id']; - } - } - // Convert time from varchar to datetime - $time = $row['post_time']; - $name = Database::escape_string($name); - $sql = "INSERT INTO ".$prefix_course."forum_post " . - "(post_id,forum_id,thread_id," . - "poster_id,post_parent_id,visible, " . - "post_title,poster_name, post_text, " . - "post_date, post_notification) VALUES " . - "('".$row['post_id']."','".$row['forum_id']."','".$row['topic_id']."'," . - "'".$poster_id."','".$row['parent_id']."',1," . - "'".Database::escape_string($row['post_title'])."','$name', '".Database::escape_string($row['post_text'])."'," . - "'$time',0)"; - //error_log($sql,0); - $res = Database::query($sql); - $lastpostid = Database::insert_id(); - - // Add item_property - forum threads were not put into item_properties before - $sql = "INSERT INTO ".$prefix_course."item_property(tool,insert_user_id,ref,lastedit_type,lastedit_user_id,visibility) " . - "VALUES ('forum_post','1','$lastpostid','ForumPostAdded','1','1')"; - $res = Database::query($sql); - //error_log($sql,0); - } - unset($users_list); - - $sql_orig = "SELECT id, tutor_id FROM ".$prefix_course."group_info"; - $res_orig = Database::query($sql_orig); - $order = 1; - while ($row = Database::fetch_array($res_orig)) { - $sql = "INSERT INTO ".$prefix_course."group_rel_tutor " . - "(user_id,group_id) VALUES " . - "('".$row['tutor_id']."','".$row['id']."')"; - $res = Database::query($sql); - } - } - } - } - } - - // Load the old-scorm to new-scorm migration script - if (!$only_test){ - include('update-db-scorm-1.6.x-1.8.0.inc.php'); - } - if (defined('SYSTEM_INSTALLATION')) { - if ($singleDbForm) { - if (empty($dbStatsForm)) $dbStatsForm = $dbNameForm; - if (empty($dbScormForm)) $dbScormForm = $dbNameForm; - if (empty($dbUserForm)) $dbUserForm = $dbNameForm; - } - // Deal with migrate-db-1.6.x-1.8.0-post.sql - // Get the main queries list (m_q_list) - $m_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-post.sql', 'main'); - if (count($m_q_list) > 0) { - // Now use the $m_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (strlen($dbNameForm) > 40) { - error_log('Database name '.$dbNameForm.' is too long, skipping', 0); - } elseif (!in_array($dbNameForm, $dblist)) { - error_log('Database '.$dbNameForm.' was not found, skipping', 0); - } else { - Database::select_db($dbNameForm); - foreach ($m_q_list as $query) { - if ($only_test){ - error_log("Database::query($dbNameForm,$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In $dbNameForm, executed: $query", 0); - } - } - } - } - } - - // Get the stats queries list (s_q_list) - $s_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-post.sql', 'stats'); - if (count($s_q_list) > 0) { - // Now use the $s_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (strlen($dbStatsForm) > 40) { - error_log('Database name '.$dbStatsForm.' is too long, skipping', 0); - } elseif (!in_array($dbNameForm, $dblist)){ - error_log('Database '.$dbNameForm.' was not found, skipping', 0); - } else { - Database::select_db($dbStatsForm); - foreach ($s_q_list as $query) { - if ($only_test) { - error_log("Database::query($dbStatsForm,$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In $dbStatsForm, executed: $query", 0); - } - } - } - } - } - - // Get the user queries list (u_q_list) - $u_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-post.sql', 'user'); - if (count($u_q_list) > 0) { - //now use the $u_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (strlen($dbUserForm) > 40) { - error_log('Database name '.$dbUserForm.' is too long, skipping', 0); - } elseif (!in_array($dbUserForm, $dblist)) { - error_log('Database '.$dbUserForm.' was not found, skipping', 0); - } else { - Database::select_db($dbUserForm); - foreach ($u_q_list as $query) { - if ($only_test) { - error_log("Database::query($dbUserForm,$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In $dbUserForm, executed: $query", 0); - } - } - } - } - } - // The SCORM database should need a drop in the post-migrate part. However, we will keep these tables a bit more, just in case... - } - - // Get the courses databases queries list (c_q_list) - $c_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-post.sql', 'course'); - if (count($c_q_list) > 0) { - // Get the courses list - if (strlen($dbNameForm) > 40) { - error_log('Database name '.$dbNameForm.' is too long, skipping', 0); - } elseif (!in_array($dbNameForm, $dblist)) { - error_log('Database '.$dbNameForm.' was not found, skipping', 0); - } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); - if ($res === false) { die('Error while querying the courses list in update_db-1.6.x-1.8.0.inc.php'); } - if (Database::num_rows($res) > 0) { - $i = 0; - while ($row = Database::fetch_array($res)) { - $list[] = $row; - $i++; - } - foreach ($list as $row) { - // Now use the $c_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - $prefix_course = $prefix; - if ($singleDbForm) { - $prefix_course = $prefix.$row['db_name']."_"; - } else { - Database::select_db($row['db_name']); - } - - foreach($c_q_list as $query) { - if ($singleDbForm) { //otherwise just use the main one - $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix$2$3", $query); - } - if ($only_test) { - error_log("Database::query(".$row['db_name'].",$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In ".$row['db_name'].", executed: $query", 0); - } - } - } - } - } - } - } - - // Upgrade user categories sort - $table_user_categories = $dbUserForm.'.user_course_category'; - - $sql = 'SELECT * FROM '.$table_user_categories.' ORDER BY user_id, title'; - $rs = Database::query($sql); - - $sort = 0; - $old_user = 0; - while ($cat = Database::fetch_array($rs)) { + while ($row = Database::fetch_array($res)) { + $list[] = $row; + $i++; + } + foreach ($list as $row_course) { + // Now use the $c_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (!$singleDbForm) { // otherwise just use the main one + Database::select_db($row_course['db_name']); + } + + foreach ($c_q_list as $query) { + if ($singleDbForm) { + $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix{$row_course['db_name']}_$2$3", $query); + } + + if ($only_test) { + error_log("Database::query(" . $row_course['db_name'] . ",$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In " . $row_course['db_name'] . ", executed: $query", 0); + } + } + } + + // Prepare reusable users list to avoid repetition of the SQL query, but only select + // users from the current course to avoid blowing the memory limit + $users_list = array(); + $sql_uc = "SELECT u.user_id as ui, u.firstname as fn, u.lastname as ln " . + " FROM $dbNameForm.user u, $dbNameForm.course_rel_user cu " . + " WHERE cu.course_code = '" . $row_course['code'] . "' " . + " AND u.user_id = cu.user_id"; + $res_uc = Database::query($sql_uc); + while ($user_row = Database::fetch_array($res_uc)) { + $users_list[$user_row['fn'] . ' ' . $user_row['ln']] = $user_row['ui']; + } + + // Update course manually + // Update group_category.forum_state ? + // Update group_info.tutor_id (put it in group_tutor table?) ? + // Update group_info.forum_state, forum_id ? + // Update forum tables (migrate from bb_ tables to forum_ tables) + // Migrate categories + $prefix_course = $prefix; + if ($singleDbForm) { + $prefix_course = $prefix . $row_course['db_name'] . "_"; + } + + $sql_orig = "SELECT * FROM " . $prefix_course . "bb_categories"; + $res_orig = Database::query($sql_orig); + $order = 1; + while ($row = Database::fetch_array($res_orig)) { + $myorder = (empty($row['cat_order']) ? $order : $row['cat_order']); + $sql = "INSERT INTO " . $prefix_course . "forum_category " . + "(cat_id,cat_title,cat_comment,cat_order,locked) VALUES " . + "('" . $row['cat_id'] . "','" . Database::escape_string($row['cat_title']) . "','','" . $myorder . "',0)"; + $res = Database::query($sql); + $lastcatid = Database::insert_id(); + //error_log($sql,0); + $order++; + // Add item_property - forum categories were not put into item_properties before + $sql = "INSERT INTO " . $prefix_course . "item_property (tool,insert_user_id,ref,lastedit_type,lastedit_user_id,visibility) " . + "VALUES ('forum_category','1','$lastcatid','ForumCategoryAdded','1','1')"; + $res = Database::query($sql); + //error_log($sql,0); + } + + $sql_orig = "SELECT * FROM " . $prefix_course . "bb_forums ORDER BY forum_last_post_id desc"; + $res_orig = Database::query($sql_orig); + $order = 1; + while ($row = Database::fetch_array($res_orig)) { + $sql = "INSERT INTO " . $prefix_course . "forum_forum " . + "(forum_id,forum_category,allow_edit,forum_comment," . + "forum_title," . + "forum_last_post, forum_threads," . + "locked, forum_posts, " . + "allow_new_threads, forum_order) VALUES " . + "('" . $row['forum_id'] . "','" . $row['cat_id'] . "',1,'" . Database::escape_string($row['forum_desc']) . "'," . + "'" . Database::escape_string($row['forum_name']) . "'," . + "'" . $row['forum_last_post_id'] . "','" . $row['forum_topics'] . "'," . + "0,'" . $row['forum_posts'] . "'," . + "1,$order)"; + //error_log($sql,0); + $res = Database::query($sql); + $lastforumid = Database::insert_id(); + $order++; + + // Add item_property - forums were not put into item_properties before + $sql = "INSERT INTO " . $prefix_course . "item_property (tool,insert_user_id,ref,lastedit_type,lastedit_user_id,visibility) " . + "VALUES ('forum','1','$lastforumid','ForumAdded','1','1')"; + $res = Database::query($sql); + //error_log($sql,0); + } + + $sql_orig = "SELECT * FROM " . $prefix_course . "bb_topics"; + $res_orig = Database::query($sql_orig); + while ($row = Database::fetch_array($res_orig)) { + $name = $row['prenom'] . ' ' . $row['nom']; + // Check whether user id is reusable + if ($row['topic_poster'] <= 1) { + if (isset($users_list[$name])) { + $poster_id = $users_list[$name]; + } else { + $poster_id = $row['topic_poster']; + } + } + // Convert time from varchar to datetime + $time = $row['topic_time']; + $name = Database::escape_string($name); + $sql = "INSERT INTO " . $prefix_course . "forum_thread " . + "(thread_id,forum_id,thread_poster_id," . + "locked,thread_replies,thread_sticky,thread_title," . + "thread_poster_name, thread_date, thread_last_post," . + "thread_views) VALUES " . + "('" . $row['topic_id'] . "','" . $row['forum_id'] . "','" . $poster_id . "'," . + "0,'" . $row['topic_replies'] . "',0,'" . Database::escape_string($row['topic_title']) . "'," . + "'$name','$time','" . $row['topic_last_post_id'] . "'," . + "'" . $row['topic_views'] . "')"; + //error_log($sql,0); + $res = Database::query($sql); + $lastthreadid = Database::insert_id(); + + // Add item_property - forum threads were not put into item_properties before + $sql = "INSERT INTO " . $prefix_course . "item_property (tool,insert_user_id,ref,lastedit_type,lastedit_user_id,visibility) " . + "VALUES ('forum_thread','1','$lastthreadid','ForumThreadAdded','1','1')"; + $res = Database::query($sql); + //error_log($sql,0); + } + + $sql_orig = "SELECT * FROM " . $prefix_course . "bb_posts bp, " . $prefix_course . "bb_posts_text bpt WHERE bp.post_id = bpt.post_id"; + $res_orig = Database::query($sql_orig); + while ($row = Database::fetch_array($res_orig)) { + $name = $row['prenom'] . ' ' . $row['nom']; + // Check whether user id is reusable + if ($row['poster_id'] <= 0) { + if (isset($users_list[$name])) { + $poster_id = $users_list[$name]; + } else { + $poster_id = $row['poster_id']; + } + } + // Convert time from varchar to datetime + $time = $row['post_time']; + $name = Database::escape_string($name); + $sql = "INSERT INTO " . $prefix_course . "forum_post " . + "(post_id,forum_id,thread_id," . + "poster_id,post_parent_id,visible, " . + "post_title,poster_name, post_text, " . + "post_date, post_notification) VALUES " . + "('" . $row['post_id'] . "','" . $row['forum_id'] . "','" . $row['topic_id'] . "'," . + "'" . $poster_id . "','" . $row['parent_id'] . "',1," . + "'" . Database::escape_string($row['post_title']) . "','$name', '" . Database::escape_string($row['post_text']) . "'," . + "'$time',0)"; + //error_log($sql,0); + $res = Database::query($sql); + $lastpostid = Database::insert_id(); + + // Add item_property - forum threads were not put into item_properties before + $sql = "INSERT INTO " . $prefix_course . "item_property(tool,insert_user_id,ref,lastedit_type,lastedit_user_id,visibility) " . + "VALUES ('forum_post','1','$lastpostid','ForumPostAdded','1','1')"; + $res = Database::query($sql); + //error_log($sql,0); + } + unset($users_list); + + $sql_orig = "SELECT id, tutor_id FROM " . $prefix_course . "group_info"; + $res_orig = Database::query($sql_orig); + $order = 1; + while ($row = Database::fetch_array($res_orig)) { + $sql = "INSERT INTO " . $prefix_course . "group_rel_tutor " . + "(user_id,group_id) VALUES " . + "('" . $row['tutor_id'] . "','" . $row['id'] . "')"; + $res = Database::query($sql); + } + } + } + } + } + + // Load the old-scorm to new-scorm migration script + if (!$only_test) { + include('update-db-scorm-1.6.x-1.8.0.inc.php'); + } + if (defined('SYSTEM_INSTALLATION')) { + if ($singleDbForm) { + if (empty($dbStatsForm)) + $dbStatsForm = $dbNameForm; + if (empty($dbScormForm)) + $dbScormForm = $dbNameForm; + if (empty($dbUserForm)) + $dbUserForm = $dbNameForm; + } + // Deal with migrate-db-1.6.x-1.8.0-post.sql + // Get the main queries list (m_q_list) + $m_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-post.sql', 'main'); + if (count($m_q_list) > 0) { + // Now use the $m_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (strlen($dbNameForm) > 40) { + error_log('Database name ' . $dbNameForm . ' is too long, skipping', 0); + } elseif (!in_array($dbNameForm, $dblist)) { + error_log('Database ' . $dbNameForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbNameForm); + foreach ($m_q_list as $query) { + if ($only_test) { + error_log("Database::query($dbNameForm,$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In $dbNameForm, executed: $query", 0); + } + } + } + } + } + + // Get the stats queries list (s_q_list) + $s_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-post.sql', 'stats'); + if (count($s_q_list) > 0) { + // Now use the $s_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (strlen($dbStatsForm) > 40) { + error_log('Database name ' . $dbStatsForm . ' is too long, skipping', 0); + } elseif (!in_array($dbNameForm, $dblist)) { + error_log('Database ' . $dbNameForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbStatsForm); + foreach ($s_q_list as $query) { + if ($only_test) { + error_log("Database::query($dbStatsForm,$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In $dbStatsForm, executed: $query", 0); + } + } + } + } + } + + // Get the user queries list (u_q_list) + $u_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-post.sql', 'user'); + if (count($u_q_list) > 0) { + //now use the $u_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (strlen($dbUserForm) > 40) { + error_log('Database name ' . $dbUserForm . ' is too long, skipping', 0); + } elseif (!in_array($dbUserForm, $dblist)) { + error_log('Database ' . $dbUserForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbUserForm); + foreach ($u_q_list as $query) { + if ($only_test) { + error_log("Database::query($dbUserForm,$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In $dbUserForm, executed: $query", 0); + } + } + } + } + } + // The SCORM database should need a drop in the post-migrate part. However, we will keep these tables a bit more, just in case... + } + + // Get the courses databases queries list (c_q_list) + $c_q_list = get_sql_file_contents('migrate-db-1.6.x-1.8.0-post.sql', 'course'); + if (count($c_q_list) > 0) { + // Get the courses list + if (strlen($dbNameForm) > 40) { + error_log('Database name ' . $dbNameForm . ' is too long, skipping', 0); + } elseif (!in_array($dbNameForm, $dblist)) { + error_log('Database ' . $dbNameForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbNameForm); + $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); + if ($res === false) { + die('Error while querying the courses list in update_db-1.6.x-1.8.0.inc.php'); + } + if (Database::num_rows($res) > 0) { + $i = 0; + while ($row = Database::fetch_array($res)) { + $list[] = $row; + $i++; + } + foreach ($list as $row) { + // Now use the $c_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + $prefix_course = $prefix; + if ($singleDbForm) { + $prefix_course = $prefix . $row['db_name'] . "_"; + } else { + Database::select_db($row['db_name']); + } + + foreach ($c_q_list as $query) { + if ($singleDbForm) { //otherwise just use the main one + $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix$2$3", $query); + } + if ($only_test) { + error_log("Database::query(" . $row['db_name'] . ",$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In " . $row['db_name'] . ", executed: $query", 0); + } + } + } + } + } + } + } + + // Upgrade user categories sort + $table_user_categories = $dbUserForm . '.user_course_category'; + + $sql = 'SELECT * FROM ' . $table_user_categories . ' ORDER BY user_id, title'; + $rs = Database::query($sql); + + $sort = 0; + $old_user = 0; + while ($cat = Database::fetch_array($rs)) { if ($old_user != $cat['user_id']) { $old_user = $cat['user_id']; $sort = 0; } $sort++; - $sql = 'UPDATE '.$table_user_categories.' SET - sort = '.intval($sort).' - WHERE id='.intval($cat['id']); + $sql = 'UPDATE ' . $table_user_categories . ' SET + sort = ' . intval($sort) . ' + WHERE id=' . intval($cat['id']); Database::query($sql); - } - + } } else { - echo 'You are not allowed here !'; - + echo 'You are not allowed here !'; } diff --git a/main/install/update-db-1.8.0-1.8.2.inc.php b/main/install/update-db-1.8.0-1.8.2.inc.php index bd1a0cc096..edf3775fc9 100644 --- a/main/install/update-db-1.8.0-1.8.2.inc.php +++ b/main/install/update-db-1.8.0-1.8.2.inc.php @@ -1,4 +1,5 @@ '.get_lang('Error').' ! Dokeos '.implode('|', $updateFromVersion).' '.get_lang('HasNotBeenFound').'.

- '.get_lang('PleasGoBackToStep1').'. -

+ // Check if the current Dokeos install is eligible for update + if (!file_exists('../inc/conf/configuration.php')) { + echo '' . get_lang('Error') . ' ! Dokeos ' . implode('|', $updateFromVersion) . ' ' . get_lang('HasNotBeenFound') . '.

+ ' . get_lang('PleasGoBackToStep1') . '. +

'; - exit (); - } - - $_configuration['db_glue'] = get_config_param('dbGlu'); - - if ($singleDbForm) { - $_configuration['table_prefix'] = get_config_param('courseTablePrefix'); - $_configuration['main_database'] = get_config_param('mainDbName'); - $_configuration['db_prefix'] = get_config_param('dbNamePrefix'); - } - - $dbScormForm = preg_replace('/[^a-zA-Z0-9_\-]/', '', $dbScormForm); - - if (!empty($dbPrefixForm) && strpos($dbScormForm, $dbPrefixForm) !== 0) { - $dbScormForm = $dbPrefixForm.$dbScormForm; - } - - if (empty($dbScormForm) || $dbScormForm == 'mysql' || $dbScormForm == $dbPrefixForm) { - $dbScormForm = $dbPrefixForm.'scorm'; - } - - /* Normal upgrade procedure: start by updating main, statistic, user databases */ - - // If this script has been included by index.php, not update_courses.php, so - // that we want to change the main databases as well... - $only_test = false; - $log = 0; - if (defined('SYSTEM_INSTALLATION')) { - if ($singleDbForm) { - $dbStatsForm = $dbNameForm; - $dbScormForm = $dbNameForm; - $dbUserForm = $dbNameForm; - } - /** - * Update the databases "pre" migration - */ - include '../lang/english/create_course.inc.php'; - - if ($languageForm != 'english') { - //languageForm has been escaped in index.php - include '../lang/'.$languageForm.'/create_course.inc.php'; - } - - // Get the main queries list (m_q_list) - $m_q_list = get_sql_file_contents('migrate-db-1.8.0-1.8.2-pre.sql', 'main'); - if (count($m_q_list) > 0) { - //now use the $m_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (strlen($dbNameForm) > 40) { - error_log('Database name '.$dbNameForm.' is too long, skipping', 0); - } elseif (!in_array($dbNameForm,$dblist)) { - error_log('Database '.$dbNameForm.' was not found, skipping', 0); - } else { - Database::select_db($dbNameForm); - foreach ($m_q_list as $query) { - if ($only_test) { - error_log("Database::query($dbNameForm,$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In $dbNameForm, executed: $query", 0); - } - } - } - } - } - - // Get the stats queries list (s_q_list) - $s_q_list = get_sql_file_contents('migrate-db-1.8.0-1.8.2-pre.sql', 'stats'); - - if (count($s_q_list) > 0) { - // Now use the $s_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (strlen($dbStatsForm) > 40) { - error_log('Database name '.$dbStatsForm.' is too long, skipping', 0); - } elseif (!in_array($dbStatsForm, $dblist)) { - error_log('Database '.$dbStatsForm.' was not found, skipping', 0); - } else { - Database::select_db($dbStatsForm); - foreach ($s_q_list as $query) { - if ($only_test) { - error_log("Database::query($dbStatsForm,$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In $dbStatsForm, executed: $query", 0); - } - } - } - } - } - // Get the user queries list (u_q_list) - $u_q_list = get_sql_file_contents('migrate-db-1.8.0-1.8.2-pre.sql', 'user'); - if (count($u_q_list) > 0) { - //now use the $u_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (strlen($dbUserForm) > 40) { - error_log('Database name '.$dbUserForm.' is too long, skipping', 0); - } elseif (!in_array($dbUserForm,$dblist)) { - error_log('Database '.$dbUserForm.' was not found, skipping', 0); - } else { - Database::select_db($dbUserForm); - foreach ($u_q_list as $query) { - if ($only_test) { - error_log("Database::query($dbUserForm,$query)", 0); - error_log("In $dbUserForm, executed: $query", 0); - } else { - $res = Database::query($query); - } - } - } - } - // The SCORM database doesn't need a change in the pre-migrate part - ignore - } - - $prefix = ''; - if ($singleDbForm) { - $prefix = $_configuration['table_prefix']; - } - // Get the courses databases queries list (c_q_list) - $c_q_list = get_sql_file_contents('migrate-db-1.8.0-1.8.2-pre.sql', 'course'); - if (count($c_q_list) > 0) { - // Get the courses list - if (strlen($dbNameForm) > 40) { - error_log('Database name '.$dbNameForm.' is too long, skipping', 0); - } elseif (!in_array($dbNameForm,$dblist)) { - error_log('Database '.$dbNameForm.' was not found, skipping', 0); - } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); - if ($res === false) { die('Error while querying the courses list in update_db-1.8.0-1.8.2.inc.php'); } - if (Database::num_rows($res) > 0) { - $i = 0; + exit(); + } + + $_configuration['db_glue'] = get_config_param('dbGlu'); + + if ($singleDbForm) { + $_configuration['table_prefix'] = get_config_param('courseTablePrefix'); + $_configuration['main_database'] = get_config_param('mainDbName'); + $_configuration['db_prefix'] = get_config_param('dbNamePrefix'); + } + + $dbScormForm = preg_replace('/[^a-zA-Z0-9_\-]/', '', $dbScormForm); + + if (!empty($dbPrefixForm) && strpos($dbScormForm, $dbPrefixForm) !== 0) { + $dbScormForm = $dbPrefixForm . $dbScormForm; + } + + if (empty($dbScormForm) || $dbScormForm == 'mysql' || $dbScormForm == $dbPrefixForm) { + $dbScormForm = $dbPrefixForm . 'scorm'; + } + + /* Normal upgrade procedure: start by updating main, statistic, user databases */ + + // If this script has been included by index.php, not update_courses.php, so + // that we want to change the main databases as well... + $only_test = false; + $log = 0; + if (defined('SYSTEM_INSTALLATION')) { + if ($singleDbForm) { + $dbStatsForm = $dbNameForm; + $dbScormForm = $dbNameForm; + $dbUserForm = $dbNameForm; + } + /** + * Update the databases "pre" migration + */ + include '../lang/english/create_course.inc.php'; + + if ($languageForm != 'english') { + //languageForm has been escaped in index.php + include '../lang/' . $languageForm . '/create_course.inc.php'; + } + + // Get the main queries list (m_q_list) + $m_q_list = get_sql_file_contents('migrate-db-1.8.0-1.8.2-pre.sql', 'main'); + if (count($m_q_list) > 0) { + //now use the $m_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (strlen($dbNameForm) > 40) { + error_log('Database name ' . $dbNameForm . ' is too long, skipping', 0); + } elseif (!in_array($dbNameForm, $dblist)) { + error_log('Database ' . $dbNameForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbNameForm); + foreach ($m_q_list as $query) { + if ($only_test) { + error_log("Database::query($dbNameForm,$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In $dbNameForm, executed: $query", 0); + } + } + } + } + } + + // Get the stats queries list (s_q_list) + $s_q_list = get_sql_file_contents('migrate-db-1.8.0-1.8.2-pre.sql', 'stats'); + + if (count($s_q_list) > 0) { + // Now use the $s_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (strlen($dbStatsForm) > 40) { + error_log('Database name ' . $dbStatsForm . ' is too long, skipping', 0); + } elseif (!in_array($dbStatsForm, $dblist)) { + error_log('Database ' . $dbStatsForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbStatsForm); + foreach ($s_q_list as $query) { + if ($only_test) { + error_log("Database::query($dbStatsForm,$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In $dbStatsForm, executed: $query", 0); + } + } + } + } + } + // Get the user queries list (u_q_list) + $u_q_list = get_sql_file_contents('migrate-db-1.8.0-1.8.2-pre.sql', 'user'); + if (count($u_q_list) > 0) { + //now use the $u_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (strlen($dbUserForm) > 40) { + error_log('Database name ' . $dbUserForm . ' is too long, skipping', 0); + } elseif (!in_array($dbUserForm, $dblist)) { + error_log('Database ' . $dbUserForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbUserForm); + foreach ($u_q_list as $query) { + if ($only_test) { + error_log("Database::query($dbUserForm,$query)", 0); + error_log("In $dbUserForm, executed: $query", 0); + } else { + $res = Database::query($query); + } + } + } + } + // The SCORM database doesn't need a change in the pre-migrate part - ignore + } + + $prefix = ''; + if ($singleDbForm) { + $prefix = $_configuration['table_prefix']; + } + // Get the courses databases queries list (c_q_list) + $c_q_list = get_sql_file_contents('migrate-db-1.8.0-1.8.2-pre.sql', 'course'); + if (count($c_q_list) > 0) { + // Get the courses list + if (strlen($dbNameForm) > 40) { + error_log('Database name ' . $dbNameForm . ' is too long, skipping', 0); + } elseif (!in_array($dbNameForm, $dblist)) { + error_log('Database ' . $dbNameForm . ' was not found, skipping', 0); + } else { + Database::select_db($dbNameForm); + $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); + if ($res === false) { + die('Error while querying the courses list in update_db-1.8.0-1.8.2.inc.php'); + } + if (Database::num_rows($res) > 0) { + $i = 0; $list = array(); - while($row = Database::fetch_array($res)) { - $list[] = $row; - $i++; - } - foreach ($list as $row_course) { - // Now use the $c_q_list - /** - * We connect to the right DB first to make sure we can use the queries - * without a database name - */ - if (!$singleDbForm) { // otherwise just use the main one - Database::select_db($row_course['db_name']); - } - - foreach ($c_q_list as $query) { - if ($singleDbForm) { - $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix{$row_course['db_name']}_$2$3", $query); - } - - if ($only_test) { - error_log("Database::query(".$row_course['db_name'].",$query)", 0); - } else { - $res = Database::query($query); - if ($log) { - error_log("In ".$row_course['db_name'].", executed: $query", 0); - } - } - } - } - } - } - } - + while ($row = Database::fetch_array($res)) { + $list[] = $row; + $i++; + } + foreach ($list as $row_course) { + // Now use the $c_q_list + /** + * We connect to the right DB first to make sure we can use the queries + * without a database name + */ + if (!$singleDbForm) { // otherwise just use the main one + Database::select_db($row_course['db_name']); + } + + foreach ($c_q_list as $query) { + if ($singleDbForm) { + $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix{$row_course['db_name']}_$2$3", $query); + } + + if ($only_test) { + error_log("Database::query(" . $row_course['db_name'] . ",$query)", 0); + } else { + $res = Database::query($query); + if ($log) { + error_log("In " . $row_course['db_name'] . ", executed: $query", 0); + } + } + } + } + } + } + } } else { - echo 'You are not allowed here !'; - + echo 'You are not allowed here !'; } diff --git a/main/install/update-db-1.8.2-1.8.3.inc.php b/main/install/update-db-1.8.2-1.8.3.inc.php old mode 100755 new mode 100644 index 2ffbfb2227..ded0a8e53f --- a/main/install/update-db-1.8.2-1.8.3.inc.php +++ b/main/install/update-db-1.8.2-1.8.3.inc.php @@ -16,6 +16,7 @@ * - reorganise code into functions * @todo use database library */ +Log::notice("Starting " . basename(__FILE__)); // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-db-1.8.3-1.8.4.inc.php b/main/install/update-db-1.8.3-1.8.4.inc.php old mode 100755 new mode 100644 index b89ee50db1..7a0cc91bba --- a/main/install/update-db-1.8.3-1.8.4.inc.php +++ b/main/install/update-db-1.8.3-1.8.4.inc.php @@ -16,6 +16,7 @@ * - reorganise code into functions * @todo use database library */ +Log::notice("Starting " . basename(__FILE__)); // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-db-1.8.4-1.8.5.inc.php b/main/install/update-db-1.8.4-1.8.5.inc.php old mode 100755 new mode 100644 index ff48f5651d..6026e78ed6 --- a/main/install/update-db-1.8.4-1.8.5.inc.php +++ b/main/install/update-db-1.8.4-1.8.5.inc.php @@ -16,6 +16,7 @@ * - reorganise code into functions * @todo use database library */ +Log::notice("Starting " . basename(__FILE__)); $old_file_version = '1.8.4'; $new_file_version = '1.8.5'; diff --git a/main/install/update-db-1.8.5-1.8.6.inc.php b/main/install/update-db-1.8.5-1.8.6.inc.php index 84bb4bbe9a..2316f22f3c 100644 --- a/main/install/update-db-1.8.5-1.8.6.inc.php +++ b/main/install/update-db-1.8.5-1.8.6.inc.php @@ -16,12 +16,11 @@ * - reorganise code into functions * @todo use database library */ +Log::notice("Starting " . basename(__FILE__)); $old_file_version = '1.8.5'; $new_file_version = '1.8.6'; -Log::notice("Starting update db " . $old_file_version . ' -> ' . $new_file_version); - // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-db-1.8.6-1.8.6.1.inc.php b/main/install/update-db-1.8.6-1.8.6.1.inc.php index 89a5fed4f3..ae8cac3b5e 100644 --- a/main/install/update-db-1.8.6-1.8.6.1.inc.php +++ b/main/install/update-db-1.8.6-1.8.6.1.inc.php @@ -16,12 +16,11 @@ * - reorganise code into functions * @todo use database library */ +Log::notice("Starting " . basename(__FILE__)); $old_file_version = '1.8.6'; $new_file_version = '1.8.6.1'; -Log::notice("Starting update db " . $old_file_version . ' -> ' . $new_file_version); - //check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php index 3d937b9b98..2beef202c9 100644 --- a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php +++ b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php @@ -16,12 +16,11 @@ * - reorganise code into functions * @todo use database library */ +Log::notice("Starting " . basename(__FILE__)); $old_file_version = '1.8.6.1'; $new_file_version = '1.8.6.2'; -Log::notice("Starting update db " . $old_file_version . ' -> ' . $new_file_version); - // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index 2c4f76b233..2e62f46dd0 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -16,12 +16,11 @@ * - reorganise code into functions * @todo use database library */ +Log::notice("Starting " . basename(__FILE__)); $old_file_version = '1.8.6.2'; $new_file_version = '1.8.7'; -Log::notice("Starting update db " . $old_file_version . ' -> ' . $new_file_version); - // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-db-1.8.7-1.8.8.inc.php b/main/install/update-db-1.8.7-1.8.8.inc.php index 6f1beb00db..2651274443 100644 --- a/main/install/update-db-1.8.7-1.8.8.inc.php +++ b/main/install/update-db-1.8.7-1.8.8.inc.php @@ -16,12 +16,11 @@ * - reorganise code into functions * @todo use database library */ +Log::notice("Starting " . basename(__FILE__)); $old_file_version = '1.8.7'; $new_file_version = '1.8.8'; -Log::notice("Starting update db " . $old_file_version . ' -> ' . $new_file_version); - // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-db-1.8.8-1.9.0.inc.php b/main/install/update-db-1.8.8-1.9.0.inc.php index 399c4581b8..1df9d83aad 100755 --- a/main/install/update-db-1.8.8-1.9.0.inc.php +++ b/main/install/update-db-1.8.8-1.9.0.inc.php @@ -16,12 +16,11 @@ * - reorganise code into functions * @todo use database library */ +Log::notice("Starting " . basename(__FILE__)); $old_file_version = '1.8.8'; $new_file_version = '1.9.0'; -Log::notice("Starting update db " . $old_file_version . ' -> ' . $new_file_version); - // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-db-scorm-1.6.x-1.8.0.inc.php b/main/install/update-db-scorm-1.6.x-1.8.0.inc.php old mode 100755 new mode 100644 index bc28776f1f..37552463f0 --- a/main/install/update-db-scorm-1.6.x-1.8.0.inc.php +++ b/main/install/update-db-scorm-1.6.x-1.8.0.inc.php @@ -12,6 +12,8 @@ /** * Include mandatory libraries */ +Log::notice("Starting " . basename(__FILE__)); + require_once api_get_path(LIBRARY_PATH).'document.lib.php'; require_once api_get_path(LIBRARY_PATH).'fileManage.lib.php'; //check_name_exists() require_once api_get_path(SYS_CODE_PATH).'newscorm/learnpath.class.php'; From ed346d247050a703645edceba913eb4391951bbc Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Tue, 8 May 2012 11:14:47 +0200 Subject: [PATCH 062/128] Adding zoom_in zoom_out icons, should fix bug in #4689 --- main/img/icons/22/zoom_in.png | Bin 0 -> 1971 bytes main/img/icons/22/zoom_out.png | Bin 0 -> 1951 bytes main/img/icons/32/zoom_in.png | Bin 0 -> 1971 bytes main/img/icons/32/zoom_out.png | Bin 0 -> 1951 bytes main/mySpace/access_details.php | 2 +- main/mySpace/slider.css | 6 ++---- main/mySpace/slider.js | 4 ++-- 7 files changed, 5 insertions(+), 7 deletions(-) create mode 100644 main/img/icons/22/zoom_in.png create mode 100644 main/img/icons/22/zoom_out.png create mode 100644 main/img/icons/32/zoom_in.png create mode 100644 main/img/icons/32/zoom_out.png diff --git a/main/img/icons/22/zoom_in.png b/main/img/icons/22/zoom_in.png new file mode 100644 index 0000000000000000000000000000000000000000..18e4383b3f05da224689b17829d1b579d32f8c23 GIT binary patch literal 1971 zcmV;k2Tb^hP)RUx6k5PybOkT zA8Z^qM3^|(IP!u?)P_);C`;QYO%N(-kQ!B0XecehK`DqECIDZaHWvcV<6x%<6$<>%$w!C*K?o8mO+3g3Q?bQXL)naxxe$>bI*Ch8HR!X z=f&OWx2-+fT4crY3ddm;fm)4OMjXc_>9s!|k8RqyW4n)T8Fvlfg|+M4b&Kkcx?GOM z?QLzS_12)k;kaSWWGsfyMtwLsJd8*rcK*`~pS17W`)2sd0&rWl_NH=!swK+_67jh#7##R)4dkqjN>z`|H=C zu&@Zx$s}Ida~PMR8VXCw;B=KhlsE_iM<6`nkqKNIzl;So4!>Q$63zlELZR#U{hl{5 zH28N}zbznQrJ1g65X&pqGZ^?F}@`l%`7?{3+Rm$vVP z&I?e6i1fQ#csF5Vz)vQ1!O3CL*yYV0%VCtwYLHTBNVWf1@pyxGT-?CD3sNfd8MTU zuVKWm!eX_fhW30iYf!Wlgd{;1B}j@w5i8IYiCoKYIuuwH5t1yRbbb-pCdo$@rZ4iz zeCLydyrJvR$dF#3C>Ar*V@!5^N_G}GTU@b_Pf^6KH{ORv>{*?|hVQKeuV#?Ras+3A zMq9ujn9p2*bDsj%4|HZg#*!qHd<2lvkuX^B3V2dLAO+asydcveoax)399AfLP19j; zI?a_#6?OWYZ;zQt5@w*0u|QE!ohJYdae~^u=>>Done4k>r^xBIO|PtCtV}Q@DSDA| zfvv}z3h2NWXmF-PG(C0o>Npu2XqaaOD|o(8n$CNc5;28fTtz66qQ!YrdbYTcvleJF zPl|;jDSWNeYWiTln9qCx^u*-kuv05CrMT=H_PHW65A7LRF7yScb_- z(XpK1c@C{DwP&19+jX&Cos5u~cW zwmw7ic^o@_f^tI8N6vqIf%(oy0aKC!}vrHfBs7^y1UnK_bqPx(T4~7x08i77XZ7oL_D6c z+w9|kK=A9{g$v;(h^3Aw9Ml05x()u66N$7Hv7`l|xQs$0i)LpO-`i7 zD5bqVtHpDad^|NHk;<`xQ>XulBS!{t@4fX@#vQaxNz~TW!-G?3|8;BXp^e9t+vNgx z(`P%4`9(#=wcmO6xi^Z7i>e=NYC?HM89W}(OmSg#A`l4R^UGIo`t)h2skB~RQO>i6 z7>Oz=FWT^E=MuQ(&w)=iWB4f0{_>GqLU6bE&T4oujRlJq)z`PRcfROwIF_-xJ{y3p zR4f)db>#4&-9F#w^`C6s(qCCq15t6|e&rlm<+p&&cR<~WAYLX2{gx27dn%T4YOv?B zA{vg|c1_P`B-A_*qY=vG(mg-kyltqhGKg+lFF0ywpbCl3eFP!h7J{4OaZSuAqTHgf zu%t-kjvAXgk4DXVuRStU@4SL4w@zJEobu4QHwUrNgovryLy!Gz@B|CwPTk7LB`1rL zJ>U6n8WXwSGP#J@J>TO!hdRzhYvGToNG7!@od(y^4EoTp3vDYD6g%Z()2*7v-MeNW zzSVP}<3zX-foSqZhz!Luh|lZ4;g`MS>BM|z+nOQPHK}~DW{ziG?O#s!S+59v zl>oCL%4if!|E;8PC8tvQs|J{cu;*&ablHzj*Mk2EFaW%tGd~88zJLG#002ovPDHLk FV1hoG#FGF3 literal 0 HcmV?d00001 diff --git a/main/img/icons/22/zoom_out.png b/main/img/icons/22/zoom_out.png new file mode 100644 index 0000000000000000000000000000000000000000..2bdc37ab3d75591e2cd3bf1940cfc2c8ca59002c GIT binary patch literal 1951 zcmV;Q2VnS#P)mRMODTR^I z1(7BM2oG&QVOnSx2PmY(aU4IceQn>z&Ua&Hp`yf9sdlB~Yv22wbAIRX{my63vMl^R zFYb2lwsmb^DJza&avUBepiXO+631}~`s`8F=u5kH?(owi>y80#+?**o=h0dQNlb*+;n_LYNQB^$E=a9e)8wX?9WsQbBRH=&@QzaLypa|JO2;E{FTEp2OG6Zq+- zjVLNAMkJQN&-Wa`m570&(sFnTN+C)d1c4(UJk;<6Zj4>U0vCrjH?4&y--%FY5`WmU z7X$qtd3z52bs`r4V&*P2FI(QZopl zGL96rRGOMlr?$}r9x0065_!mq09oQuu$JQdEg}pyeNVb*j*wm5xT|Wxu2{BuceXJIVy((29x`Lc5~g5~vOrM~&l3OxDuLSZ(lbG}?w7rXAZt zDAU9VDdL6{mC2y@pWo2nCJ@WKUFWH*>;uw7!=&Y1Hw5koRfyM$zHTt|>te?vo>*7G=iVu*S|FfU&C_!6_7 z3l-aG8u9<+Kng81`ay3yIWp1XT-(+eLS>e)dW##{i{WyDoAo#)CM3j~7S@hx14LISbW9f6xB zVBBjoFHWQNcdL{4Z9c&mF*WCbgd~q-esOV0-H)Dp>aCKJ;+kd6 z&8Vm>hu7vw zV&5%6aJTr)IJ|^p!J*$OoX2YUPeA*7#9ZWe_(cL?-V(%@or+cFO6@YWsQOok9<5ks(IYGYX-y*x(>7rO*J79N!$z~O);q&oBHf> z-Dv@bE*~WZt`}zSkHQ7+(DgGy3?pa08*{leClK^IeC@0C!{;edrmdR4;n+A{t lk(c3?EbXgVF8Hqi0{|13K^-xaz?uL6002ovPDHLkV1iEptQ!CT literal 0 HcmV?d00001 diff --git a/main/img/icons/32/zoom_in.png b/main/img/icons/32/zoom_in.png new file mode 100644 index 0000000000000000000000000000000000000000..18e4383b3f05da224689b17829d1b579d32f8c23 GIT binary patch literal 1971 zcmV;k2Tb^hP)RUx6k5PybOkT zA8Z^qM3^|(IP!u?)P_);C`;QYO%N(-kQ!B0XecehK`DqECIDZaHWvcV<6x%<6$<>%$w!C*K?o8mO+3g3Q?bQXL)naxxe$>bI*Ch8HR!X z=f&OWx2-+fT4crY3ddm;fm)4OMjXc_>9s!|k8RqyW4n)T8Fvlfg|+M4b&Kkcx?GOM z?QLzS_12)k;kaSWWGsfyMtwLsJd8*rcK*`~pS17W`)2sd0&rWl_NH=!swK+_67jh#7##R)4dkqjN>z`|H=C zu&@Zx$s}Ida~PMR8VXCw;B=KhlsE_iM<6`nkqKNIzl;So4!>Q$63zlELZR#U{hl{5 zH28N}zbznQrJ1g65X&pqGZ^?F}@`l%`7?{3+Rm$vVP z&I?e6i1fQ#csF5Vz)vQ1!O3CL*yYV0%VCtwYLHTBNVWf1@pyxGT-?CD3sNfd8MTU zuVKWm!eX_fhW30iYf!Wlgd{;1B}j@w5i8IYiCoKYIuuwH5t1yRbbb-pCdo$@rZ4iz zeCLydyrJvR$dF#3C>Ar*V@!5^N_G}GTU@b_Pf^6KH{ORv>{*?|hVQKeuV#?Ras+3A zMq9ujn9p2*bDsj%4|HZg#*!qHd<2lvkuX^B3V2dLAO+asydcveoax)399AfLP19j; zI?a_#6?OWYZ;zQt5@w*0u|QE!ohJYdae~^u=>>Done4k>r^xBIO|PtCtV}Q@DSDA| zfvv}z3h2NWXmF-PG(C0o>Npu2XqaaOD|o(8n$CNc5;28fTtz66qQ!YrdbYTcvleJF zPl|;jDSWNeYWiTln9qCx^u*-kuv05CrMT=H_PHW65A7LRF7yScb_- z(XpK1c@C{DwP&19+jX&Cos5u~cW zwmw7ic^o@_f^tI8N6vqIf%(oy0aKC!}vrHfBs7^y1UnK_bqPx(T4~7x08i77XZ7oL_D6c z+w9|kK=A9{g$v;(h^3Aw9Ml05x()u66N$7Hv7`l|xQs$0i)LpO-`i7 zD5bqVtHpDad^|NHk;<`xQ>XulBS!{t@4fX@#vQaxNz~TW!-G?3|8;BXp^e9t+vNgx z(`P%4`9(#=wcmO6xi^Z7i>e=NYC?HM89W}(OmSg#A`l4R^UGIo`t)h2skB~RQO>i6 z7>Oz=FWT^E=MuQ(&w)=iWB4f0{_>GqLU6bE&T4oujRlJq)z`PRcfROwIF_-xJ{y3p zR4f)db>#4&-9F#w^`C6s(qCCq15t6|e&rlm<+p&&cR<~WAYLX2{gx27dn%T4YOv?B zA{vg|c1_P`B-A_*qY=vG(mg-kyltqhGKg+lFF0ywpbCl3eFP!h7J{4OaZSuAqTHgf zu%t-kjvAXgk4DXVuRStU@4SL4w@zJEobu4QHwUrNgovryLy!Gz@B|CwPTk7LB`1rL zJ>U6n8WXwSGP#J@J>TO!hdRzhYvGToNG7!@od(y^4EoTp3vDYD6g%Z()2*7v-MeNW zzSVP}<3zX-foSqZhz!Luh|lZ4;g`MS>BM|z+nOQPHK}~DW{ziG?O#s!S+59v zl>oCL%4if!|E;8PC8tvQs|J{cu;*&ablHzj*Mk2EFaW%tGd~88zJLG#002ovPDHLk FV1hoG#FGF3 literal 0 HcmV?d00001 diff --git a/main/img/icons/32/zoom_out.png b/main/img/icons/32/zoom_out.png new file mode 100644 index 0000000000000000000000000000000000000000..2bdc37ab3d75591e2cd3bf1940cfc2c8ca59002c GIT binary patch literal 1951 zcmV;Q2VnS#P)mRMODTR^I z1(7BM2oG&QVOnSx2PmY(aU4IceQn>z&Ua&Hp`yf9sdlB~Yv22wbAIRX{my63vMl^R zFYb2lwsmb^DJza&avUBepiXO+631}~`s`8F=u5kH?(owi>y80#+?**o=h0dQNlb*+;n_LYNQB^$E=a9e)8wX?9WsQbBRH=&@QzaLypa|JO2;E{FTEp2OG6Zq+- zjVLNAMkJQN&-Wa`m570&(sFnTN+C)d1c4(UJk;<6Zj4>U0vCrjH?4&y--%FY5`WmU z7X$qtd3z52bs`r4V&*P2FI(QZopl zGL96rRGOMlr?$}r9x0065_!mq09oQuu$JQdEg}pyeNVb*j*wm5xT|Wxu2{BuceXJIVy((29x`Lc5~g5~vOrM~&l3OxDuLSZ(lbG}?w7rXAZt zDAU9VDdL6{mC2y@pWo2nCJ@WKUFWH*>;uw7!=&Y1Hw5koRfyM$zHTt|>te?vo>*7G=iVu*S|FfU&C_!6_7 z3l-aG8u9<+Kng81`ay3yIWp1XT-(+eLS>e)dW##{i{WyDoAo#)CM3j~7S@hx14LISbW9f6xB zVBBjoFHWQNcdL{4Z9c&mF*WCbgd~q-esOV0-H)Dp>aCKJ;+kd6 z&8Vm>hu7vw zV&5%6aJTr)IJ|^p!J*$OoX2YUPeA*7#9ZWe_(cL?-V(%@or+cFO6@YWsQOok9<5ks(IYGYX-y*x(>7rO*J79N!$z~O);q&oBHf> z-Dv@bE*~WZt`}zSkHQ7+(DgGy3?pa08*{leClK^IeC@0C!{;edrmdR4;n+A{t lk(c3?EbXgVF8Hqi0{|13K^-xaz?uL6002ovPDHLkV1iEptQ!CT literal 0 HcmV?d00001 diff --git a/main/mySpace/access_details.php b/main/mySpace/access_details.php index 9b27cfaa4c..bc36b22b1c 100644 --- a/main/mySpace/access_details.php +++ b/main/mySpace/access_details.php @@ -216,7 +216,7 @@ $form->display(); '; }?>
diff --git a/main/mySpace/slider.css b/main/mySpace/slider.css index 82d04f7136..d38663f79f 100644 --- a/main/mySpace/slider.css +++ b/main/mySpace/slider.css @@ -1,7 +1,5 @@ -div#cev_cont_results -{ - margin: 0; - padding-left:18px; +div#cev_cont_results { + margin: 0; padding-right:18px; } div#cev_cont_header diff --git a/main/mySpace/slider.js b/main/mySpace/slider.js index 2bec3e0f58..4ac0a6a40b 100644 --- a/main/mySpace/slider.js +++ b/main/mySpace/slider.js @@ -59,13 +59,13 @@ function sliderAction() { sliderOpen(); slider_state = "open" - $(".slider_menu").html('Cerrar'); + $(".slider_menu").html(''); } else if (slider_state == "open") { sliderClose(); slider_state = "close"; - $(".slider_menu").html('Más...'); + $(".slider_menu").html(''); } return false; From 7cb2d54497e28d7a85d8423923e1cebf8d29b931 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Tue, 8 May 2012 12:08:32 +0200 Subject: [PATCH 063/128] Adding Twig options in order to improve performance see #4635 --- main/inc/lib/template.lib.php | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/main/inc/lib/template.lib.php b/main/inc/lib/template.lib.php index 8c2cf531f8..49bce70e52 100644 --- a/main/inc/lib/template.lib.php +++ b/main/inc/lib/template.lib.php @@ -42,13 +42,28 @@ class Template { $loader = new Twig_Loader_Filesystem($template_paths); - $this->twig = new Twig_Environment($loader, array( - //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder - 'autoescape' => false, - //'debug' => true, - //'auto_reload' => true - //'optimizations' => 0 // turn on optimizations with -1 - )); + //Setting Twig options depending on the server see http://twig.sensiolabs.org/doc/api.html#environment-options + if (api_get_setting('server_type') == 'test') { + $options = array ( + //'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder + 'autoescape' => false, + 'debug' => true, + 'auto_reload' => true, + 'optimizations' => 0, // turn on optimizations with -1 + 'strict_variables' => true, //If set to false, Twig will silently ignore invalid variables + ); + } else { + $options = array ( + 'cache' => api_get_path(SYS_ARCHIVE_PATH), //path to the cache folder + 'autoescape' => false, + 'debug' => false, + 'auto_reload' => false, + 'optimizations' => -1, // turn on optimizations with -1 + 'strict_variables' => false //If set to false, Twig will silently ignore invalid variables + ); + } + + $this->twig = new Twig_Environment($loader, $options); $this->twig->addFilter('get_lang', new Twig_Filter_Function('get_lang')); $this->twig->addFilter('get_path', new Twig_Filter_Function('api_get_path')); From 21919300def91d8d71bfc9c7eb3a2ba4ba741cac Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 14:48:22 +0200 Subject: [PATCH 064/128] #4694 add feedback during installation --- main/install/update-db-1.8.0-1.8.2.inc.php | 3 +- main/install/update-db-1.8.2-1.8.3.inc.php | 1 + main/install/update-db-1.8.3-1.8.4.inc.php | 1 + main/install/update-db-1.8.4-1.8.5.inc.php | 1 + main/install/update-db-1.8.5-1.8.6.inc.php | 1 + main/install/update-db-1.8.6-1.8.6.1.inc.php | 1 + .../install/update-db-1.8.6.1-1.8.6.2.inc.php | 1 + main/install/update-db-1.8.6.2-1.8.7.inc.php | 1 + main/install/update-db-1.8.7-1.8.8.inc.php | 1 + main/install/update-db-1.8.8-1.9.0.inc.php | 1 + .../update-db-scorm-1.6.x-1.8.0.inc.php | 84 +++++++++---------- 11 files changed, 53 insertions(+), 43 deletions(-) diff --git a/main/install/update-db-1.8.0-1.8.2.inc.php b/main/install/update-db-1.8.0-1.8.2.inc.php index edf3775fc9..4e24dfcc09 100644 --- a/main/install/update-db-1.8.0-1.8.2.inc.php +++ b/main/install/update-db-1.8.0-1.8.2.inc.php @@ -185,7 +185,8 @@ if (defined('SYSTEM_INSTALLATION')) { */ if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); - } + } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.2-1.8.3.inc.php b/main/install/update-db-1.8.2-1.8.3.inc.php index ded0a8e53f..93aecdee35 100644 --- a/main/install/update-db-1.8.2-1.8.3.inc.php +++ b/main/install/update-db-1.8.2-1.8.3.inc.php @@ -184,6 +184,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { //otherwise just use the main one diff --git a/main/install/update-db-1.8.3-1.8.4.inc.php b/main/install/update-db-1.8.3-1.8.4.inc.php index 7a0cc91bba..4206ff3909 100644 --- a/main/install/update-db-1.8.3-1.8.4.inc.php +++ b/main/install/update-db-1.8.3-1.8.4.inc.php @@ -184,6 +184,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.4-1.8.5.inc.php b/main/install/update-db-1.8.4-1.8.5.inc.php index 6026e78ed6..cd0d2b3639 100644 --- a/main/install/update-db-1.8.4-1.8.5.inc.php +++ b/main/install/update-db-1.8.4-1.8.5.inc.php @@ -191,6 +191,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.5-1.8.6.inc.php b/main/install/update-db-1.8.5-1.8.6.inc.php index 2316f22f3c..fe6129ea24 100644 --- a/main/install/update-db-1.8.5-1.8.6.inc.php +++ b/main/install/update-db-1.8.5-1.8.6.inc.php @@ -1102,6 +1102,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { //otherwise just use the main one diff --git a/main/install/update-db-1.8.6-1.8.6.1.inc.php b/main/install/update-db-1.8.6-1.8.6.1.inc.php index ae8cac3b5e..4290c4fd30 100644 --- a/main/install/update-db-1.8.6-1.8.6.1.inc.php +++ b/main/install/update-db-1.8.6-1.8.6.1.inc.php @@ -192,6 +192,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php index 2beef202c9..55768dcc10 100644 --- a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php +++ b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php @@ -296,6 +296,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index 2e62f46dd0..b47c50e63a 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -401,6 +401,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.7-1.8.8.inc.php b/main/install/update-db-1.8.7-1.8.8.inc.php index 2651274443..1dc3ea9ef6 100644 --- a/main/install/update-db-1.8.7-1.8.8.inc.php +++ b/main/install/update-db-1.8.7-1.8.8.inc.php @@ -229,6 +229,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.8-1.9.0.inc.php b/main/install/update-db-1.8.8-1.9.0.inc.php index 1df9d83aad..40e355b554 100755 --- a/main/install/update-db-1.8.8-1.9.0.inc.php +++ b/main/install/update-db-1.8.8-1.9.0.inc.php @@ -264,6 +264,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } + Log::notice(basename(__FILE__) . ' - course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-scorm-1.6.x-1.8.0.inc.php b/main/install/update-db-scorm-1.6.x-1.8.0.inc.php index 37552463f0..e00d6fde5e 100644 --- a/main/install/update-db-scorm-1.6.x-1.8.0.inc.php +++ b/main/install/update-db-scorm-1.6.x-1.8.0.inc.php @@ -81,7 +81,7 @@ while ($row = Database::fetch_array($res)) { $courses_dir_list[$row['code']] = $row['directory']; } -if ($loglevel > 0) { error_log("Tables created/deleted for all courses", 0); } +if ($loglevel > 0) { Log::notice("Tables created/deleted for all courses"); } /** * The migration needs to take all data from the original learnpath tables and add them to the new @@ -91,12 +91,12 @@ if ($loglevel > 0) { error_log("Tables created/deleted for all courses", 0); } // Test only one course foreach ($courses_id_full_table_prefix_list as $course_code => $db) { if (strlen($courses_id_list[$course_code]) > 40) { - error_log('Database '.$courses_id_list[$course_code].' is too long, skipping', 0); + Log::error('Database '.$courses_id_list[$course_code].' is too long, skipping'); continue; } $incoherences = 0; - if ($loglevel > 0) { error_log("Now starting migration of learnpath tables from $db database...", 0); } + if ($loglevel > 0) { Log::notice("Now starting migration of learnpath tables from $db database..."); } $lp_doc = $db.TABLE_DOCUMENT; $lp_main = $db.TABLE_LEARNPATH_MAIN; $lp_ids = array(); @@ -119,13 +119,13 @@ foreach ($courses_id_full_table_prefix_list as $course_code => $db) { $sql_test = "SELECT * FROM $my_new_lp"; $res_test = Database::query($sql_test); $sql_lp = "SELECT * FROM $lp_main"; - if ($loglevel > 1) { error_log("$sql_lp", 0); } + if ($loglevel > 1) { Log::notice("$sql_lp"); } $res_lp = Database::query($sql_lp); if (!$res_lp or !$res_test) { if ($loglevel > 1) { - error_log("+++Problem querying DB $lp_main+++ skipping (".Database::error().")", 0); + Log::error("+++Problem querying DB $lp_main+++ skipping (".Database::error().")"); if (!$res_test) { - error_log("This might be due to no existing table in the destination course", 0); + Log::error("This might be due to no existing table in the destination course"); } } continue; @@ -280,13 +280,13 @@ foreach ($courses_id_full_table_prefix_list as $course_code => $db) { case 'c': // chapter-type prereq $prereq_id = $lp_chap_items[$row['prereq_id']]; - if (empty($prereq_id) && $loglevel > 1) { error_log("Could not find prereq chapter ".$row['prereq_id'], 0); } + if (empty($prereq_id) && $loglevel > 1) { Log::error("Could not find prereq chapter ".$row['prereq_id']); } break; case 'i': default: // item type prereq $prereq_id = $lp_items[$parent_lps[$row['chapter_id']]][$row['prereq_id']]; - if (empty($prereq_id) && $loglevel > 1) { error_log("Could not find prereq item ".$row['prereq_id'], 0); } + if (empty($prereq_id) && $loglevel > 1) { Log::error("Could not find prereq item ".$row['prereq_id']); } break; } } @@ -513,7 +513,7 @@ foreach ($courses_id_full_table_prefix_list as $course_code => $db) { $sql_tool_upd = "UPDATE $tbl_tool " . "SET link='newscorm/lp_controller.php?action=view&lp_id=$new_lp_id' " . "WHERE id = ".$row_tool['id']; - error_log('New LP - Migration - Updating tool table: '.$sql_tool_upd, 0); + Log::notice('New LP - Migration - Updating tool table: '.$sql_tool_upd); // Make sure there is a way of retrieving which links were updated (to revert) fwrite($fh,$sql_tool_upd." AND link ='$link'"); fwrite($fh_revert, "UPDATE $tbl_tool SET link='$link' WHERE id=".$row_tool['id']." AND link ='newscorm/lp_controller.php?action=view&lp_id=$new_lp_id';\n"); @@ -534,7 +534,7 @@ foreach ($courses_id_full_table_prefix_list as $course_code => $db) { if (!empty($matches[3]) && (strtolower(substr($matches[3], -15)) == 'imsmanifest.xml') && !is_file(realpath(urldecode($matches[3])))) { //echo "Removing link $link from tools
"; $sql_tool_upd = "DELETE FROM $tbl_tool WHERE id = ".$row_tool['id']; - error_log('New LP - Migration - Updating tool table (dead link): '.$sql_tool_upd, 0); + Log::notice('New LP - Migration - Updating tool table (dead link): '.$sql_tool_upd); // Make sure there is a way of retrieving which links were updated (to revert) fwrite($fh, $sql_tool_upd." AND link ='$link'"); fwrite($fh_revert, "INSERT INTO $tbl_tool (link) VALUES ('$link');\n"); @@ -579,7 +579,7 @@ foreach ($courses_id_full_table_prefix_list as $course_code => $db) { } } - if ($loglevel > 0) { error_log("Done!".$msg, 0); } + if ($loglevel > 0) { Log::notice("Done!".$msg); } //flush(); //ob_flush(); } @@ -602,7 +602,7 @@ fwrite($fh_res, "-- Recording resulting course homepages links changes for SCORM * The migration needs to take all data from the scorm.scorm_main and scorm.scorm_sco_data tables * and add them to the new lp, lp_view, lp_item and lp_item_view tables. */ -if ($loglevel > 0) { error_log("Now starting migration of scorm tables from global SCORM database", 0); } +if ($loglevel > 0) { Log::notice("Now starting migration of scorm tables from global SCORM database"); } $scorm_main = $dbScormForm.'.'.TABLE_SCORM_MAIN; $scorm_item = $dbScormForm.'.'.TABLE_SCORM_SCO_DATA; @@ -619,7 +619,7 @@ $scorm_lp_paths = array(); Database::select_db($dbNameForm); $course_main = TABLE_MAIN_COURSE; $sql_crs = "SELECT * FROM $course_main WHERE target_course_code IS NULL"; -if ($loglevel > 0) { error_log("$sql_crs", 0); } +if ($loglevel > 0) { Log::notice("$sql_crs"); } $res_crs = Database::query($sql_crs); $num = Database::num_rows($res_crs); @@ -629,7 +629,7 @@ $course_code_swap = ''; $scormdocuments_lps = array(); while ($course_row = Database::fetch_array($res_crs)) { - if ($loglevel > 0) { error_log("Now dealing with course ".$course_row['code']."...", 0); } + if ($loglevel > 0) { Log::notice("Now dealing with course ".$course_row['code']."..."); } // Check the validity of this new course $my_course_code = $course_row['code']; @@ -637,21 +637,21 @@ while ($course_row = Database::fetch_array($res_crs)) { //$scormdocuments_lps = array(); $db_name = $courses_id_full_table_prefix_list[$my_course_code]; if (strlen($courses_id_list[$course_code]) > 40) { - error_log('Database '.$courses_id_list[$course_code].' is too long, skipping', 0); + Log::notice('Database '.$courses_id_list[$course_code].' is too long, skipping'); continue; } //echo "Now processing database $db_name
"; $tblscodoc = $db_name.TABLE_SCORMDOC; $sql_scodoc = "SELECT path FROM $tblscodoc WHERE path IS NOT NULL AND path != ''"; - if ($loglevel > 1) { error_log("$sql_scodoc", 0); } + if ($loglevel > 1) { Log::notice("$sql_scodoc"); } $res_scodoc = Database::query($sql_scodoc); while ($row_scodoc = Database::fetch_array($res_scodoc)) { // Check if there's more than one slash in total if (strpos($row_scodoc['path'], '/', 1) === false) { $tmp_path = $row_scodoc['path']; - if ($loglevel > 1) { error_log("++Now opening $tmp_path", 0); } + if ($loglevel > 1) { Log::notice("++Now opening $tmp_path"); } // Add a prefixing slash if there is none if (substr($tmp_path, 0, 1) != '/') { @@ -672,17 +672,17 @@ while ($course_row = Database::fetch_array($res_crs)) { // Avoid if contentTitle is not the name of an existing directory } elseif (!is_file($courses_dir."/imsmanifest.xml")) { // If the imsmanifest file was not found there - if ($loglevel > 2) { error_log(" !!imsmanifest.xml not found at scormdocument's $courses_dir/imsmanifest.xml, skipping", 0); } + if ($loglevel > 2) { Log::error(" !!imsmanifest.xml not found at scormdocument's $courses_dir/imsmanifest.xml, skipping"); } // Try subdirectories on one level depth - if ($loglevel > 2) { error_log(" Trying subdirectories...", 0); } + if ($loglevel > 2) { Log::notice(" Trying subdirectories..."); } $dh = opendir($courses_dir); while ($entry = readdir($dh)) { if (substr($entry, 0, 1) != '.') { if (is_dir($courses_dir."/".$entry)) { if (is_file($courses_dir."/".$entry."/imsmanifest.xml")) { - if ($loglevel > 2) { error_log(". .. and found $courses_dir/$entry/imsmanifest.xml!", 0); } + if ($loglevel > 2) { Log::notice(". .. and found $courses_dir/$entry/imsmanifest.xml!"); } if (!in_array($tmp_path."/".$entry."/imsmanifest.xml",$scormdocuments_lps)) { - if ($loglevel > 2){ error_log(" Recording.
", 0); } + if ($loglevel > 2){ Log::notice(" Recording.
"); } $scormdocuments_lps[] = $tmp_path."/".$entry; } } @@ -690,7 +690,7 @@ while ($course_row = Database::fetch_array($res_crs)) { } } } else { - if ($loglevel > 2) { error_log(" Found scormdocument $tmp_path in ".$sys_course_path.$courses_dir_list[$my_course_code]."/scorm, treating it.", 0); } + if ($loglevel > 2) { Log::notice(" Found scormdocument $tmp_path in ".$sys_course_path.$courses_dir_list[$my_course_code]."/scorm, treating it."); } $scormdocuments_lps[] = $tmp_path; } } @@ -736,9 +736,9 @@ while ($course_row = Database::fetch_array($res_crs)) { //echo "Checking if manifest exists in ".$courses_dir.$entry."/imsmanifest.xml
"; if (is_file($courses_dir.$entry."/imsmanifest.xml")) { //echo "found $courses_dir/$entry/imsmanifest.xml!
"; - if ($loglevel > 2) { error_log(". .. and found $courses_dir/$entry/imsmanifest.xml!", 0); } + if ($loglevel > 2) { Log::notice(". .. and found $courses_dir/$entry/imsmanifest.xml!"); } if (!in_array($entry."/imsmanifest.xml", $scormdocuments_lps)) { - if ($loglevel > 2) { error_log(" Recording.
", 0); } + if ($loglevel > 2) { Log::notice(" Recording.
"); } //echo "Recording $entry
"; $scormdocuments_lps[] = $entry; } @@ -756,7 +756,7 @@ while ($course_row = Database::fetch_array($res_crs)) { $scorms[$my_course_code] = array(); $sql_paths = "SELECT * FROM $scorm_main WHERE dokeosCourse = '".$my_course_code."'"; - if ($loglevel > 0) { error_log("$sql_paths", 0); } + if ($loglevel > 0) { Log::notice("$sql_paths"); } $res_paths = Database::query($sql_paths); $num = Database::num_rows($res_paths); while ($scorm_row = Database::fetch_array($res_paths)) { @@ -769,16 +769,16 @@ while ($course_row = Database::fetch_array($res_crs)) { if ($my_path == '/') { $my_path = ''; } - if ($loglevel > 1) { error_log("++++Now opening $my_path", 0); } + if ($loglevel > 1) { Log::notice("++++Now opening $my_path"); } if (!is_dir($courses_dir = $sys_course_path.''.$courses_dir_list[$my_course_code].'/scorm'.$my_path)) { - if ($loglevel > 1) { error_log("Path $my_content_id: $my_path doesn't exist in ".$sys_course_path.$courses_dir_list[$my_course_code]."/scorm, skipping", 0); } + if ($loglevel > 1) { Log::notice("Path $my_content_id: $my_path doesn't exist in ".$sys_course_path.$courses_dir_list[$my_course_code]."/scorm, skipping"); } continue; // Avoid if contentTitle is not the name of an existing directory } elseif (!is_file($sys_course_path.$courses_dir_list[$my_course_code].'/scorm'.$my_path."/imsmanifest.xml")) { - if ($loglevel > 1) { error_log("!!imsmanifest.xml not found at ".$sys_course_path.$courses_dir_list[$my_course_code].'/scorm'.$my_path."/imsmanifest.xml, skipping", 0); } + if ($loglevel > 1) { Log::notice("!!imsmanifest.xml not found at ".$sys_course_path.$courses_dir_list[$my_course_code].'/scorm'.$my_path."/imsmanifest.xml, skipping"); } continue; } else { - if ($loglevel > 1) { error_log("Found $my_path in ".$sys_course_path.$courses_dir_list[$my_course_code]."/scorm".$mypath."/imsmanifest.xml, keeping it.", 0); } + if ($loglevel > 1) { Log::notice("Found $my_path in ".$sys_course_path.$courses_dir_list[$my_course_code]."/scorm".$mypath."/imsmanifest.xml, keeping it."); } $scorms[$my_course_code][$my_path] = $my_content_id; } } @@ -787,7 +787,7 @@ while ($course_row = Database::fetch_array($res_crs)) { foreach ($scormdocuments_lps as $path) { if (!in_array($path,array_keys($scorms[$my_course_code]))) { // Add it (-1 means no ID) - if ($loglevel > 1) { error_log("** Scormdocument path $path wasn't recorded yet. Added.", 0); } + if ($loglevel > 1) { Log::notice("** Scormdocument path $path wasn't recorded yet. Added."); } $scorms[$my_course_code][$path] = -1; } } @@ -801,7 +801,7 @@ $my_count = 0; foreach ($scorms as $mycourse => $my_paths) { $my_count += count($my_paths); } -if ($loglevel > 0) { error_log("---- Scorms array now contains ".$mycount." paths to migrate. Starting migration...", 0); } +if ($loglevel > 0) { Log::notice("---- Scorms array now contains ".$mycount." paths to migrate. Starting migration..."); } /** * Looping through the SCO_MAIN table for SCORM learnpath attached to courses @@ -813,9 +813,9 @@ foreach ($scorms as $my_course_code => $paths_list) { $course_lp_done = array(); $db_name = $courses_id_full_table_prefix_list[$my_course_code]; foreach ($paths_list as $my_path => $old_id) { - if ($loglevel > 1) { error_log("Migrating lp $my_path from course $my_course_code...", 0); } + if ($loglevel > 1) { Log::notice("Migrating lp $my_path from course $my_course_code..."); } $i_count ++; - //error_log('New LP - Migration script - Content '.$i_count.' on '.$num.' (course '.$scorm['dokeosCourse'].')',0); + //Log::notice('New LP - Migration script - Content '.$i_count.' on '.$num.' (course '.$scorm['dokeosCourse'].')'); // Check whether there is no embedded learnpaths into other learnpaths (one root-level and another embedded) $embedded = false; foreach ($course_lp_done as $tmp_lp) { @@ -826,7 +826,7 @@ foreach ($scorms as $my_course_code => $paths_list) { // Let it be } else { // This lp is embedded inside another lp who's imsmanifest exists, so prevent from parsing - if ($loglevel > 1) { error_log("LP $my_path is embedded into $tmp_lp, ignoring...", 0); } + if ($loglevel > 1) { Log::notice("LP $my_path is embedded into $tmp_lp, ignoring..."); } $embedded = true; continue; } @@ -840,7 +840,7 @@ foreach ($scorms as $my_course_code => $paths_list) { $my_path = $my_path; $my_name = basename($my_path); - if ($loglevel > 1) { error_log("Try importing LP $my_path from imsmanifest first as it is more reliable", 0); } + if ($loglevel > 1) { Log::notice("Try importing LP $my_path from imsmanifest first as it is more reliable"); } // Setup the ims path (path to the imsmanifest.xml file) //echo "Looking for course with code ".$lp_course_code[$my_content_id]." (using $my_content_id)
\n"; @@ -855,7 +855,7 @@ foreach ($scorms as $my_course_code => $paths_list) { $oScorm = new scorm(); // Check whether imsmanifest.xml exists at this location. If not, ignore the imsmanifest. // That should have been done before already, now. - if ($loglevel > 1) { error_log("Found imsmanifest ($ims), importing...", 0); } + if ($loglevel > 1) { Log::notice("Found imsmanifest ($ims), importing..."); } if (!empty($sco_middle_path)) { $oScorm->subdir = $sco_middle_path; } //this sets the subdir for the scorm package inside the scorm dir // Parse manifest file $manifest = $oScorm->parse_manifest($ims); @@ -864,7 +864,7 @@ foreach ($scorms as $my_course_code => $paths_list) { //TODO: Add code to update the path in that new lp created, as it probably uses / where // $sco_path_temp should be used... $lp_ids[$my_content_id] = $oScorm->lp_id; // Contains the old LP ID => the new LP ID - if ($loglevel > 1) { error_log(" @@@ Created scorm lp ".$oScorm->lp_id." from imsmanifest [".$ims."] in course $my_course_code", 0); } + if ($loglevel > 1) { Log::notice(" @@@ Created scorm lp ".$oScorm->lp_id." from imsmanifest [".$ims."] in course $my_course_code"); } $lp_course[$my_content_id] = $courses_id_list[$my_course_code]; // Contains the old learnpath ID => the course DB name $lp_course_code[$my_content_id] = $my_course_code; $max_dsp_lp++; @@ -945,7 +945,7 @@ foreach ($scorms as $my_course_code => $paths_list) { } else { //echo "Could not find $ims... Proceeding from database...(line ".__LINE__.")
"; - if ($loglevel > 1) { error_log("This is a normal SCORM path", 0); } + if ($loglevel > 1) { Log::notice("This is a normal SCORM path"); } $scorm_lp_paths[$my_content_id]['path'] = $my_path; //$scorm_lp_paths[$my_content_id]['ims'] = ''; $table_name = $db_name.$new_lp; @@ -972,7 +972,7 @@ foreach ($scorms as $my_course_code => $paths_list) { "'Unknown'," . "'scorm_api.php'" . ")"; - if ($loglevel > 1) { error_log("$sql_ins", 0); } + if ($loglevel > 1) { Log::notice("$sql_ins"); } $sql_res = Database::query($sql_ins); $in_id = Database::insert_id(); if (!$in_id) die('Could not insert scorm lp: '.$sql_ins); @@ -994,7 +994,7 @@ foreach ($scorms as $my_course_code => $paths_list) { // Check whether imsmanifest.xml exists at this location. If not, ignore the imsmanifest. // That should have been done before already, now. if (!is_file($scorm_lp_paths[$my_content_id]['ims'])) { - if ($loglevel > 1) { error_log("!!! imsmanifest file not found at ".$scorm_lp_paths[$my_content_id]['ims'].' for old lp '.$my_content_id.' and new '.$lp_ids[$my_content_id], 0); } + if ($loglevel > 1) { Log::notice("!!! imsmanifest file not found at ".$scorm_lp_paths[$my_content_id]['ims'].' for old lp '.$my_content_id.' and new '.$lp_ids[$my_content_id]); } $manifest = false; } else { //echo "Parsing ".$scorm_lp_paths[$my_content_id]['ims']."
\n"; @@ -1009,7 +1009,7 @@ foreach ($scorms as $my_course_code => $paths_list) { "SET name = '$my_lp_title', " . "default_encoding = '".strtoupper($oScorm->manifest_encoding)."' " . "WHERE id = ".$lp_ids[$my_content_id]; - if ($loglevel > 1) { error_log("Updating title and encoding: ".$my_sql, 0); } + if ($loglevel > 1) { Log::notice("Updating title and encoding: ".$my_sql); } $my_res = Database::query($my_sql); } } @@ -1280,5 +1280,5 @@ foreach ($scorms as $my_course_code => $paths_list) { fclose($fh); fclose($fh_revert); fclose($fh_res); -if ($loglevel > 0) { error_log("All done!", 0); } +if ($loglevel > 0) { Log::notice("All done!"); } //echo ""; From f4d1e63a628d2d9d4d87f163da5b9e7e3c4ff729 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 15:46:08 +0200 Subject: [PATCH 065/128] #4694 add feedback during installation --- main/inc/lib/log.class.php | 71 ++++++++++++++----- main/install/update-db-1.6.x-1.8.0.inc.php | 3 +- main/install/update-db-1.8.0-1.8.2.inc.php | 4 +- main/install/update-db-1.8.2-1.8.3.inc.php | 4 +- main/install/update-db-1.8.3-1.8.4.inc.php | 4 +- main/install/update-db-1.8.4-1.8.5.inc.php | 4 +- main/install/update-db-1.8.5-1.8.6.inc.php | 4 +- main/install/update-db-1.8.6-1.8.6.1.inc.php | 4 +- .../install/update-db-1.8.6.1-1.8.6.2.inc.php | 4 +- main/install/update-db-1.8.6.2-1.8.7.inc.php | 4 +- main/install/update-db-1.8.7-1.8.8.inc.php | 4 +- main/install/update-db-1.8.8-1.9.0.inc.php | 4 +- .../update-db-scorm-1.6.x-1.8.0.inc.php | 2 +- main/install/update-files-1.6.x-1.8.0.inc.php | 2 +- main/install/update-files-1.8.3-1.8.4.inc.php | 2 +- main/install/update-files-1.8.4-1.8.5.inc.php | 2 +- main/install/update-files-1.8.5-1.8.6.inc.php | 2 +- .../update-files-1.8.6-1.8.6.1.inc.php | 2 +- .../update-files-1.8.6.1-1.8.6.2.inc.php | 2 +- .../update-files-1.8.6.2-1.8.7.inc.php | 3 +- main/install/update-files-1.8.7-1.8.8.inc.php | 2 +- main/install/update-files-1.8.8-1.9.0.inc.php | 2 +- 22 files changed, 85 insertions(+), 50 deletions(-) diff --git a/main/inc/lib/log.class.php b/main/inc/lib/log.class.php index ad90bb5929..a711d33d09 100644 --- a/main/inc/lib/log.class.php +++ b/main/inc/lib/log.class.php @@ -2,6 +2,8 @@ use Monolog\Logger; +Log::register_autoload(); + /** * Description of log * @@ -11,7 +13,7 @@ use Monolog\Logger; class Log { - private static function register_autoload() + public static function register_autoload() { static $has_run = false; if ($has_run) { @@ -29,23 +31,56 @@ class Log $has_run = true; } + /** + * + * @return \Monolog\Logger + */ + public static function default_logger() + { + $name = 'chamilo'; + $result = new Logger($name); + $handler = new Monolog\Handler\StreamHandler('php://stderr'); + $handler->setFormatter(new Monolog\Formatter\LineFormatter('[%datetime%] [%level_name%] [%channel%] %message%' . PHP_EOL, 'Y-m-d H:i:s')); //%context% %extra% + $result->pushHandler($handler); + return $result; + } + + private static $logger = null; + /** * * @return \Monolog\Logger */ public static function logger() { - static $result = null; - if (empty($result)) { - self::register_autoload(); - $name = 'chamilo'; - $result = new Logger($name); - $handler = new Monolog\Handler\StreamHandler('php://stderr'); - $handler->setFormatter(new Monolog\Formatter\LineFormatter('[%datetime%] [%level_name%] [%channel%]: %message%' . PHP_EOL, 'Y-m-d H:i:s')); //%context% %extra% - $result->pushHandler($handler); - //$result->pushProcessor(new \Monolog\Processor\WebProcessor()); + if (empty(self::$logger)) { + self::$logger = self::default_logger(); } - return $result; + return self::$logger; + } + + public static function set_logger($value) + { + self::$logger = $value; + } + + public static function write($level, $message, $context = array()) + { + /* + * Note that the same could be done with a monolog processor. + */ + + $trace = debug_backtrace(); + array_shift($trace); + $trace = reset($trace); + $file = $trace['file']; + $root = realpath(api_get_path(SYS_PATH)); + $file = str_replace($root, '', $file); + $file = trim($file, DIRECTORY_SEPARATOR); + $line = $trace['line']; + $message = "[$file:$line] " . $message; + + self::logger()->addRecord($level, $message, $context); } /** @@ -59,7 +94,7 @@ class Log */ public static function debug($message, array $context = array()) { - return self::logger()->debug($message, $context); + return self::write(Logger::DEBUG, $message, $context); } /** @@ -73,7 +108,7 @@ class Log */ public static function info($message, array $context = array()) { - return self::logger()->info($message, $context); + return self::write(Logger::INFO, self::message($message), $context); } /** @@ -87,7 +122,7 @@ class Log */ public static function notice($message, array $context = array()) { - return self::logger()->notice($message, $context); + return self::write(Logger::INFO, $message, $context); } /** @@ -101,7 +136,7 @@ class Log */ public static function warning($message, array $context = array()) { - return self::logger()->warn($message, $context); + return self::write(Logger::WARNING, $message, $context); } /** @@ -115,7 +150,7 @@ class Log */ public static function error($message, array $context = array()) { - return self::logger()->err($message, $context); + return self::write(Logger::ERROR, $message, $context); } /** @@ -129,7 +164,7 @@ class Log */ public static function crit($message, array $context = array()) { - return self::logger()->crit($message, $context); + return self::write(Logger::CRITICAL, $message, $context); } /** @@ -143,7 +178,7 @@ class Log */ public static function alert($message, array $context = array()) { - return self::logger()->alert($message, $context); + return self::write(Logger::ALERT, $message, $context); } } \ No newline at end of file diff --git a/main/install/update-db-1.6.x-1.8.0.inc.php b/main/install/update-db-1.6.x-1.8.0.inc.php index cb48ffb95a..2a1dee7fc2 100644 --- a/main/install/update-db-1.6.x-1.8.0.inc.php +++ b/main/install/update-db-1.6.x-1.8.0.inc.php @@ -18,7 +18,8 @@ * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); + // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-db-1.8.0-1.8.2.inc.php b/main/install/update-db-1.8.0-1.8.2.inc.php index 4e24dfcc09..4cd4c7abbd 100644 --- a/main/install/update-db-1.8.0-1.8.2.inc.php +++ b/main/install/update-db-1.8.0-1.8.2.inc.php @@ -17,7 +17,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { @@ -186,7 +186,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.2-1.8.3.inc.php b/main/install/update-db-1.8.2-1.8.3.inc.php index 93aecdee35..4aee70046a 100644 --- a/main/install/update-db-1.8.2-1.8.3.inc.php +++ b/main/install/update-db-1.8.2-1.8.3.inc.php @@ -16,7 +16,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { @@ -184,7 +184,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { //otherwise just use the main one diff --git a/main/install/update-db-1.8.3-1.8.4.inc.php b/main/install/update-db-1.8.3-1.8.4.inc.php index 4206ff3909..7c869d3591 100644 --- a/main/install/update-db-1.8.3-1.8.4.inc.php +++ b/main/install/update-db-1.8.3-1.8.4.inc.php @@ -16,7 +16,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); // Check if we come from index.php or update_courses.php - otherwise display error msg if (defined('SYSTEM_INSTALLATION')) { @@ -184,7 +184,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.4-1.8.5.inc.php b/main/install/update-db-1.8.4-1.8.5.inc.php index cd0d2b3639..95da478044 100644 --- a/main/install/update-db-1.8.4-1.8.5.inc.php +++ b/main/install/update-db-1.8.4-1.8.5.inc.php @@ -16,7 +16,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); $old_file_version = '1.8.4'; $new_file_version = '1.8.5'; @@ -191,7 +191,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.5-1.8.6.inc.php b/main/install/update-db-1.8.5-1.8.6.inc.php index fe6129ea24..f64b1ea8c2 100644 --- a/main/install/update-db-1.8.5-1.8.6.inc.php +++ b/main/install/update-db-1.8.5-1.8.6.inc.php @@ -16,7 +16,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); $old_file_version = '1.8.5'; $new_file_version = '1.8.6'; @@ -1102,7 +1102,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { //otherwise just use the main one diff --git a/main/install/update-db-1.8.6-1.8.6.1.inc.php b/main/install/update-db-1.8.6-1.8.6.1.inc.php index 4290c4fd30..6fea16a70c 100644 --- a/main/install/update-db-1.8.6-1.8.6.1.inc.php +++ b/main/install/update-db-1.8.6-1.8.6.1.inc.php @@ -16,7 +16,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); $old_file_version = '1.8.6'; $new_file_version = '1.8.6.1'; @@ -192,7 +192,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php index 55768dcc10..61f12512aa 100644 --- a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php +++ b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php @@ -16,7 +16,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); $old_file_version = '1.8.6.1'; $new_file_version = '1.8.6.2'; @@ -296,7 +296,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index b47c50e63a..781b339a6e 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -16,7 +16,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); $old_file_version = '1.8.6.2'; $new_file_version = '1.8.7'; @@ -401,7 +401,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.7-1.8.8.inc.php b/main/install/update-db-1.8.7-1.8.8.inc.php index 1dc3ea9ef6..5249487d27 100644 --- a/main/install/update-db-1.8.7-1.8.8.inc.php +++ b/main/install/update-db-1.8.7-1.8.8.inc.php @@ -16,7 +16,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); $old_file_version = '1.8.7'; $new_file_version = '1.8.8'; @@ -229,7 +229,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.8-1.9.0.inc.php b/main/install/update-db-1.8.8-1.9.0.inc.php index 40e355b554..44f82f5153 100755 --- a/main/install/update-db-1.8.8-1.9.0.inc.php +++ b/main/install/update-db-1.8.8-1.9.0.inc.php @@ -16,7 +16,7 @@ * - reorganise code into functions * @todo use database library */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); $old_file_version = '1.8.8'; $new_file_version = '1.9.0'; @@ -264,7 +264,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice(basename(__FILE__) . ' - course ' . $row_course); + Log::notice('Course ' . $row_course); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-scorm-1.6.x-1.8.0.inc.php b/main/install/update-db-scorm-1.6.x-1.8.0.inc.php index e00d6fde5e..094a2d6ee7 100644 --- a/main/install/update-db-scorm-1.6.x-1.8.0.inc.php +++ b/main/install/update-db-scorm-1.6.x-1.8.0.inc.php @@ -12,7 +12,7 @@ /** * Include mandatory libraries */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); require_once api_get_path(LIBRARY_PATH).'document.lib.php'; require_once api_get_path(LIBRARY_PATH).'fileManage.lib.php'; //check_name_exists() diff --git a/main/install/update-files-1.6.x-1.8.0.inc.php b/main/install/update-files-1.6.x-1.8.0.inc.php index 09d21a1e97..b9525a7240 100644 --- a/main/install/update-files-1.6.x-1.8.0.inc.php +++ b/main/install/update-files-1.6.x-1.8.0.inc.php @@ -18,7 +18,7 @@ * * @package chamilo.install */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); function insert_db($db_name, $folder_name, $text) { diff --git a/main/install/update-files-1.8.3-1.8.4.inc.php b/main/install/update-files-1.8.3-1.8.4.inc.php index f2e1b7498a..1d08ed24d7 100644 --- a/main/install/update-files-1.8.3-1.8.4.inc.php +++ b/main/install/update-files-1.8.3-1.8.4.inc.php @@ -17,7 +17,7 @@ * @package chamilo.install */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-files-1.8.4-1.8.5.inc.php b/main/install/update-files-1.8.4-1.8.5.inc.php index 2ff9b8a7be..21e5a4792d 100644 --- a/main/install/update-files-1.8.4-1.8.5.inc.php +++ b/main/install/update-files-1.8.4-1.8.5.inc.php @@ -17,7 +17,7 @@ * @package chamilo.install */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-files-1.8.5-1.8.6.inc.php b/main/install/update-files-1.8.5-1.8.6.inc.php index 1f29ac5701..8426e79423 100644 --- a/main/install/update-files-1.8.5-1.8.6.inc.php +++ b/main/install/update-files-1.8.5-1.8.6.inc.php @@ -18,7 +18,7 @@ * @package chamilo.install */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-files-1.8.6-1.8.6.1.inc.php b/main/install/update-files-1.8.6-1.8.6.1.inc.php index a2455fbb63..f3fdfd08b9 100644 --- a/main/install/update-files-1.8.6-1.8.6.1.inc.php +++ b/main/install/update-files-1.8.6-1.8.6.1.inc.php @@ -17,7 +17,7 @@ * @package chamilo.install */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-files-1.8.6.1-1.8.6.2.inc.php b/main/install/update-files-1.8.6.1-1.8.6.2.inc.php index 818dd37f8a..fbeadb5870 100644 --- a/main/install/update-files-1.8.6.1-1.8.6.2.inc.php +++ b/main/install/update-files-1.8.6.1-1.8.6.2.inc.php @@ -12,7 +12,7 @@ * @package chamilo.install */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-files-1.8.6.2-1.8.7.inc.php b/main/install/update-files-1.8.6.2-1.8.7.inc.php index c109b844a8..bf1c00373f 100644 --- a/main/install/update-files-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-files-1.8.6.2-1.8.7.inc.php @@ -11,8 +11,7 @@ * @package chamilo.install */ - -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-files-1.8.7-1.8.8.inc.php b/main/install/update-files-1.8.7-1.8.8.inc.php index 2e5157c7ba..500974ad35 100644 --- a/main/install/update-files-1.8.7-1.8.8.inc.php +++ b/main/install/update-files-1.8.7-1.8.8.inc.php @@ -11,7 +11,7 @@ * @package chamilo.install */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); if (defined('SYSTEM_INSTALLATION')) { diff --git a/main/install/update-files-1.8.8-1.9.0.inc.php b/main/install/update-files-1.8.8-1.9.0.inc.php index 1da3eb1629..dfece002e4 100644 --- a/main/install/update-files-1.8.8-1.9.0.inc.php +++ b/main/install/update-files-1.8.8-1.9.0.inc.php @@ -11,7 +11,7 @@ * @package chamilo.install */ -Log::notice("Starting " . basename(__FILE__)); +Log::notice('Entering file'); if (defined('SYSTEM_INSTALLATION')) { From 536f68ef78a7946546359db060f33e8e55d96133 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 15:52:01 +0200 Subject: [PATCH 066/128] #4694 add feedback during installation --- main/install/update-db-1.8.0-1.8.2.inc.php | 2 +- main/install/update-db-1.8.2-1.8.3.inc.php | 2 +- main/install/update-db-1.8.3-1.8.4.inc.php | 2 +- main/install/update-db-1.8.4-1.8.5.inc.php | 2 +- main/install/update-db-1.8.5-1.8.6.inc.php | 2 +- main/install/update-db-1.8.6-1.8.6.1.inc.php | 2 +- main/install/update-db-1.8.6.1-1.8.6.2.inc.php | 2 +- main/install/update-db-1.8.6.2-1.8.7.inc.php | 2 +- main/install/update-db-1.8.7-1.8.8.inc.php | 2 +- main/install/update-db-1.8.8-1.9.0.inc.php | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/main/install/update-db-1.8.0-1.8.2.inc.php b/main/install/update-db-1.8.0-1.8.2.inc.php index 4cd4c7abbd..ec2d7f4646 100644 --- a/main/install/update-db-1.8.0-1.8.2.inc.php +++ b/main/install/update-db-1.8.0-1.8.2.inc.php @@ -186,7 +186,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.2-1.8.3.inc.php b/main/install/update-db-1.8.2-1.8.3.inc.php index 4aee70046a..c087d5b3fd 100644 --- a/main/install/update-db-1.8.2-1.8.3.inc.php +++ b/main/install/update-db-1.8.2-1.8.3.inc.php @@ -184,7 +184,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { //otherwise just use the main one diff --git a/main/install/update-db-1.8.3-1.8.4.inc.php b/main/install/update-db-1.8.3-1.8.4.inc.php index 7c869d3591..1d10486c87 100644 --- a/main/install/update-db-1.8.3-1.8.4.inc.php +++ b/main/install/update-db-1.8.3-1.8.4.inc.php @@ -184,7 +184,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.4-1.8.5.inc.php b/main/install/update-db-1.8.4-1.8.5.inc.php index 95da478044..94fcab57ac 100644 --- a/main/install/update-db-1.8.4-1.8.5.inc.php +++ b/main/install/update-db-1.8.4-1.8.5.inc.php @@ -191,7 +191,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.5-1.8.6.inc.php b/main/install/update-db-1.8.5-1.8.6.inc.php index f64b1ea8c2..e5602714bb 100644 --- a/main/install/update-db-1.8.5-1.8.6.inc.php +++ b/main/install/update-db-1.8.5-1.8.6.inc.php @@ -1102,7 +1102,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { //otherwise just use the main one diff --git a/main/install/update-db-1.8.6-1.8.6.1.inc.php b/main/install/update-db-1.8.6-1.8.6.1.inc.php index 6fea16a70c..8f8b859d67 100644 --- a/main/install/update-db-1.8.6-1.8.6.1.inc.php +++ b/main/install/update-db-1.8.6-1.8.6.1.inc.php @@ -192,7 +192,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php index 61f12512aa..64d0d958df 100644 --- a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php +++ b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php @@ -296,7 +296,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { //otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index 781b339a6e..d82f800b46 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -401,7 +401,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.7-1.8.8.inc.php b/main/install/update-db-1.8.7-1.8.8.inc.php index 5249487d27..b02accea3b 100644 --- a/main/install/update-db-1.8.7-1.8.8.inc.php +++ b/main/install/update-db-1.8.7-1.8.8.inc.php @@ -229,7 +229,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.8-1.9.0.inc.php b/main/install/update-db-1.8.8-1.9.0.inc.php index 44f82f5153..f2e20f59f7 100755 --- a/main/install/update-db-1.8.8-1.9.0.inc.php +++ b/main/install/update-db-1.8.8-1.9.0.inc.php @@ -264,7 +264,7 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one Database::select_db($row_course['db_name']); } - Log::notice('Course ' . $row_course); + Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { From aa3dafc3af3c0ac563419633b042d4a0fcc540c5 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 15:59:45 +0200 Subject: [PATCH 067/128] #4694 add feedback during installation --- main/install/update-db-1.8.6.2-1.8.7.inc.php | 361 +++++++++---------- 1 file changed, 178 insertions(+), 183 deletions(-) diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index d82f800b46..07503c7ca3 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -1,4 +1,5 @@ '.get_lang('Error').' ! Chamilo '.implode('|', $updateFromVersion).' '.get_lang('HasNotBeenFound').'.

- '.get_lang('PleasGoBackToStep1').'. -

+ echo '' . get_lang('Error') . ' ! Chamilo ' . implode('|', $updateFromVersion) . ' ' . get_lang('HasNotBeenFound') . '.

+ ' . get_lang('PleasGoBackToStep1') . '. +

'; - exit (); + exit(); } $_configuration['db_glue'] = get_config_param('dbGlu'); @@ -41,14 +42,14 @@ if (defined('SYSTEM_INSTALLATION')) { $_configuration['db_prefix'] = get_config_param('dbNamePrefix'); } - $dbScormForm = preg_replace('/[^a-zA-Z0-9_\-]/', '', $dbScormForm); + $dbScormForm = preg_replace('/[^a-zA-Z0-9_\-]/', '', $dbScormForm); - if (!empty($dbPrefixForm) && strpos($dbScormForm, $dbPrefixForm) !== 0) { - $dbScormForm = $dbPrefixForm.$dbScormForm; + if (!empty($dbPrefixForm) && strpos($dbScormForm, $dbPrefixForm) !== 0) { + $dbScormForm = $dbPrefixForm . $dbScormForm; } if (empty($dbScormForm) || $dbScormForm == 'mysql' || $dbScormForm == $dbPrefixForm) { - $dbScormForm = $dbPrefixForm.'scorm'; + $dbScormForm = $dbPrefixForm . 'scorm'; } /* Normal upgrade procedure: start by updating main, statistic, user databases */ @@ -71,11 +72,11 @@ if (defined('SYSTEM_INSTALLATION')) { if ($languageForm != 'english') { // languageForm has been escaped in index.php - include '../lang/'.$languageForm.'/create_course.inc.php'; + include '../lang/' . $languageForm . '/create_course.inc.php'; } // Get the main queries list (m_q_list) - $m_q_list = get_sql_file_contents('migrate-db-'.$old_file_version.'-'.$new_file_version.'-pre.sql', 'main'); + $m_q_list = get_sql_file_contents('migrate-db-' . $old_file_version . '-' . $new_file_version . '-pre.sql', 'main'); if (count($m_q_list) > 0) { // Now use the $m_q_list /** @@ -83,36 +84,36 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (strlen($dbNameForm) > 40) { - Log::error('Database name '.$dbNameForm.' is too long, skipping'); + Log::error('Database name ' . $dbNameForm . ' is too long, skipping'); } elseif (!in_array($dbNameForm, $dblist)) { - Log::error('Database '.$dbNameForm.' was not found, skipping'); + Log::error('Database ' . $dbNameForm . ' was not found, skipping'); } else { Database::select_db($dbNameForm); - foreach ($m_q_list as $query){ + foreach ($m_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbNameForm,$query)"); + Log::notice("Database::query($dbNameForm,$query)"); } else { $res = Database::query($query); if ($log) { - Log::notice("In $dbNameForm, executed: $query"); + Log::notice("In $dbNameForm, executed: $query"); } if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } } $tables = Database::get_tables($dbNameForm); foreach ($tables as $table) { - $query = "ALTER TABLE `".$table."` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; + $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; $res = Database::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } - $query = "ALTER DATABASE `".$dbNameForm."` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; + $query = "ALTER DATABASE `" . $dbNameForm . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; $res = Database::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } } @@ -127,29 +128,29 @@ if (defined('SYSTEM_INSTALLATION')) { $timeOffsetSeconds = $dateTimeZoneCurrent->getOffset($dateTimeUTC); $timeOffsetHours = $timeOffsetSeconds / 3600; $timeOffsetString = ""; - - if($timeOffsetHours < 0) { - $timeOffsetString .= "-"; - $timeOffsetHours = abs($timeOffsetHours); + + if ($timeOffsetHours < 0) { + $timeOffsetString .= "-"; + $timeOffsetHours = abs($timeOffsetHours); } else { - $timeOffsetString .= "+"; + $timeOffsetString .= "+"; } - - if($timeOffsetHours < 10) { - $timeOffsetString .= "0"; + + if ($timeOffsetHours < 10) { + $timeOffsetString .= "0"; } - + $timeOffsetString .= "$timeOffsetHours"; $timeOffsetString .= ":00"; - + // Executing the queries to convert everything - $queries[] = "UPDATE gradebook_certificate SET created_at = CONVERT_TZ(created_at, '".$timeOffsetString."', '+00:00');"; - $queries[] = "UPDATE gradebook_evaluation SET created_at = CONVERT_TZ(created_at, '".$timeOffsetString."', '+00:00');"; - $queries[] = "UPDATE gradebook_link SET created_at = CONVERT_TZ(created_at, '".$timeOffsetString."', '+00:00');"; - $queries[] = "UPDATE gradebook_linkeval_log SET created_at = CONVERT_TZ(created_at, '".$timeOffsetString."', '+00:00');"; - $queries[] = "UPDATE gradebook_result SET created_at = CONVERT_TZ(created_at, '".$timeOffsetString."', '+00:00');"; - $queries[] = "UPDATE gradebook_result_log SET created_at = CONVERT_TZ(created_at, '".$timeOffsetString."', '+00:00');"; - + $queries[] = "UPDATE gradebook_certificate SET created_at = CONVERT_TZ(created_at, '" . $timeOffsetString . "', '+00:00');"; + $queries[] = "UPDATE gradebook_evaluation SET created_at = CONVERT_TZ(created_at, '" . $timeOffsetString . "', '+00:00');"; + $queries[] = "UPDATE gradebook_link SET created_at = CONVERT_TZ(created_at, '" . $timeOffsetString . "', '+00:00');"; + $queries[] = "UPDATE gradebook_linkeval_log SET created_at = CONVERT_TZ(created_at, '" . $timeOffsetString . "', '+00:00');"; + $queries[] = "UPDATE gradebook_result SET created_at = CONVERT_TZ(created_at, '" . $timeOffsetString . "', '+00:00');"; + $queries[] = "UPDATE gradebook_result_log SET created_at = CONVERT_TZ(created_at, '" . $timeOffsetString . "', '+00:00');"; + foreach ($queries as $query) { Database::query($query); } @@ -158,16 +159,16 @@ if (defined('SYSTEM_INSTALLATION')) { $query = "SELECT user_id, hr_dept_id FROM $dbNameForm.user"; $result = Database::query($query); if (Database::num_rows($result) > 0) { - require_once api_get_path(LIBRARY_PATH).'usermanager.lib.php'; + require_once api_get_path(LIBRARY_PATH) . 'usermanager.lib.php'; while ($row = Database::fetch_array($result, 'ASSOC')) { $user_id = $row['user_id']; $hr_dept_id = $row['hr_dept_id']; // moving data to user_rel_user table if (!empty($hr_dept_id)) { - $sql = " SELECT id FROM $dbNameForm.user_rel_user WHERE user_id = $user_id AND friend_user_id = $hr_dept_id AND relation_type = ".USER_RELATION_TYPE_RRHH." "; - $rs = Database::query($sql); + $sql = " SELECT id FROM $dbNameForm.user_rel_user WHERE user_id = $user_id AND friend_user_id = $hr_dept_id AND relation_type = " . USER_RELATION_TYPE_RRHH . " "; + $rs = Database::query($sql); if (Database::num_rows($rs) == 0) { - $ins = "INSERT INTO $dbNameForm.user_rel_user SET user_id = $user_id, friend_user_id = $hr_dept_id, relation_type = ".USER_RELATION_TYPE_RRHH." "; + $ins = "INSERT INTO $dbNameForm.user_rel_user SET user_id = $user_id, friend_user_id = $hr_dept_id, relation_type = " . USER_RELATION_TYPE_RRHH . " "; Database::query($ins); } } @@ -178,7 +179,6 @@ if (defined('SYSTEM_INSTALLATION')) { } // Updating score display for each gradebook category - // first we check if there already is migrated data to categoy_id field $query = "SELECT id FROM $dbNameForm.gradebook_score_display WHERE category_id = 0"; $rs_check = Database::query($query); @@ -189,7 +189,7 @@ if (defined('SYSTEM_INSTALLATION')) { $query = "SELECT id FROM $dbNameForm.gradebook_category"; $rs_gradebook = Database::query($query); if (Database::num_rows($rs_gradebook) > 0) { - while($row_gradebook = Database::fetch_row($rs_gradebook)) { + while ($row_gradebook = Database::fetch_row($rs_gradebook)) { $a_categories[] = $row_gradebook[0]; } } @@ -214,7 +214,7 @@ if (defined('SYSTEM_INSTALLATION')) { } // Now clean the deprecated id_coach field from the session_rel_course table - $m_q_list = get_sql_file_contents('migrate-db-'.$old_file_version.'-'.$new_file_version.'-post.sql', 'main'); + $m_q_list = get_sql_file_contents('migrate-db-' . $old_file_version . '-' . $new_file_version . '-post.sql', 'main'); if (count($m_q_list) > 0) { // Now use the $m_q_list /** @@ -222,18 +222,18 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (strlen($dbNameForm) > 40) { - Log::error('Database name '.$dbNameForm.' is too long, skipping'); - } elseif (!in_array($dbNameForm,$dblist)) { - Log::error('Database '.$dbNameForm.' was not found, skipping'); + Log::error('Database name ' . $dbNameForm . ' is too long, skipping'); + } elseif (!in_array($dbNameForm, $dblist)) { + Log::error('Database ' . $dbNameForm . ' was not found, skipping'); } else { Database::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbNameForm,$query)"); + Log::notice("Database::query($dbNameForm,$query)"); } else { $res = Database::query($query); if ($log) { - Log::notice("In $dbNameForm, executed: $query"); + Log::notice("In $dbNameForm, executed: $query"); } } } @@ -241,7 +241,7 @@ if (defined('SYSTEM_INSTALLATION')) { } // Get the stats queries list (s_q_list) - $s_q_list = get_sql_file_contents('migrate-db-'.$old_file_version.'-'.$new_file_version.'-pre.sql', 'stats'); + $s_q_list = get_sql_file_contents('migrate-db-' . $old_file_version . '-' . $new_file_version . '-pre.sql', 'stats'); if (count($s_q_list) > 0) { // Now use the $s_q_list /** @@ -249,82 +249,81 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (strlen($dbStatsForm) > 40) { - Log::error('Database name '.$dbStatsForm.' is too long, skipping'); - } elseif (!in_array($dbStatsForm, $dblist)){ - Log::error('Database '.$dbStatsForm.' was not found, skipping'); + Log::error('Database name ' . $dbStatsForm . ' is too long, skipping'); + } elseif (!in_array($dbStatsForm, $dblist)) { + Log::error('Database ' . $dbStatsForm . ' was not found, skipping'); } else { Database::select_db($dbStatsForm); + Log::notice('Database: statistics'); foreach ($s_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbStatsForm,$query)"); + Log::notice("Database::query($dbStatsForm,$query)"); } else { $res = Database::query($query); if ($log) { - Log::notice("In $dbStatsForm, executed: $query"); + Log::notice("In $dbStatsForm, executed: $query"); } if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } } $tables = Database::get_tables($dbStatsForm); foreach ($tables as $table) { - $query = "ALTER TABLE `".$table."` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; + $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; $res = Database::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } - $query = "ALTER DATABASE `".$dbStatsForm."` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; + $query = "ALTER DATABASE `" . $dbStatsForm . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; $res = Database::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } // chamilo_stat.track_e_attempt table update changing id by id_auto - $sql = "SELECT exe_id, question_id, course_code, answer FROM $dbStatsForm.track_e_attempt"; + $sql = "SELECT exe_id, question_id, course_code, answer FROM $dbStatsForm.track_e_attempt"; $result = Database::query($sql); if (Database::num_rows($result) > 0) { - while ($row = Database::fetch_array($result)) { - $course_code = $row['course_code']; - $course_info = api_get_course_info($course_code); - $my_course_db = $course_info['dbName']; - $question_id = $row['question_id']; - $answer = $row['answer']; - $exe_id = $row['exe_id']; - - //getting the type question id - $sql_question = "SELECT type FROM $my_course_db.quiz_question where id = $question_id"; - $res_question = Database::query($sql_question); - $row = Database::fetch_array($res_question); - $type = $row['type']; - - require_once api_get_path(SYS_CODE_PATH).'exercice/question.class.php'; - //this type of questions produce problems in the track_e_attempt table - if (in_array($type, array(UNIQUE_ANSWER, MULTIPLE_ANSWER, MATCHING, MULTIPLE_ANSWER_COMBINATION))) { - $sql_question = "SELECT id_auto FROM $my_course_db.quiz_answer where question_id = $question_id and id = $answer"; - $res_question = Database::query($sql_question); - $row = Database::fetch_array($res_question); - $id_auto = $row['id_auto']; - if (!empty($id_auto)) { - $sql = "UPDATE $dbStatsForm.track_e_attempt SET answer = '$id_auto' WHERE exe_id = $exe_id AND question_id = $question_id AND course_code = '$course_code' and answer = $answer "; - Database::query($sql); - } - } - } + while ($row = Database::fetch_array($result)) { + $course_code = $row['course_code']; + $course_info = api_get_course_info($course_code); + $my_course_db = $course_info['dbName']; + $question_id = $row['question_id']; + $answer = $row['answer']; + $exe_id = $row['exe_id']; + + //getting the type question id + $sql_question = "SELECT type FROM $my_course_db.quiz_question where id = $question_id"; + $res_question = Database::query($sql_question); + $row = Database::fetch_array($res_question); + $type = $row['type']; + + require_once api_get_path(SYS_CODE_PATH) . 'exercice/question.class.php'; + //this type of questions produce problems in the track_e_attempt table + if (in_array($type, array(UNIQUE_ANSWER, MULTIPLE_ANSWER, MATCHING, MULTIPLE_ANSWER_COMBINATION))) { + $sql_question = "SELECT id_auto FROM $my_course_db.quiz_answer where question_id = $question_id and id = $answer"; + $res_question = Database::query($sql_question); + $row = Database::fetch_array($res_question); + $id_auto = $row['id_auto']; + if (!empty($id_auto)) { + $sql = "UPDATE $dbStatsForm.track_e_attempt SET answer = '$id_auto' WHERE exe_id = $exe_id AND question_id = $question_id AND course_code = '$course_code' and answer = $answer "; + Database::query($sql); + } + } + } } - - } } // Get the user queries list (u_q_list) - $u_q_list = get_sql_file_contents('migrate-db-'.$old_file_version.'-'.$new_file_version.'-pre.sql', 'user'); + $u_q_list = get_sql_file_contents('migrate-db-' . $old_file_version . '-' . $new_file_version . '-pre.sql', 'user'); if (count($u_q_list) > 0) { // Now use the $u_q_list /** @@ -332,34 +331,35 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (strlen($dbUserForm) > 40) { - Log::error('Database name '.$dbUserForm.' is too long, skipping'); - } elseif (!in_array($dbUserForm,$dblist)) { - Log::error('Database '.$dbUserForm.' was not found, skipping'); + Log::error('Database name ' . $dbUserForm . ' is too long, skipping'); + } elseif (!in_array($dbUserForm, $dblist)) { + Log::error('Database ' . $dbUserForm . ' was not found, skipping'); } else { Database::select_db($dbUserForm); + Log::notice('Database: user'); foreach ($u_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbUserForm,$query)"); - Log::notice("In $dbUserForm, executed: $query"); + Log::notice("Database::query($dbUserForm,$query)"); + Log::notice("In $dbUserForm, executed: $query"); } else { $res = Database::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } } $tables = Database::get_tables($dbUserForm); foreach ($tables as $table) { - $query = "ALTER TABLE `".$table."` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; + $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; $res = Database::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } - $query = "ALTER DATABASE `".$dbUserForm."` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; + $query = "ALTER DATABASE `" . $dbUserForm . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; $res = Database::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } } @@ -368,22 +368,24 @@ if (defined('SYSTEM_INSTALLATION')) { $prefix = ''; if ($singleDbForm) { - $prefix = get_config_param ('table_prefix'); + $prefix = get_config_param('table_prefix'); } // Get the courses databases queries list (c_q_list) - $c_q_list = get_sql_file_contents('migrate-db-'.$old_file_version.'-'.$new_file_version.'-pre.sql', 'course'); + $c_q_list = get_sql_file_contents('migrate-db-' . $old_file_version . '-' . $new_file_version . '-pre.sql', 'course'); if (count($c_q_list) > 0) { // Get the courses list if (strlen($dbNameForm) > 40) { - Log::error('Database name '.$dbNameForm.' is too long, skipping'); - } elseif(!in_array($dbNameForm, $dblist)) { - Log::error('Database '.$dbNameForm.' was not found, skipping'); + Log::error('Database name ' . $dbNameForm . ' is too long, skipping'); + } elseif (!in_array($dbNameForm, $dblist)) { + Log::error('Database ' . $dbNameForm . ' was not found, skipping'); } else { Database::select_db($dbNameForm); $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); - if ($res === false) { die('Error while querying the courses list in update_db-1.8.6.2-1.8.7.inc.php'); } + if ($res === false) { + die('Error while querying the courses list in update_db-1.8.6.2-1.8.7.inc.php'); + } if (Database::num_rows($res) > 0) { $i = 0; @@ -409,14 +411,14 @@ if (defined('SYSTEM_INSTALLATION')) { } if ($only_test) { - Log::notice("Database::query(".$row_course['db_name'].",$query)"); + Log::notice("Database::query(" . $row_course['db_name'] . ",$query)"); } else { $res = Database::query($query); if ($log) { - Log::notice("In ".$row_course['db_name'].", executed: $query"); + Log::notice("In " . $row_course['db_name'] . ", executed: $query"); } if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } } @@ -424,20 +426,20 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { $tables = Database::get_tables($row_course['db_name']); foreach ($tables as $table) { - $query = "ALTER TABLE `".$table."` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; + $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; $res = Database::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } - $query = "ALTER DATABASE `".$row_course['db_name']."` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; - $res = Database::query($query); + $query = "ALTER DATABASE `" . $row_course['db_name'] . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; + $res = Database::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in ' . $query . ': ' . Database::error()); } } - $t_student_publication = $row_course['db_name'].".student_publication"; - $t_item_property = $row_course['db_name'].".item_property"; + $t_student_publication = $row_course['db_name'] . ".student_publication"; + $t_item_property = $row_course['db_name'] . ".item_property"; if ($singleDbForm) { $t_student_publication = "$prefix{$row_course['db_name']}_student_publication"; @@ -449,79 +451,75 @@ if (defined('SYSTEM_INSTALLATION')) { $rs_insert_user = Database::query($sql_insert_user); if ($rs_insert_user === false) { - Log::error('Could not query insert_user_id table: '.Database::error()); - } else { - if (Database::num_rows($rs_insert_user) > 0) { - while ($row_ids = Database::fetch_array($rs_insert_user)) { - $user_id = $row_ids['insert_user_id']; - $ref = $row_ids['ref']; - $sql_upd = "UPDATE $t_student_publication SET user_id='$user_id' WHERE id='$ref'"; - Database::query($sql_upd); - } - } - } - - //updating parent_id of the student_publication table - $sql = 'SELECT id, url, parent_id FROM '.$t_student_publication; - $result = Database::query($sql); - if (Database::num_rows($result) > 0) { - $items = Database::store_result($result); - $directory_list = $file_list=array(); - - foreach($items as $item) { - $student_slash = substr($item['url'], 0, 1); - //means this is a directory - if ($student_slash == '/') { - $directory_list[$item['id']]= $item['url']; - } else { - // this is a file with no parents - if ($item['parent_id'] == 0) - $file_list []= $item; - } - } - - if (is_array($file_list) && count($file_list) > 0) { - foreach ($file_list as $file) { - $parent_id = 0; - if (is_array($directory_list) && count($directory_list) > 0) { - foreach($directory_list as $id => $dir) { - $pos = strpos($file['url'], $dir.'/'); - if ($pos !== false) { - $parent_id = $id; - break; - } - } - } - - if ($parent_id != 0 ) { - $sql = 'UPDATE '.$t_student_publication.' SET parent_id = '.$parent_id.' WHERE id = '.$file['id'].''; - Database::query($sql); - } - } - } - } - - - - + Log::error('Could not query insert_user_id table: ' . Database::error()); + } else { + if (Database::num_rows($rs_insert_user) > 0) { + while ($row_ids = Database::fetch_array($rs_insert_user)) { + $user_id = $row_ids['insert_user_id']; + $ref = $row_ids['ref']; + $sql_upd = "UPDATE $t_student_publication SET user_id='$user_id' WHERE id='$ref'"; + Database::query($sql_upd); + } + } + } + //updating parent_id of the student_publication table + $sql = 'SELECT id, url, parent_id FROM ' . $t_student_publication; + $result = Database::query($sql); + if (Database::num_rows($result) > 0) { + $items = Database::store_result($result); + $directory_list = $file_list = array(); + + foreach ($items as $item) { + $student_slash = substr($item['url'], 0, 1); + //means this is a directory + if ($student_slash == '/') { + $directory_list[$item['id']] = $item['url']; + } else { + // this is a file with no parents + if ($item['parent_id'] == 0) + $file_list [] = $item; + } + } + if (is_array($file_list) && count($file_list) > 0) { + foreach ($file_list as $file) { + $parent_id = 0; + if (is_array($directory_list) && count($directory_list) > 0) { + foreach ($directory_list as $id => $dir) { + $pos = strpos($file['url'], $dir . '/'); + if ($pos !== false) { + $parent_id = $id; + break; + } + } + } + + if ($parent_id != 0) { + $sql = 'UPDATE ' . $t_student_publication . ' SET parent_id = ' . $parent_id . ' WHERE id = ' . $file['id'] . ''; + Database::query($sql); + } + } + } + } } } } } // Get the courses databases queries list (c_q_list) - $c_q_list = get_sql_file_contents('migrate-db-'.$old_file_version.'-'.$new_file_version.'-post.sql', 'course'); + $c_q_list = get_sql_file_contents('migrate-db-' . $old_file_version . '-' . $new_file_version . '-post.sql', 'course'); if (count($c_q_list) > 0) { // Get the courses list if (strlen($dbNameForm) > 40) { - Log::error('Database name '.$dbNameForm.' is too long, skipping'); + Log::error('Database name ' . $dbNameForm . ' is too long, skipping'); } elseif (!in_array($dbNameForm, $dblist)) { - Log::error('Database '.$dbNameForm.' was not found, skipping'); + Log::error('Database ' . $dbNameForm . ' was not found, skipping'); } else { Database::select_db($dbNameForm); $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); - if ($res === false) { die('Error while querying the courses list in update_db-1.8.6.2-1.8.7.inc.php'); } + if ($res === false) { + die('Error while querying the courses list in update_db-1.8.6.2-1.8.7.inc.php'); + } if (Database::num_rows($res) > 0) { $i = 0; while ($row = Database::fetch_array($res)) { @@ -536,21 +534,21 @@ if (defined('SYSTEM_INSTALLATION')) { */ $prefix_course = $prefix; if ($singleDbForm) { - $prefix_course = $prefix.$row['db_name']."_"; + $prefix_course = $prefix . $row['db_name'] . "_"; } else { Database::select_db($row['db_name']); } - foreach($c_q_list as $query) { + foreach ($c_q_list as $query) { if ($singleDbForm) { //otherwise just use the main one $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix$2$3", $query); } if ($only_test) { - Log::notice("Database::query(".$row['db_name'].",$query)"); + Log::notice("Database::query(" . $row['db_name'] . ",$query)"); } else { $res = Database::query($query); if ($log) { - Log::notice("In ".$row['db_name'].", executed: $query"); + Log::notice("In " . $row['db_name'] . ", executed: $query"); } } } @@ -558,10 +556,7 @@ if (defined('SYSTEM_INSTALLATION')) { } } } - - } else { echo 'You are not allowed here !'; - } From e48b177242abe77dcebbdd171b8e496210db0abe Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 16:30:04 +0200 Subject: [PATCH 068/128] #4694 add feedback during installation --- main/install/update-db-1.8.6.2-1.8.7.inc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index 07503c7ca3..57f888e701 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -272,6 +272,7 @@ if (defined('SYSTEM_INSTALLATION')) { $tables = Database::get_tables($dbStatsForm); foreach ($tables as $table) { $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; + Log::notice('Database: statistics, Table: '. $table); $res = Database::query($query); if ($res === false) { Log::error('Error in ' . $query . ': ' . Database::error()); @@ -299,6 +300,7 @@ if (defined('SYSTEM_INSTALLATION')) { //getting the type question id $sql_question = "SELECT type FROM $my_course_db.quiz_question where id = $question_id"; + Log::notice('Database: '. $my_course_db); $res_question = Database::query($sql_question); $row = Database::fetch_array($res_question); $type = $row['type']; From 4af782cb773ca7fef56f638beda597ef33f856e6 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 16:44:08 +0200 Subject: [PATCH 069/128] #4694 add feedback during installation --- main/install/update-db-1.8.6.2-1.8.7.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index 57f888e701..e632bd2eb3 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -279,6 +279,7 @@ if (defined('SYSTEM_INSTALLATION')) { } } $query = "ALTER DATABASE `" . $dbStatsForm . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; + Log::notice('Database: statistics - change default char set'); $res = Database::query($query); if ($res === false) { Log::error('Error in ' . $query . ': ' . Database::error()); From 9e3061fbd62dbbcf9f135a8f2d13d7998d16a022 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Tue, 8 May 2012 16:56:44 +0200 Subject: [PATCH 070/128] Updating icons see #4689 --- main/img/icons/22/zoom_in.png | Bin 1971 -> 1501 bytes main/img/icons/22/zoom_out.png | Bin 1951 -> 1470 bytes main/img/icons/32/zoom_in.png | Bin 1971 -> 2391 bytes main/img/icons/32/zoom_out.png | Bin 1951 -> 2343 bytes main/img/icons/64/zoom_in.png | Bin 0 -> 6276 bytes main/img/icons/64/zoom_out.png | Bin 0 -> 6157 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 main/img/icons/64/zoom_in.png create mode 100644 main/img/icons/64/zoom_out.png diff --git a/main/img/icons/22/zoom_in.png b/main/img/icons/22/zoom_in.png index 18e4383b3f05da224689b17829d1b579d32f8c23..f7b05bc74692c6109b24135860d0504747e35910 100644 GIT binary patch literal 1501 zcmV<31tR*1P)5i1Jm7Hyk0X-rLPVoaA0 zn)I`2V{J^W*0iRm2rhu22xx0!ts;U*by#Gv>@&l>Vb-_YewkV;H0g)_lat(gZtgE9 z_x$gn;2GU_bV5!>9smHG_~{rMB^jeBiedqXs%qM7d0FKw06@#t%TThq6#h;0)0^g& zi;$C%2j3j|+ORk!_4AaJ)KXCp;}FJzrfK0|AmD7ddbxdidisl!)unwG8qUF{jhp8M zQ_m(^uU;-Pn`2tz7Q{zA8X8mwhK6;&FF-hs1*)p=Y$w1Vk&cymOU{qaGD5QA!Sk7x% zp2lQlElHz$dmTqMt}lCkzKU^8eGQbCmBYoR3)akx%;tx^4s`L3znzlOrbL602rR}N zOVJEXVT1+MPfXt4DRxLyA6ttG@>jgDYUSjqlhwDYs=kMsn)6S~u^{@|Fy@Nkp7v;OHm=PcO8H+}eT!E+Z+L7ex*m3@jFT z7Exk???#WiPvE&Ew?9VA#BUjXjP6LeZFl zu%f}*6{+MUg`}}8hT}~=;d|r3YaI@!Z&RMxFG1Xyfj1u@CRn$+}XO^>({Q| zn-7d5{>D!=7e#X1Q)esy@QEq5RU6j7a)8E&DJm)?Uawc~xZ9bJ|HJU7A|MI?bO2BR zKmh;^04T3#W@KX0*_xD`R5>y{Oxe@z{MhK|$@#z}0w9sgS_Bl1L@*NmNQAr|&!ore z>&jW0m3Qm*ow_rpYfr%cAOrvm00?GFToM3C06_lRUx6k5PybOkT zA8Z^qM3^|(IP!u?)P_);C`;QYO%N(-kQ!B0XecehK`DqECIDZaHWvcV<6x%<6$<>%$w!C*K?o8mO+3g3Q?bQXL)naxxe$>bI*Ch8HR!X z=f&OWx2-+fT4crY3ddm;fm)4OMjXc_>9s!|k8RqyW4n)T8Fvlfg|+M4b&Kkcx?GOM z?QLzS_12)k;kaSWWGsfyMtwLsJd8*rcK*`~pS17W`)2sd0&rWl_NH=!swK+_67jh#7##R)4dkqjN>z`|H=C zu&@Zx$s}Ida~PMR8VXCw;B=KhlsE_iM<6`nkqKNIzl;So4!>Q$63zlELZR#U{hl{5 zH28N}zbznQrJ1g65X&pqGZ^?F}@`l%`7?{3+Rm$vVP z&I?e6i1fQ#csF5Vz)vQ1!O3CL*yYV0%VCtwYLHTBNVWf1@pyxGT-?CD3sNfd8MTU zuVKWm!eX_fhW30iYf!Wlgd{;1B}j@w5i8IYiCoKYIuuwH5t1yRbbb-pCdo$@rZ4iz zeCLydyrJvR$dF#3C>Ar*V@!5^N_G}GTU@b_Pf^6KH{ORv>{*?|hVQKeuV#?Ras+3A zMq9ujn9p2*bDsj%4|HZg#*!qHd<2lvkuX^B3V2dLAO+asydcveoax)399AfLP19j; zI?a_#6?OWYZ;zQt5@w*0u|QE!ohJYdae~^u=>>Done4k>r^xBIO|PtCtV}Q@DSDA| zfvv}z3h2NWXmF-PG(C0o>Npu2XqaaOD|o(8n$CNc5;28fTtz66qQ!YrdbYTcvleJF zPl|;jDSWNeYWiTln9qCx^u*-kuv05CrMT=H_PHW65A7LRF7yScb_- z(XpK1c@C{DwP&19+jX&Cos5u~cW zwmw7ic^o@_f^tI8N6vqIf%(oy0aKC!}vrHfBs7^y1UnK_bqPx(T4~7x08i77XZ7oL_D6c z+w9|kK=A9{g$v;(h^3Aw9Ml05x()u66N$7Hv7`l|xQs$0i)LpO-`i7 zD5bqVtHpDad^|NHk;<`xQ>XulBS!{t@4fX@#vQaxNz~TW!-G?3|8;BXp^e9t+vNgx z(`P%4`9(#=wcmO6xi^Z7i>e=NYC?HM89W}(OmSg#A`l4R^UGIo`t)h2skB~RQO>i6 z7>Oz=FWT^E=MuQ(&w)=iWB4f0{_>GqLU6bE&T4oujRlJq)z`PRcfROwIF_-xJ{y3p zR4f)db>#4&-9F#w^`C6s(qCCq15t6|e&rlm<+p&&cR<~WAYLX2{gx27dn%T4YOv?B zA{vg|c1_P`B-A_*qY=vG(mg-kyltqhGKg+lFF0ywpbCl3eFP!h7J{4OaZSuAqTHgf zu%t-kjvAXgk4DXVuRStU@4SL4w@zJEobu4QHwUrNgovryLy!Gz@B|CwPTk7LB`1rL zJ>U6n8WXwSGP#J@J>TO!hdRzhYvGToNG7!@od(y^4EoTp3vDYD6g%Z()2*7v-MeNW zzSVP}<3zX-foSqZhz!Luh|lZ4;g`MS>BM|z+nOQPHK}~DW{ziG?O#s!S+59v zl>oCL%4if!|E;8PC8tvQs|J{cu;*&ablHzj*Mk2EFaW%tGd~88zJLG#002ovPDHLk FV1hoG#FGF3 diff --git a/main/img/icons/22/zoom_out.png b/main/img/icons/22/zoom_out.png index 2bdc37ab3d75591e2cd3bf1940cfc2c8ca59002c..f3c91a9c8cc4dcdd699f81a14935a9d53e962640 100644 GIT binary patch literal 1470 zcmV;v1ws0WP)W8eWvY9J2RcR_Z}Y@4a=DL;6M2u&N(^1 z|Ce*V{0Z)<%k39YkXr-*_~FNIgwy3tA%qA(nx?@0KoB+$58fUIsUEqor}if zhf$DQgst1Zbj;1l{wOOeyWG%?49b{pSyn6>iTID7Jk~NYGV)2;ljYa;AKHr-o_{eZ znB2Q@;^eW?)YNGwGN#XPUhlqPc6ImI;mL?pRe{XRnKaioR|$oJ=pX2N*FQM2<<-~T zkoEg&@KVLf`@wZ}b*QYY#F55>ug{-1e`nW?8#vwO?-+_WhioNn(t={zR-DlIxR$1d z(ii6_`T6s5ct=P3_UD&ZtV!mW)gG)xRYesJH|)>M%gt-N+R;uAp9{ATSI)5Ea7#nw zOcjI)g)%}lGb}x!j$zSlm^U*^ONt+TV##AeKkcqLyKC3CsIA@i513{Qb^!o%!`MAK z=GRVKinh9Dvu!ar5 zakt}d_c!93@3s{eG4&bsyN{au-IUQ!*~al&*4$Xe{;hWxfmoNfNn{QbI}_ zQV52f4Oe292BN3VxBDkwC`t{xT&~BH=2%Jy+qPv~QtLp=Xsa10m$2U z+lGwAr8O`biyk-^9&~Z264bJ7X(R;)0)gwADrnzmG~Des!ebNW%?;mohAE=}B}Ce= zO-stSW!sPv1OAwm>UMBxQkm}2T)my+SCWEB(umF(I_*n1YkpIN&IkT&KdwPiPA)nUY*S9+v zSSA26aoI|MVhKeP3MVub8Xq4T4^6ffEXXf9bN1YUpZC=Lfd8Q=00n@anw~KmfC~Ws Y3&G<=!^U9ECjbBd07*qoM6N<$g51=?#sB~S literal 1951 zcmV;Q2VnS#P)mRMODTR^I z1(7BM2oG&QVOnSx2PmY(aU4IceQn>z&Ua&Hp`yf9sdlB~Yv22wbAIRX{my63vMl^R zFYb2lwsmb^DJza&avUBepiXO+631}~`s`8F=u5kH?(owi>y80#+?**o=h0dQNlb*+;n_LYNQB^$E=a9e)8wX?9WsQbBRH=&@QzaLypa|JO2;E{FTEp2OG6Zq+- zjVLNAMkJQN&-Wa`m570&(sFnTN+C)d1c4(UJk;<6Zj4>U0vCrjH?4&y--%FY5`WmU z7X$qtd3z52bs`r4V&*P2FI(QZopl zGL96rRGOMlr?$}r9x0065_!mq09oQuu$JQdEg}pyeNVb*j*wm5xT|Wxu2{BuceXJIVy((29x`Lc5~g5~vOrM~&l3OxDuLSZ(lbG}?w7rXAZt zDAU9VDdL6{mC2y@pWo2nCJ@WKUFWH*>;uw7!=&Y1Hw5koRfyM$zHTt|>te?vo>*7G=iVu*S|FfU&C_!6_7 z3l-aG8u9<+Kng81`ay3yIWp1XT-(+eLS>e)dW##{i{WyDoAo#)CM3j~7S@hx14LISbW9f6xB zVBBjoFHWQNcdL{4Z9c&mF*WCbgd~q-esOV0-H)Dp>aCKJ;+kd6 z&8Vm>hu7vw zV&5%6aJTr)IJ|^p!J*$OoX2YUPeA*7#9ZWe_(cL?-V(%@or+cFO6@YWsQOok9<5ks(IYGYX-y*x(>7rO*J79N!$z~O);q&oBHf> z-Dv@bE*~WZt`}zSkHQ7+(DgGy3?pa08*{leClK^IeC@0C!{;edrmdR4;n+A{t lk(c3?EbXgVF8Hqi0{|13K^-xaz?uL6002ovPDHLkV1iEptQ!CT diff --git a/main/img/icons/32/zoom_in.png b/main/img/icons/32/zoom_in.png index 18e4383b3f05da224689b17829d1b579d32f8c23..0b1e42c533ff562419b7957c1109c40bf03b804a 100644 GIT binary patch delta 2380 zcmV-S3A6UI57!cqB!32COGiWi{{a60|De66lK=n!32;bRa{vGf6951U69E94oEQKA z00(qQO+^RX1qco`HCkZ$^Z)<|Gd@T~=sul9M?zXOj8+e)Ij!?{|QkXmy9{<}`ORjb>Z$ z-iL2v`-6|-U}Jr%l-S}ZCtpd-CjekHBp7dpq>t~t_rCGE{d=*cviha~#PvQL`1b*9 zD%*sl#EkntZGYVNQbtDRDzDcI-K8r{(?}@=(==5i8m2%XfKLwAw=1ch2hgy8e;q0- zxBPGq)b0BK-h{;XkQw_tH|Lh()Ra_=O^mAZ=esE2zl3Ns3IH(N2D~XL$jQl7o&*n# zjEtbC_hK_+#ywI+!&Maz+&sYH=FbrhgnXJ?KT}kAyMNw4*o)&WO?0L=JQUIv^+#B` z-$r~?K|!dn9w$dr5}f`;E0-qCFIrQq662F_@>E;Qj97W56aKb(>mzdq_~esXFeXx5 zhI^p6=nlQ5^(emlx?^%k6dn`qBwOc-0|W&qDW$R;r5q`x?Jy}+$i0}_i%ZuPdX_H9 zMQdwIEPob_&bOo!sD5Dk+&!@W)4KC_uPt5LeC#NFcC>rIpICCzYcMxsM1TS#rW~b| zluFr-Ql{y^mP$&cRLo{}HnkOQT6gQhCBCKVt0RZIw{F>%dm|6HV=j%eINe1}-(1KY7=N2g9vYiW9uHhj^JS)vOGqLRai*9b znS;Thj%44WwD|cM3zBcYvuNVO4{Dp|6a|T%#8)(zhPKv|_PD#`cv_+`bd52=8F9u) z*M(fSGGpG853F_+fH!JSFex;qKxA@9+Kwa1lH#IW(9(9|$%sPTm#^*Hw4&Q zzke67t!+zuIr{nTF7!-#&L=0kbX^zZ7K~{cXPh(U(u6aqK$j+i1VA}bQJk(bTLEM; z;x=cTNfonfbdGB0R*jD2`4;=!Z~t@mPr%p*k3RC~{{b)nsIIDp8M7Yrdc7Fv>qRtv zdB34++$A{E4IOS>Bg3tcVYrAuV2nUSM1LSM3=M|nVs2d{w_AgzadNo?O~BVXG|-3n z85yum^TF@i{C|!hES!k>U(QjHy+=B*htrf+DFP z4}N`mnQcuAkr7yN{<5(g6T+9Hl~$2m!!TTl2vgOHvAoGlth|+xSF`VvQ&K{*Io@Q!kW9ZzCYf zt-G`5Btl0@MO;V_=s%|?N4%ammE(~z5DY0P9Y)iEI~}?T2uC7HD!{UplHhhAWIL~a zF>+BOQ|CgE<-h_+sT<^+?*J^*1b=6Y;&iSZ=nRhZjz=T<1UXL1q5 zWw;oWQfexu`^gtLfM8oRf?(fN^J29xHjQ@-|yB!n=(fd~dsRSUCbG=Gh82?3j! zvtqF)gNVWJztlD>z*H!7$c&k*=OrbO&lB{H#ypoD5HWY!fN%+LA;5&&;=CWkn1TXv z&d8O#Xi(V^&9QCRmIGm1%m&ArMbWf{8R=pw7=%ACdFXlo3;_1**#pM#R$pH)7G!3j z+&57WakyhCk`9=(6_+-Ibbm-lU^)b+LlMwi8n~uG2n}50V1h%EkX3n81zFik(Am`q z#%TAhUAwODfrlP?2mspOeCzKWRh#c$S)QMmcW5|vVle8uY%3-~90Ug9LiUdaS>ITg z0HA+tig8^7q&;noRN!19FD*K6Ye`m~-~t_|JKBHq%^|(cYlBpZvxR1*}f&n z<`=mVZj&!MHz^^liKQ&Julic!=KL`|i%)|Mrj1&N&j&`?`ysE(uo@6%_Hl zzHjNx-T%Ph!$(8Qa+j{iFDM9{J#%(wZXWpCPCWDUGkE3I9e?}Ru3cAg%ko<=IyMZy ze**18)IDl>Mgz7H1b}%Wl9=I|O#e}qD<^ZoBBUgzqP49RUmW_Zp|k74=JK*qq-Ug| zxv3e)T8`iUaoxW9In{(UH8ptdx##fmjz2%1nwGZf&O1t2R#p~bW)z`N2##%mh(Xug z@OYA-2@Mx}E`Q?4*GJ?)fBzGIdhw+X@$FEgAsbh>!Oa6s>8f+*q2>+1W+e+1V)HP=+I4eTC*@tyT3O)i>~20N6GC zweK?@b$<=Guq{hXjE}!J6)~&tDk*k#cX!kH_$A!4z7&@y0}p#s(qFyapOL!K%NgUV zmO3-6y*hU-bPRw6z#R#NBJHiM8vrzJt|&`5b*h7ghldf1nrNu44T&3QKwa5PUdLkk z9v!I}5H0{Z06jDnjJ3BO-#~=MijDUqe0s1Er$ySo*$%)U{IEu|fYS_JXwxv{_ISOi y3oWqZ delta 1957 zcmV;W2U_^o60;AGB!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o000M7 zNkl%$w!C*K?o8 zmO+3g3Q?bQXL)naxxe$>bI*Ch8HR!X=f&OWx2-+fT4crY3ddm;fm)4OMjXc_>9s!| zk8RqyW4n)T8Fvlfg|+M4b&Kkcx?GOM?QLzS_12)k;kaSWWGsfyMtwLsJd8*rcK*`~ zpS17W`)2sd0)KE@w)U)+CFMZ(n$>7*T#}cQGiT0X|A9WFGpRK@e*RkD7g1w20Jr(4 zTe{uu!rl!pu7}IzGH)I}H-_GmpW)=Ep|G$B(a9uU+JAExm!cX9OUmGMl|Ym@2m(hS zJmQfFTpPcP1vU=9UB42}0xLqH>-hbiH!(E$cTa!c`xE&9h`D#E>A_`#T`M}w#lx{U zp83rOu(&I*qPY@XbxwGT6-3h-VrdTHnSerynFuRbAh=4c&0*SRn^YcHT5iKcJVT3XNYm8sZrP2Ow(o_`3x80_P^DauWe!!|a$Gkg44k=S`e448 z&shrJ5x^n}!Xs4`6=a;nz`p}6i1fQ#csF5Vz)vQ1!O3CL*yYV z0%VCtwYLHTBNVWf1@pyxGT-?CD3sNfd8MTUuVKWm!eX_fhW30iYf!Wlgd{;1B}j@w z5q~St6^UHSa5@xN6%mpwpmcr_*(S+H7N#%q$$aONguJ2a(8!QppePnI(_>6_eM)u~ zIa^$@kWW#>t~cI?M(kOg!-nsz1g~b0$#Mi|fks=vAehfwfODS$)(>=MK*o|JlY9h_ z(vdJ&@CtZRKp+L!;=CZ!BAn^lpd3~xdVfvRVQ@Oll}r_N`kZf%nMo36ppmgaQBa*H z01a`1+P>)pbI+OVyI!Zr>9tQSY`XFn|q$ondF8!mu;Id)f(XsrqNo#wg(s;8$*0D z_7AhD|hRI3Mv7F#}4y`SC{xR~Oo=X9B;BOxu3kHItCqFuctij{?x)hxT zJDq*WOfa@cnodP3nMOR3MoP^>&19+jX&Cos5u~cWwmw7ic^o@_f^tI8N6vqIf%(oy z0aK+!Q z6S@ulloN@x6|tlRp}34fBa3Ed6yKN^f+C5O1J|){-`i+f`T!n&cqObh2WlIdwjMgT zf9IVbrjH@(TET+{`+KR7@PDeB`ej#FCzdrWMMFUX4Ynwyy*{hObCi5MH6xMAv4T^l z|A`|<266Ab^;E_kv`tCW*44vdG@(Cii?Y? zA8cwuc|{pK9?wj1VRa%92;lR}S8)3DX{f2RUS3hovxgXoDk(48@PBCM61e5hfloGL z_$bi+@{wCYaJTr*YIre?1&bEd*SEEIzUXi`ma)1%8-T70KHuo|pKRXJ zUs+QFQE}mZh;CaiIDcwrpbCl3eFP!h7J{4OaZSuAqTHgfu%t-kjvAXgk4DXVuRStU z@4SL4w@zJEobu4QHwUrNgovryLy!Gz@B|CwPTk7LB`1rLJ>U6n8WXwSGP#J@J>TO! zhdRzhYvGToNG7!@od(y^4EoTp3vDYD6g%Z()2*7v-MeNWzJJwopyNci5rJs(Mu-f> zM14h@I+V7%4R8a*w|m|rh$ZlaMX0JaRSAX&!mzWlHd6xbHo#2~`#VOWUIZcuWK_DH zrIENsr-;w%zu}j?ihA diff --git a/main/img/icons/32/zoom_out.png b/main/img/icons/32/zoom_out.png index 2bdc37ab3d75591e2cd3bf1940cfc2c8ca59002c..8d213d4ca1b9407ef84a72987353ee63296083fa 100644 GIT binary patch delta 2332 zcmV+%3FG#k52q54B!32COGiWi{{a60|De66lK=n!32;bRa{vGf6951U69E94oEQKA z00(qQO+^RX1qco`8ECkc7XSbVv`IukR9M5EmuqlU)fLD8Yd_B8Cb{8~7X%UlF&GgE zG(<&ki~?#<1T5;P9~@h!9c#zwSRFg#2W`iZsaU4dnRd!l)PHIFMd~9l;c0wO5lI38 zLIe_s#E=jY6LLdxlY8$uXRm$;aZ*MIxM$Anv-jC&_HVDV)_<)7TtlncTXj`)*V1UR z1@C_FHXeEKN$jqz&NK#V0uC0i!88H@LETEoCK&qYo_p@=tJ?k^)~s58O#te04|aaC z6ZbB^7wKs^4}a{c-S%ouPVP;SNCdWJv(}oJ8OdalN8=+DjYhF!cXbmRehEO$_U%fRMg|HCi#VJb zrkMaC~HS#oB8J*jxV@MxwC-?bydl7k}Mscb@IQ!G=0I-Z9c0(=$6q zMfQM?lsJQ-c*G8w-i*|sbLRXx>C;LVmvLH3I*uGYlt_+x#mQjg+x6=nzj}ZjJ1QZB z%CKCgtE}`EyP zU4+KQhJQpN9-ro!Ai93-BUf*M?YpW@-M+MZPW^%X^y&V#u7R{AMh(w_yaywZ2)fR6Af7U})3vpbu?UU3CGstI2u|@vVSZ^{V3?@?mB~MIXUo?$p?RE^Zyf~P)ca2 z?|bMU@5MyCOWPh01Fia2_W@bo1=;$31t{V{?FyIr1Q!HBwB0uR( zo{XZ==wYSw!t8VzY3}j|(`=;;NHq0Yb-#J%q#28M0!Sb*V@enpupbyUhQY=_3q@KB zX`tYf21Mv#aZzw>z3pdE2+?Ythwp==U!}{REjrl+JHnN`NXl~$B{Ry z5YLu%uhoi3DnWuI2`NcRO-gH0mWHx4)cDDjfFKE}2$mxHUHQ=3f`8dXsBfsp@aXUp zfBN$uCr?Hn@A?GWx9#XIS$Na5>*f?K&d$k@^WBp-HuXnZN7?bTRwR`i+tkt!QjUp$ zF<=J#fH~8OhhDv-^U>RHxz+CO?xx)z@7(m_^Dq5#_s-g@%Z6LGZpBkS|HZaBMYC5G z&n=!YBR5+uN^dW5F@Ma*2D8pWDppF2Wk3MN7$ki*zHfMaL0joFOGYY6OG@RLGvCsi zTmFH)d-un#E1ENJK}kvU#PJi|S5*&e`s*e<_sny6{f!OVmo8maasAxu(fi#w3=H(6 zshiq*y>M^TcZUFAiW*JJu?Dk$l4lj>PM?X4shMaz)QHdbe1BTg()!K)E0&idJ0}bE zb@e#VaPWbTsn%$}US1v&$v9%M7y{n|k$`PG z2#3?5mB#7z)7babKGW6N`ODwG^6Hy+uc`>{xcxTax*^;+{|3}I)T5#9!0L}GYih2k zEC+y>UwP@bX@BAH&t}akn3tK6iBKp602mpGq5ph8+S}WY_4oDtd&6rR|8nuOCKoI& z`~0DG_ubsm(n@)G`M7I&Iri7pp}wwRb@c=YnxtNo7bArLBmty6{p+U}T3Y2AHZ(jG z>wSC6J6{7x00>Q3tHSA1!t+WNd{MEoJndxbNy^L5$A5|y%dv0&KGfG8_#T3;u=zxQ z@m^eJZhTA^wM7H4-ISDYN$KL6Rd<)CwzRZTetteytXz(LUw(=D1C6VzKdi2ilK_ZI z`b+O8UVI6-@;#6H`}*D;9!;*lZAqEc*49RSedlrKUFEni7=0{~k^RQy{*1z&Ua&H zp`yf9sdlB~Yv22wbAIRX{my63vMl^RFYb2lwsmb^DJza&avUBepiXO+631}~`s`8F z=u5kH?(owi>y80#+?**o=h0e^5?w{@+PCFMZp`gLe(T9T8IvuDp?|AB)@rIYJ-{`QrFUnLu}0dQM> zy|uHju&DdFXE&jspum23BT@`Cfkf``=>;#?SsZh?HE4=O4NokKR)ViK3oN=!j?rqA3EA zHUXX#c^*=}2b?IQ_tYhHuBbtIc?JG?_MEq*)cgL0kIx6@0>HB@R8?2+TD@u|`8II) z+!b6`Iow-cg{2iPOsHv0YP#(-Zdgc=Z_O498h`bIEOV&#RbbMR(0lfZZG+ijHfLq{ zwg4QWAUsfASxL$|djA!GyTFT%MIMAG>ZoplGL96rRGOMlr?$}r9x0065_!mq09oQu z0nWV(*gPc8X|u^7{2LQnt`I&k06& z{!j|Bq)v^P!~~I2P)!om>Xd2{x@WZoTFg_%rou^lyUc0ZV78deTmhKzSZvULd4CkN z%do0KqBM&HK*M+}jfuEH1T-C$WwKIP(6;3zO$A5!?;K<2Sr|r&ux;{y}A&>UFWH*>;uw7!=&Y1Hw z5koRfyM$zHTt|>te?vo>*7G=iVu*S|FfU&C_!6_73l-aG8u9<+Kng81`ay3yIWo`1W0anlPQ z9_raa8pd1z*k#03HJ#_m8w&)2-|;P6h(ZFf)E$AFCScrjVLa(UJmo|*;Xp{0QDo^@ z;fdhEc_Ap0NIfu#ef!=;^U`~9|NU#>bh%O2*u3rVq5ZpV2O_%-+0+UiI@HrmM8a!Y z^0khRb}VmRipKmn8eNg;J%5M)9m*`KHOKfsRB-ytKhW3LkGt+_AR2c=jVDl7-vBR8 zqxE;IllN^t!5A?$=YfPIk7RyvaY@~eo_y-9l9J+@WzEf~s4R!q>zyGN#uI@+0H0mG zhBIf*Kue~~ipmO}9bzP6QeJf7q4p&xls^N8w_xxn(E4KEEkSU%_zQfMo;%0IlSBNADR5smaRQiwY3nH0^FmV$7=acK>K^dT;zB7 zMFL^o62zCCilt08*tx8j#GNTuc0EJF*eFU8%JkB=ez9fyKuc8+ovv;gR-{f0iS~U2 zLi$n=+#JU>F_RJH7Jq}q%+cFO6@Y zWsQOok9<5ks(IYGYX-y*x(>7rO*J79N!$z~O);q&oBHf>-G6BSH-Y$J*9Qb*3H(zc zG&)P#OfWzotURh6KSKd`8o(Do>~Fgm@gWe7BdyV6og{vPb`hV`f5WeP$=SwyZ~OWI zHZ|E$<0<|pUhY{%&)KX9eUkuYgD5A-&;G3>xt7UN>YE0T1(BEGmMrb7SuXgm00RIM Xmq8sdl)#z*015yANkvXXu0mjfw(YPh diff --git a/main/img/icons/64/zoom_in.png b/main/img/icons/64/zoom_in.png new file mode 100644 index 0000000000000000000000000000000000000000..b6a1ecb6d1ffd4e467f63d1143d9be302d7b6aea GIT binary patch literal 6276 zcmV-~7<=c5P)!3W07wE{KvD@AnG9*klr0w`IVweQqEK-XS#soZC6N^-QI#VyWyMKktDLx0 zk;<_Ik^;q@p(xU_#6<)FF4zfx00uLd?Y(*Xc5k1PKkj?O0SJJ^LRF=buIjn>-8;9t z&v#CrK7H;5{(t#@yU>T-!H<6SqjcQ2E7_TO4w3=@1Fi;)saB+Q?4DchseIUDxKO#` z0G@m9iKPy>i-iM8c#}8BQgVNF4s$v1W=$w2z z<|V&>+ikZ6S7Lk@DwhS|zWeUuZMWR;c@Vw^=wLdXp@IHE8th*H5YTS7(P}jjI3Ga} zKt#e$iC~O{wHBWBV66ug!PN95rlu#fT&XBPV^F#8m6vvZ=f3;ylPe1}g zuQi0f0CYH)>*W>8R#GCKLcLK%xl%;ES%Y(eAP7*a*3fLW5V%mGp0$X@<47fwu$~2z zK`a_WJeEW>5<$IQ!^r4}<_pux#Cz1q=kLDzo;_Dg>N(}20jMhd_$N>Ot`hE#MPpdE zW`mc`WKb#CR5TsFrODJ7{t8!^I@$; zGM+*_8b_sC!jX55`i*)Gs{DH&zx$s5b|r+KTP_N~^UptT+ph5!fPQAdf`znh%`jD} zWlT(+M!i|b$#+iR*gMCy-D;8Jbg81*i3WN~EhK9`5={XM05F6-)MHW9k};j>$(VA# zm1;H`jq1u(t7!R(rHDmiNF~znYy`(n9MjXMM-`y&Hf#Pr-oAai`=tZev13Ohn@j8j z(H-lq-e3p&7hrtqG-irCw)#dhyenTC7SI=6%Z&?p`xnY zYZ0v_`efs%ix|JYdH6c7C)S4 z-EH?n2k_K0kKGTVFK^y-jm`D+;>5@?3a=D1N_PrU1 zlW+XSC$@j}LkIBGQ;*y&M31doyPg*;7{ZB>W0;zr!pkqcqKzO?7`2;slZi+w8nM{;AZQH1)CyR74i^=J6 z?AyOzK)CxiKk@gT`OpCD+_|$S5~rgB0}FDShp(Y`Mvft$&*R0Pzob={o*bo3Z$u&< z(sAP%CNP+Y2~6QUhl0@g>r_EXvt}=X@0V!!;PkKfiq^&~6 zh=_tz6iNg#1QF7Af~((H&3m`*-o2;i=3BN=tKGy^D_7HWKA#fNuLJnvr2;sw1w8V^ zBf|!|XXEfD)6>(7lcVq8;Qm86K61Ks95?*TMq`qRThB0&F$R`E%phV0Kp=nwiXXqS zf4JMG&i=uy*W0#v&2A?UCjt?t;-Df>rvep)bY_LowzoFE_m-8*hN5e)UW-I5g;KeQ z-Fseh8U(|i`qXC+Tnd2mS^z=5nn}G zjT+4=0U!c_2r!1pi&*lEp@=2+ER(eiV+^q&GM<4kL`+N-&COJiJH3DZK@n91F2Ks= zD%eP`Jf1HdYu^E|ILIIs{ir25W%ozYYeevvYr7OL&h*!W8fJ>)-W04 zfejNg(^zxSky5!xEk57Ahx<;Z;YiUEM=KNuVsi1|T)dZUKpCq}fzxhdym znu(ZaxFdY1B|~hOt!K#dh^=9^*1|BcXABW30ZJM=1|lLDgz*7`$nzN18Zw5+bhK}6 zsC{AsV+?tQ$XWwtrWU0d4M|NMKYmifxIwUJ(NIiPK6ga`JoMN@YejU)g26>ptyK^N z0Sfs7Dm*yqS*ECG*suXJ5qAb=EQ1Y^VJ2(4*1%*e6M+y0#9>88^VIRbhC@s7*pMM6 z%S=o}o(;86hC$4sudxQkF!KJq(R_XiE)Y0z7?|Hr>SXzM{_;ClT{Zv&!EHp`&gJ^h zXjUk^ncnpQ05d>L06+>2t-xUtU!)GgE-7Ae+g;7}I8Pw_hxP_pAaUdR;0LXDHBU zHc%{;5!iH@*s5m@vt@M5Uzv$dO%$?*K@27^LMVhzJP3f4h)9_jVYr|m28crTrzQ(I zaZnY}Kom|PBC4ta5omv3c7_3XVE8H!kSax7n^L7>vCuO(I0zy}CX=D5eBs*51^~kP zSUhf>IEV;pwYvI9mW{`uLt+l?hKQJyUf+LWF*-trtN*O%-6bCiB@mQCGN6v(5rN(~ zaB{IqxNlI>*<~`^H$fN7%gv}!5EMqkRD!ajrbNr-N-c}fnvhJUynMbe{2qBO7J#ZO zPsEb&+u?4r*=Ql)zPiVTh(q7aY`{6nX2JB zKmeTcRV3(WIh-OPgb+m3i_JbgRSufFkClr1N9tAQ`v|uO0Vax478Rn<^k9sIsAeu3 zfQlyA7&xa8Q7{pNtOFAPpk|hO2-AszTw8 z0O;%xL*W%fAZ-P{wtR8Lsvms+=aZ+p$yBxm2n1p*nqu0dI!n$N3lT|NJ^-L4;$orK z4g-A4Y8(S&Gp+iM-z-jmNj+;RVya~7!P=%T#usG)u{9KG6#!_i4bYrEx-b+VQYWg; zL42pqcjAl@Z3Y5g5w0qR0S+JmgDt=!h(^c~6O1vT0z{yyOKKAn? z;S@ku=*}1byu5z`0KjAbW(a~aAPl556OYAar&Xib07ND(8-O_XR<&AP!yIm8(uo9B zgI4nRWV`N^#Q;oXRY6c@h)s+i8E@n0)TvN>nuQPw)2>-Frj!8%OFdfo)P6VJh$TBz(fbAI&7Gzy-Pfs6Hxa^=*E{TY|arpp5_Lj?)Un3yq z*$C3vG-gWUxpD)(6H--H*A47JaM>lhl`NPEhB;i^nL7*^a(d6*9qGW#bMzdRMrPG6 zfrL4;(8VJV>EzA=aG(&24g`ikV1#L?2ZOnuo{+dIW(tLN;B?=`0(fsI%y^;MY{n|J zDq_(XGMNk*fgMT~a|%`^QV>*$Q~-5qRFxFO>OiW7RhgB@sFG0tASNXy)y}>EAfOWo zvN5n^!G=LLyl%PcKrGl2m>6UMrZ61dw4goDGaBjZoeu&~uQyPsR$~G@f7t+%(d;X# zQXd-~K`a^%Us)y7ZtJ4zDgX$S)PW$%3N@+<6(V&+>WI~;2`d>@V-#~%L&I|x1_l5E z84I$e6JuDAr8#kb2Lcn&xyQt~d3p1yWHRgG@imkj^_oXY>4 znJIeZN(sqC61lz{;-2NZSLCl|;xJ|>Qh`d~NS(4mSsg(EhAOKNDafdT5eBy=Od2u+ zWM=(jXy%~>5LsXj1Q3Ti$j*_8@#|NY)+J&QGdM5^ae`*Efw9x4qw3_l7c2aE0o?nK z{@L@Y*mv;I0ZqgbFl;ciWTDwMRN2y-3}QrG-)SL4p~*9;l2HMPn9vuv**7<#<_%jI zwqa079Ra&0Z{9U|SPG{DhsW;qd8r`&k!8&-YgVr@%nauo_8r(S%>3q;zVwx!UJ8Ko zCPhWueJ4(w`2M=J8@yy94F!-+70hpM7`^>ZUcc(eS#+JvA#~0K2~C&Df&l!Lf&H z)}f(UN*9|{dGkc&j5^bxirQF(vV&u!46t^RMG8^s{0_%L3jEfF$!pgS_^YqkbPY2x ze7}ufy!uKoQ!KptK6Gpa{ z{b=pEvBAR(4mAm&YYq(Vm@k7DU%QLg%+6;3;VUy0a3|*=EMUhFc0gDA2-^`B+`X*0 z`sT&;>xS2Dq*yeLMx&1LiPJdz_F-y^`zMzwJa7RE0Dvc+czWXQU;VqW@zbYoSiWqz zNyd{P16XS?XeXD&thA1lvXjIHVeXF5O^cBsn9h;Oz*qut=m?n+E{>!iAqdIr@9xr} z3P2RUv3g?oj^)K$SFc(_gZ&H8Y&KA@H}LqAkF|Zj{U86}U;e8dmjmG3S>ZXQf8K&W z^nL&J=bwMhR|V3E40`+euyEl5{H;a#ZU1onv0G!-8KAp;Ija!QdUUb|WX&1Z-t+IB zHsU6*_ih@w^|mGD8&|DdjfI1Y&}=r*Y&P-KGf(<{yS;1a;+6mIa)b~2`vB$7{_KJN zK)qLcdU6Zz{OFz5sYA71LA_SP$f;4O`lj;u$t6F1tJrti*mnaOOPwIcFgQ$-0tn-L zaSq}H8aM0ACE42?MQ9j6m=XS+i(f9_ROw=AdK~;Be({N)tTx3I~I*!yD(8(($mwct5&R{ zXe5eu+efR_!1w<0ds460c{*Rv>8WW~DwnJ^2A=0tiFp?Zf91gkAAIdY0RRBs{N^`T zkdfzNvDkv!{`T$Bd42OxZ#LiuE!1i?DDlfe7;=Fr) z?JlGi~dUNfd?MwXRAAi=$6f!H=E%N z8v#``+f6ueXf~TDmrE#Dsv<660lB)1R%(H%w$!!&AWA_rX8qpS=9)u75i^Hu>URcix7+-d+$H^v&zT(9l98Q%OAb zqetET{f8PC1L2as6Wp<5hdFub*uPQ5A7(Ncz43+{yv0LH;l#lY+6bHj5zub6(QG!+ zYPS#sL1&K-Fk3{u2%@nVQmGW;v3U6M1n4G8F*-Ji7hihOFBWH1MF0IWPd)pM7hZTl zx88VD`MT>iC6+B)g1~p^>FGftk-)-*1Lz;<$IeF{afc2Z{=g6}>r2sZeB(c?A-4ZT zp?CE5_5~Y~x;le^~n8(&zxYUxc|uDgb2W{OCq(r_+7B9XxQ4eQZAFb_L_xYHdv z_;$lVZ+rOr5AXUg0GyHS{QB4LyU}{yzXsthYdu-Ibcr1r8p48sg~((soT;u=+ww>K^Ll^hqql#=6bc1QPD~-0N};zm zhn}7sHf&svfx-EB_@SNd@WI3H3*k}#&^e9-fWG|YFZB1#AN;guy^j&|jUo~?#<)}} z<>Ilp@uCqX0Djw-MziiJm8x;h86s+l$Sbv4{mFfAy}onj&L{Kd>wE3+rccHb@o(R> z^%^W*ya*#BBbb>fBA4q$E|)`ZZ!d<2*P(x~9}hkBusi%dmT<8E-Xrw+>hSPz^v++s zb5lGPU2E7bH%#-vlmY-1skuO=TYl?AF+cP66C_s@G@2$urjLX|(@eZ0^4x%y&+p*sQKH5)d5 zA(2e{?zZc%!O+lLOUTVy!p2P-F~7eL4?XmdJAClSIU!tdFK`~==MMN%gr9qU_OSqt^Jur5;0N!^BTmZ_&T1mH>PVGW4`Kie_)7c(3IbGP2Nhh&%$r7|$ZOqKf zgik9_E>)1pX0dh4bv!i|iiP5*uUfVG+XoLGY+fvYxyN$}aiQlvXwh@j zbG6xRSMyVoyV5;5e{!mDLnfWXvSmxr?m*~%Yfvhck?YN2-G+7i(u*%g$?)GC*mvN_ z1-}$M$G~XLdAD?uRoE23-nagI?S_r|;w!tq z2ms4hEQdln5C9^eUaf@*7!mbbjiUhQVl3eOieBJ&c9pZvyVZSwD(9#QfTkxWUdv{4 zGCq~RK9fpf#fs%0-VW#r_k^6`_$ ze`{)ds(3j7&IWNdjQ7+2xq!?S=zM~n4J^QWtpfR}$=9;koQ_ZBuNNn%RI2#d&tG!m zQ&W@UrzbwU?~T20cb~mj2lYW=T*|!OkelU3N@;F;puOI&HWHRwNYm5tA@bsy7 z-uc$l)YLS9W~a8UB!CN*%jsvCO^m;C7EhA~PyE6!eCo_{Khx6VFGD$a@Ss;H zPW=NW`I1w26Eg?#cwCanG$-Q;#N!D>B2fqn0H7VT(P}nOsZ~*{RZyvxU9Hxzs?Gp- z&RX}asF!%)w%cwCmgD)BDpv&H-h1!mn?H8L7eV*~KnGK)G!66*(qR7(KtQY2LbKUG zVA}|S0M5B^P$GyJ7-QfW55{;<=a8G3Ms8+GOXacxGy!$@zWDs%Z{K_Gy>3~gy-2xi z08c*s&CysK6#e10_2PABu@CK5^4Kd_RAh6b@> zmloP76`wwg_{oGO;JXR3}&v57>rjd;U>9RM&Kd#FVts3xL1 zn@LNl-?&OoBofh$n>Nw<4I_v~qDaP5@Qja>r%&p+bK?rocN*39Z|vK*&;Hy2?BBoN z@5#mwfas2GTX&ej{vk}}&S7>gkFhgjICk`e2F|*o4xE~!b!XZfuM-0VB11Gkjw;}w zP=z{G?Y8+^jrY;mnjXrn^9=Kj9ouN_$XY}rF(l(D%oK7s{^s!jPM>VlgU{^Sx3Bec z1F(Ppeo1E&|C1QMynFOIFVmC3nekI7mWnuh=oL3xC{T&|Pvv;aTOi+hhS?V)CSnJG zI;QVb0abMhIHzjW0SdJa9TWg-(+u)ESM|`$NN-;s_U^rw;;}eV$sUv|CA{&*Yi(=Y z_wWAHXFk{M_ag`J#8Z#n2coa;-gS-1W_odY>?HDqJYIPIZ?xXx`lM`sxk=el)MxPw zixB}rErW=ls_3X%RTWMVLQqxbR28buhJaK<7zvt9uaP&ejYT+m^G!EWx+jBFB8^gM z4zC}1EpXO-{Z~G{@Ap1(08c#e@Li7R(QQ|6=b@otoE|%g+)NHHJpZEBgLq-w>^@B5 zyJW;S#v>vq5dda_Td;VAx(1x013}dWp}^L;&=$@!f_19w+Gd0Q#&rp=mA&QWn<6u9!IeOHAaMx!){r8{x$N(HTa3JHy=$(Oqq3rI_Yv|pvlgQ`uc3Mbw^t`idzg?hEU;q#yWeCcul@KP8382^#y`H3A{chThZ zB&yXa4j+73>oz`nPIkWk3T%>to!1YtFDeTTMf(>^LXpcw@_`gTNAwdW#9KG7598$W-$g4BNXw3Bfdwz zXUO-2jS=>IA!CG?!Ny}2!^DQ!GaiXB8zUs1knan59c0wf)<K#>RA#w!O^a+f>we zo(Op&U$zW6q+kSvt?on@o) zb?S_Uaf8F^)x%L$_l0Ev@Zh5lUhSN&9U5Fsm1-G55TKARpv;5go?(i3!onRV)p;;6 z3>G3`CS$tRz$Au=$sqLTM9e}S35BLF#0(M+EyZIYAtu92OcYv+Fp)5bnS?uI2_xTL zF`m!oU;_v1ECyEglUld_+kf%xtF9OTg5WkHZe_E5s5dH@%@;s`Hq2l?>WeUO_~0UB zh(Jsvorf1;5DC}-A_5A5u;~bFJOLXbVG13cF(ii3g6N3W*PtUbfdHBp9T)CYy19U`eSY^tr0T+bgOYalhv9F94z0+}swfBw(J+;u zY^mWQrBb=t6LzdfB$8e}Ul_e&0IF_%Jeoke749}0^(F%Dt9dL$Oi%(b3m8gZqaecl z|Lj%__NBtOnxIe(i9oR++9v9Rx#2jNzpff?6bRjolVYk+!Eb%@r$oXqRw>_TwO&6} zDxRFE)~$2;>FwG(kf;w65kY}OJPuX2?ur38>ykzUPQ#pob!{ROZ3{D)1x!#75i==u zd8 zIdw##=|RN6siv3qEwiwLjIMq^#ctPS9tMMsh0 zF6g}Sao+alLChP0o1YdS0%70!cgAe;#9!hYw^LdAo^1v2bw z;XgnDyl`|10Kg;wGaP~oAPgim9g9XgmJ}}8aBk{~0XS=4uT&~qn3;(Psd$_!K{Ih` zx>d8vP5>q{svsycoQY4qJ=wxLxwE18G!J2cK-A6lbUprj=A)Aw?V_1qJJmUWVj#od zzyWM7fH2f!do!6nrf}Iou~c-9c}AKRatGQ zK@bSGXYFAn17?CS0~Gp=kO2csU`3eiVF?2q8|H)Cwwn%fVa_ac@d%vjBu z7-RsZFdW`B)LP+*`hC4CK>%vCI?9zw)B(?2F@Qv*=S5Xln;0KMG!hG6StU|-@9N4X z00@-Sg5Z=D8Vcx$)Do#BR;v=$j-c8BK_toyFtdV1l|`8hNDRnGC&n-!Lkr^m4g@Bk zbB&2{%lgJuiA0Z$#bQuZOioS!pi0z4U%Fxd`}XZ?sk-l-IeVt*dp<-A2K!gYmcH7S zh_A*f)G4b~(f|O6RS9a96e{Y7R4JS)stAQ=21wL(-~a|925bbTt6^cVA(&9r^ANxU zbYK9Cc!bQ(!C>?Hkr4^4Uvcu?cN)&w@7{CIJ?$$70036q|CpVf^Gf9+67dAGeObgj z!*^}SZ)M^zW+zeyb%7=5&@n`~`@h~#7mWR{r zRiE8FaSekz8e+h7&6PrPHRpwA;(1L=r?R22jrcqS)48`}`sn(G@P!M0bu@SF>WmxO zzI7Wr=U{DsLx&FrAbsh#zw*0}EIR-qQrB*M@$A`goEbljbTWfTB!V?-*6@vkb9+BA zlG_|=pF#5-G3MJkaF`j?ncplO?UMnqgc@HUWLNE>{b0WBu8nh>Z&_2jZgkryM8KJOId27axE8$*H@3@$W__&z-wr{krv%h$TP*7$X=o)9a$f zHQz4wOcM*j+#R8t79$}@=g1@wLm`NcnL`O61v!EvH~+i)B2^WDQ~b*2snI*u&)vFt z(-s=+A3~#1N3B-JV?TVf)o!=`)9?QFzuA8!0G50;1_1plhJL@@Zol%(Gf%fwfmA$= z-o8GpS~Y~fwK{+EKi+=w)~K-pbhj^y3h}&0CnF#u7qq?S-#dN8Brx~v8oTwjwWS+3 zZQP7igR9YKG|*@?@WfL;Y`0sjgClD;{)a0OJ{<2ult1~C`}+g+Udm*$tM2^7oyMv~ zrB+6*TE*DeaaUaqTOnvQYquV{r5iw3pEcNdi6Vj4Sp(+mmYcKkrP;) zfm==h0Px4({Nqh*_4%Gmrss~obEoHd2GvFd&1MsmlapGlRq0$kdFIFCs}H?hU6H%c zxfvL9;ZQ*k#`>-!xCV;N>6!jJR!?5LDqdZi$@J=`4Vx(9N6>1u(QMZ7=YR3%u2!q@ zOunEqxfxq56^#*r=Xn)kK1hy#=X>A#-l2~K004aB8{gPK;+~F1qeHj-?b{y&*xpEQRi|Hn>|v@ym@pkd-iN|ML|2O!}%HKpz1(QF%mEIZcFEfw`Yr6 zlG4b=;|X0mJVL$MUf7PeFXRh&>PJsDXXj?i&p!Lyio1X5lSrjgh{qG~jG$Jp6NRdZ@riLf_xyA1xw%<&PXFUmPyFcX&p!LC?!ED*(skGEimzL@7D3x0 zlgS_+k7L!U0rU^_%&z!=mufH1Prl$>{|En-l`pSLx-S-YUPVSoP zZ+v$1rjeWWTz3u4&dwp3Ou^a!@pv5DcWg)hzzQ7r{sH^u@we(0dfP(}Jaq7*0B}LJ z^J`zb_eSG+{}zN#8soWW!K$ zmn&ke6(VXn=U%Km}bk}EM@z}R++ItPwtXYk*u`$ff&LNxa zMK+s7Z*MO~N4KGWupbXT_>evE0hVy70Nx|?`_<9W(a4>@c;~KIG;+1DSuad0!IT65 zb*^dyH`8o4PtWCN-+Jt^C*C-F_H26zxEGAMb?5GX8I48%^-b4bgEhmeab|1`bF*{E zX0sg#eb~8c2Uhm4_&^Ak17NAjAM!dr;QV4^F~ZQD0PvO_JHHf9#DDYV>#xD^@Ip(- z&RfFHT|2R|zYh;S_@F&;{OyZESaL7$KEf}2;L8zy;rZgW?r&M}n-L~&7gjGnJ@r~T zlMSYF`RjYqDXd*Hj8?0O+1a`I2QHOMNTpKPvu6)aO-;&de)dp+au@aH=QMo}MY}O{WrAH?kJZW)p?N?ELHKQn7?g zPY?F&*~1g(CS-CAK6d2T+wc8AV(AB?1?S!35Ne}) zeet6g`GR%uVLzt^~kh5Q|}a zkoGSIWT8OsC+K2e0p4pB$mgaH_4H(QGMB&JS%-4Dg1`RR^L8?qo1Q#3^=n67edDd} zy_f2sJ}ivOx%Oc)I*a26!F!j-`MP=g=&vUd@h=z=8`$8 Date: Tue, 8 May 2012 17:08:42 +0200 Subject: [PATCH 071/128] #4694 add feedback during installation --- main/inc/lib/log.class.php | 30 +++- main/install/index.php | 1 + main/install/update-db-1.8.6.2-1.8.7.inc.php | 156 +++++++++---------- 3 files changed, 103 insertions(+), 84 deletions(-) diff --git a/main/inc/lib/log.class.php b/main/inc/lib/log.class.php index a711d33d09..4e99beae17 100644 --- a/main/inc/lib/log.class.php +++ b/main/inc/lib/log.class.php @@ -64,20 +64,38 @@ class Log self::$logger = $value; } + /** + * Returns the + * @param type $index + * @return type + */ + public static function frame($index) + { + $result = debug_backtrace(); + array_shift($result); + for ($i = 0; $i++; $i < $index) { + array_shift($result); + } + return $result; + } + public static function write($level, $message, $context = array()) { /* * Note that the same could be done with a monolog processor. */ - - $trace = debug_backtrace(); - array_shift($trace); - $trace = reset($trace); - $file = $trace['file']; + if (!isset($context['file'])) { + $trace = debug_backtrace(); + array_shift($trace); + $trace = reset($trace); + $context['file'] = $trace['file']; + $context['file'] = $trace['file']; + } + $file = $context['file']; $root = realpath(api_get_path(SYS_PATH)); $file = str_replace($root, '', $file); $file = trim($file, DIRECTORY_SEPARATOR); - $line = $trace['line']; + $line = $context['line']; $message = "[$file:$line] " . $message; self::logger()->addRecord($level, $message, $context); diff --git a/main/install/index.php b/main/install/index.php index 614200e933..0e67177e56 100644 --- a/main/install/index.php +++ b/main/install/index.php @@ -46,6 +46,7 @@ require_once api_get_path(LIBRARY_PATH).'database.lib.php'; require_once api_get_path(LIBRARY_PATH).'log.class.php'; require_once 'install.lib.php'; require_once 'install.class.php'; +require_once 'i_database.class.php'; // The function api_get_setting() might be called within the installation scripts. // We need to provide some limited support for it through initialization of the diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index e632bd2eb3..2221eee3fa 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -88,32 +88,32 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database ' . $dbNameForm . ' was not found, skipping'); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { Log::notice("Database::query($dbNameForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbNameForm, executed: $query"); } if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } } - $tables = Database::get_tables($dbNameForm); + $tables = iDatabase::get_tables($dbNameForm); foreach ($tables as $table) { $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } $query = "ALTER DATABASE `" . $dbNameForm . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; $res = Database::query($query); if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } } @@ -152,64 +152,64 @@ if (defined('SYSTEM_INSTALLATION')) { $queries[] = "UPDATE gradebook_result_log SET created_at = CONVERT_TZ(created_at, '" . $timeOffsetString . "', '+00:00');"; foreach ($queries as $query) { - Database::query($query); + iDatabase::query($query); } } // Moving user followed by a human resource manager from hr_dept_id field to user_rel_user table $query = "SELECT user_id, hr_dept_id FROM $dbNameForm.user"; - $result = Database::query($query); - if (Database::num_rows($result) > 0) { + $result = iDatabase::query($query); + if (iDatabase::num_rows($result) > 0) { require_once api_get_path(LIBRARY_PATH) . 'usermanager.lib.php'; - while ($row = Database::fetch_array($result, 'ASSOC')) { + while ($row = iDatabase::fetch_array($result, 'ASSOC')) { $user_id = $row['user_id']; $hr_dept_id = $row['hr_dept_id']; // moving data to user_rel_user table if (!empty($hr_dept_id)) { $sql = " SELECT id FROM $dbNameForm.user_rel_user WHERE user_id = $user_id AND friend_user_id = $hr_dept_id AND relation_type = " . USER_RELATION_TYPE_RRHH . " "; - $rs = Database::query($sql); - if (Database::num_rows($rs) == 0) { + $rs = iDatabase::query($sql); + if (iDatabase::num_rows($rs) == 0) { $ins = "INSERT INTO $dbNameForm.user_rel_user SET user_id = $user_id, friend_user_id = $hr_dept_id, relation_type = " . USER_RELATION_TYPE_RRHH . " "; - Database::query($ins); + iDatabase::query($ins); } } } // cleaning hr_dept_id field inside user table $upd = "UPDATE $dbNameForm.user SET hr_dept_id = 0"; - Database::query($upd); + iDatabase::query($upd); } // Updating score display for each gradebook category // first we check if there already is migrated data to categoy_id field $query = "SELECT id FROM $dbNameForm.gradebook_score_display WHERE category_id = 0"; - $rs_check = Database::query($query); + $rs_check = iDatabase::query($query); - if (Database::num_rows($rs_check) > 0) { + if (iDatabase::num_rows($rs_check) > 0) { // get all gradebook categories id $a_categories = array(); $query = "SELECT id FROM $dbNameForm.gradebook_category"; - $rs_gradebook = Database::query($query); - if (Database::num_rows($rs_gradebook) > 0) { - while ($row_gradebook = Database::fetch_row($rs_gradebook)) { + $rs_gradebook = iDatabase::query($query); + if (iDatabase::num_rows($rs_gradebook) > 0) { + while ($row_gradebook = iDatabase::fetch_row($rs_gradebook)) { $a_categories[] = $row_gradebook[0]; } } // get all gradebook score display $query = "SELECT * FROM $dbNameForm.gradebook_score_display"; - $rs_score_display = Database::query($query); - if (Database::num_rows($rs_score_display) > 0) { + $rs_score_display = iDatabase::query($query); + if (iDatabase::num_rows($rs_score_display) > 0) { $score_color_percent = api_get_setting('gradebook_score_display_colorsplit'); - while ($row_score_display = Database::fetch_array($rs_score_display)) { + while ($row_score_display = iDatabase::fetch_array($rs_score_display)) { $score = $row_score_display['score']; $display = $row_score_display['display']; foreach ($a_categories as $category_id) { $ins = "INSERT INTO $dbNameForm.gradebook_score_display(score, display, category_id, score_color_percent) VALUES('$score', '$display', $category_id, '$score_color_percent')"; - Database::query($ins); + iDatabase::query($ins); } } // remove score display with category id = 0 $del = "DELETE FROM $dbNameForm.gradebook_score_display WHERE category_id = 0"; - Database::query($del); + iDatabase::query($del); } } @@ -226,12 +226,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database ' . $dbNameForm . ' was not found, skipping'); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { Log::notice("Database::query($dbNameForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbNameForm, executed: $query"); } @@ -253,45 +253,45 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbStatsForm, $dblist)) { Log::error('Database ' . $dbStatsForm . ' was not found, skipping'); } else { - Database::select_db($dbStatsForm); + iDatabase::select_db($dbStatsForm); Log::notice('Database: statistics'); foreach ($s_q_list as $query) { if ($only_test) { Log::notice("Database::query($dbStatsForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbStatsForm, executed: $query"); } if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } } - $tables = Database::get_tables($dbStatsForm); + $tables = iDatabase::get_tables($dbStatsForm); foreach ($tables as $table) { $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; Log::notice('Database: statistics, Table: '. $table); - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } $query = "ALTER DATABASE `" . $dbStatsForm . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; Log::notice('Database: statistics - change default char set'); - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } // chamilo_stat.track_e_attempt table update changing id by id_auto $sql = "SELECT exe_id, question_id, course_code, answer FROM $dbStatsForm.track_e_attempt"; - $result = Database::query($sql); - if (Database::num_rows($result) > 0) { - while ($row = Database::fetch_array($result)) { + $result = iDatabase::query($sql); + if (iDatabase::num_rows($result) > 0) { + while ($row = iDatabase::fetch_array($result)) { $course_code = $row['course_code']; $course_info = api_get_course_info($course_code); $my_course_db = $course_info['dbName']; @@ -302,20 +302,20 @@ if (defined('SYSTEM_INSTALLATION')) { //getting the type question id $sql_question = "SELECT type FROM $my_course_db.quiz_question where id = $question_id"; Log::notice('Database: '. $my_course_db); - $res_question = Database::query($sql_question); - $row = Database::fetch_array($res_question); + $res_question = iDatabase::query($sql_question); + $row = iDatabase::fetch_array($res_question); $type = $row['type']; require_once api_get_path(SYS_CODE_PATH) . 'exercice/question.class.php'; //this type of questions produce problems in the track_e_attempt table if (in_array($type, array(UNIQUE_ANSWER, MULTIPLE_ANSWER, MATCHING, MULTIPLE_ANSWER_COMBINATION))) { $sql_question = "SELECT id_auto FROM $my_course_db.quiz_answer where question_id = $question_id and id = $answer"; - $res_question = Database::query($sql_question); - $row = Database::fetch_array($res_question); + $res_question = iDatabase::query($sql_question); + $row = iDatabase::fetch_array($res_question); $id_auto = $row['id_auto']; if (!empty($id_auto)) { $sql = "UPDATE $dbStatsForm.track_e_attempt SET answer = '$id_auto' WHERE exe_id = $exe_id AND question_id = $question_id AND course_code = '$course_code' and answer = $answer "; - Database::query($sql); + iDatabase::query($sql); } } } @@ -338,31 +338,31 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbUserForm, $dblist)) { Log::error('Database ' . $dbUserForm . ' was not found, skipping'); } else { - Database::select_db($dbUserForm); + iDatabase::select_db($dbUserForm); Log::notice('Database: user'); foreach ($u_q_list as $query) { if ($only_test) { Log::notice("Database::query($dbUserForm,$query)"); Log::notice("In $dbUserForm, executed: $query"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } } - $tables = Database::get_tables($dbUserForm); + $tables = iDatabase::get_tables($dbUserForm); foreach ($tables as $table) { $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } $query = "ALTER DATABASE `" . $dbUserForm . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } } @@ -383,17 +383,17 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database ' . $dbNameForm . ' was not found, skipping'); } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); + iDatabase::select_db($dbNameForm); + $res = iDatabase::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); if ($res === false) { die('Error while querying the courses list in update_db-1.8.6.2-1.8.7.inc.php'); } - if (Database::num_rows($res) > 0) { + if (iDatabase::num_rows($res) > 0) { $i = 0; $list = array(); - while ($row = Database::fetch_array($res)) { + while ($row = iDatabase::fetch_array($res)) { $list[] = $row; $i++; } @@ -404,7 +404,7 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (!$singleDbForm) { // otherwise just use the main one - Database::select_db($row_course['db_name']); + iDatabase::select_db($row_course['db_name']); } Log::notice('Course db ' . $row_course['db_name']); @@ -416,29 +416,29 @@ if (defined('SYSTEM_INSTALLATION')) { if ($only_test) { Log::notice("Database::query(" . $row_course['db_name'] . ",$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In " . $row_course['db_name'] . ", executed: $query"); } if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } } if (!$singleDbForm) { - $tables = Database::get_tables($row_course['db_name']); + $tables = iDatabase::get_tables($row_course['db_name']); foreach ($tables as $table) { $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } $query = "ALTER DATABASE `" . $row_course['db_name'] . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in ' . $query . ': ' . Database::error()); + Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } $t_student_publication = $row_course['db_name'] . ".student_publication"; @@ -451,26 +451,26 @@ if (defined('SYSTEM_INSTALLATION')) { $sql_insert_user = "SELECT ref, insert_user_id FROM $t_item_property WHERE tool='work'"; - $rs_insert_user = Database::query($sql_insert_user); + $rs_insert_user = iDatabase::query($sql_insert_user); if ($rs_insert_user === false) { - Log::error('Could not query insert_user_id table: ' . Database::error()); + Log::error('Could not query insert_user_id table: ' . iDatabase::error()); } else { - if (Database::num_rows($rs_insert_user) > 0) { - while ($row_ids = Database::fetch_array($rs_insert_user)) { + if (iDatabase::num_rows($rs_insert_user) > 0) { + while ($row_ids = iDatabase::fetch_array($rs_insert_user)) { $user_id = $row_ids['insert_user_id']; $ref = $row_ids['ref']; $sql_upd = "UPDATE $t_student_publication SET user_id='$user_id' WHERE id='$ref'"; - Database::query($sql_upd); + iDatabase::query($sql_upd); } } } //updating parent_id of the student_publication table $sql = 'SELECT id, url, parent_id FROM ' . $t_student_publication; - $result = Database::query($sql); - if (Database::num_rows($result) > 0) { - $items = Database::store_result($result); + $result = iDatabase::query($sql); + if (iDatabase::num_rows($result) > 0) { + $items = iDatabase::store_result($result); $directory_list = $file_list = array(); foreach ($items as $item) { @@ -500,7 +500,7 @@ if (defined('SYSTEM_INSTALLATION')) { if ($parent_id != 0) { $sql = 'UPDATE ' . $t_student_publication . ' SET parent_id = ' . $parent_id . ' WHERE id = ' . $file['id'] . ''; - Database::query($sql); + iDatabase::query($sql); } } } @@ -518,14 +518,14 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database ' . $dbNameForm . ' was not found, skipping'); } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); + iDatabase::select_db($dbNameForm); + $res = iDatabase::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); if ($res === false) { die('Error while querying the courses list in update_db-1.8.6.2-1.8.7.inc.php'); } - if (Database::num_rows($res) > 0) { + if (iDatabase::num_rows($res) > 0) { $i = 0; - while ($row = Database::fetch_array($res)) { + while ($row = iDatabase::fetch_array($res)) { $list[] = $row; $i++; } @@ -539,7 +539,7 @@ if (defined('SYSTEM_INSTALLATION')) { if ($singleDbForm) { $prefix_course = $prefix . $row['db_name'] . "_"; } else { - Database::select_db($row['db_name']); + iDatabase::select_db($row['db_name']); } foreach ($c_q_list as $query) { @@ -549,7 +549,7 @@ if (defined('SYSTEM_INSTALLATION')) { if ($only_test) { Log::notice("Database::query(" . $row['db_name'] . ",$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In " . $row['db_name'] . ", executed: $query"); } From 8dbc17a6765cc1caac67e65948f211d27f0a64a9 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 17:11:45 +0200 Subject: [PATCH 072/128] #4694 add feedback during installation --- main/install/i_database.class.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 main/install/i_database.class.php diff --git a/main/install/i_database.class.php b/main/install/i_database.class.php new file mode 100644 index 0000000000..b5f58060f4 --- /dev/null +++ b/main/install/i_database.class.php @@ -0,0 +1,26 @@ + + */ +class iDatabase extends Database +{ + + static function select_db($database_name, $connection = null) + { + Log::notice(__FUNCTION__ . ' ' . $database_name, Log::get_frame(1)); + parent::select_db($database_name, $connection); + } + + static function query($query, $connection = null, $file = null, $line = null) + { + Log::notice(__FUNCTION__ . ' ' . $database_name, Log::get_frame(1)); + + parent::query($query, $connection, $file, $line); + } + +} \ No newline at end of file From ebcf363804bbebb90ebb6ab55d28c64edb6201e6 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 17:18:21 +0200 Subject: [PATCH 073/128] #4694 add feedback during installation --- main/inc/lib/log.class.php | 6 +----- main/install/i_database.class.php | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/main/inc/lib/log.class.php b/main/inc/lib/log.class.php index 4e99beae17..92b0cd1631 100644 --- a/main/inc/lib/log.class.php +++ b/main/inc/lib/log.class.php @@ -72,11 +72,7 @@ class Log public static function frame($index) { $result = debug_backtrace(); - array_shift($result); - for ($i = 0; $i++; $i < $index) { - array_shift($result); - } - return $result; + return isset($result[$index]) ? $result[$index] : array(); } public static function write($level, $message, $context = array()) diff --git a/main/install/i_database.class.php b/main/install/i_database.class.php index b5f58060f4..174402f140 100644 --- a/main/install/i_database.class.php +++ b/main/install/i_database.class.php @@ -12,13 +12,13 @@ class iDatabase extends Database static function select_db($database_name, $connection = null) { - Log::notice(__FUNCTION__ . ' ' . $database_name, Log::get_frame(1)); + Log::notice(__FUNCTION__ . ' ' . $database_name, Log::frame(1)); parent::select_db($database_name, $connection); } static function query($query, $connection = null, $file = null, $line = null) { - Log::notice(__FUNCTION__ . ' ' . $database_name, Log::get_frame(1)); + Log::notice(__FUNCTION__ . ' ' . $database_name, Log::frame(1)); parent::query($query, $connection, $file, $line); } From 8348ea7fe55828bbebb666a664103d4b3dd6bfa1 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Tue, 8 May 2012 17:24:14 +0200 Subject: [PATCH 074/128] #4694 add feedback during installation --- main/inc/lib/log.class.php | 2 +- main/install/i_database.class.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main/inc/lib/log.class.php b/main/inc/lib/log.class.php index 92b0cd1631..64e9350262 100644 --- a/main/inc/lib/log.class.php +++ b/main/inc/lib/log.class.php @@ -85,7 +85,7 @@ class Log array_shift($trace); $trace = reset($trace); $context['file'] = $trace['file']; - $context['file'] = $trace['file']; + $context['line'] = $trace['line']; } $file = $context['file']; $root = realpath(api_get_path(SYS_PATH)); diff --git a/main/install/i_database.class.php b/main/install/i_database.class.php index 174402f140..eb318c020e 100644 --- a/main/install/i_database.class.php +++ b/main/install/i_database.class.php @@ -18,7 +18,7 @@ class iDatabase extends Database static function query($query, $connection = null, $file = null, $line = null) { - Log::notice(__FUNCTION__ . ' ' . $database_name, Log::frame(1)); + Log::notice(__FUNCTION__ . ' ' . $query, Log::frame(1)); parent::query($query, $connection, $file, $line); } From 237957f12a3fd9203ddafce2d4050453118db78d Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Tue, 8 May 2012 17:46:30 +0200 Subject: [PATCH 075/128] All databases (stat, user) are going to use the main DB see #3910 --- main/inc/lib/database.lib.php | 14 ++---------- main/install/update-db-1.8.8-1.9.0.inc.php | 25 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/main/inc/lib/database.lib.php b/main/inc/lib/database.lib.php index 5eec8f7c56..f2942eb063 100644 --- a/main/inc/lib/database.lib.php +++ b/main/inc/lib/database.lib.php @@ -43,17 +43,7 @@ class Database { */ public static function get_statistic_database() { global $_configuration; - return $_configuration['statistics_database']; - } - - /** - * Returns the name of the SCORM database. - * @todo use main_database - * @deprecated - */ - public static function get_scorm_database() { - global $_configuration; - return $_configuration['scorm_database']; + return $_configuration['main_database']; } /** @@ -62,7 +52,7 @@ class Database { */ public static function get_user_personal_database() { global $_configuration; - return $_configuration['user_personal_database']; + return $_configuration['main_database']; } /** diff --git a/main/install/update-db-1.8.8-1.9.0.inc.php b/main/install/update-db-1.8.8-1.9.0.inc.php index 0f982c14af..51eb5c5286 100755 --- a/main/install/update-db-1.8.8-1.9.0.inc.php +++ b/main/install/update-db-1.8.8-1.9.0.inc.php @@ -57,6 +57,7 @@ if (defined('SYSTEM_INSTALLATION')) { $only_test = false; $log = 0; if (defined('SYSTEM_INSTALLATION')) { + if ($singleDbForm) { $dbStatsForm = $dbNameForm; $dbScormForm = $dbNameForm; @@ -132,7 +133,7 @@ if (defined('SYSTEM_INSTALLATION')) { } } - //Moving Stats DB to the main database + //Moving Stats DB to the main DB $stats_table = array( "track_c_browsers", @@ -165,14 +166,30 @@ if (defined('SYSTEM_INSTALLATION')) { if ($dbNameForm != $dbStatsForm) { Database::select_db($dbStatsForm); - foreach($stats_table as $stat_table) { + foreach ($stats_table as $stat_table) { $sql = "ALTER TABLE $dbStatsForm.$stat_table RENAME $dbNameForm.$stat_table"; Database::query($sql); } Database::select_db($dbNameForm); } - - + + //Renaming user tables in the main DB + $user_tables = array( + 'personal_agenda', + 'personal_agenda_repeat', + 'personal_agenda_repeat_not', + 'user_course_category', + ); + + if ($dbNameForm != $dbUserForm) { + Database::select_db($dbUserForm); + foreach ($user_tables as $table) { + $sql = "ALTER TABLE $dbUserForm.$table RENAME $dbNameForm.$table"; + Database::query($sql); + } + Database::select_db($dbNameForm); + } + // Get the user queries list (u_q_list) $u_q_list = get_sql_file_contents('migrate-db-'.$old_file_version.'-'.$new_file_version.'-pre.sql', 'user'); From be42ac122c5cc227d03dcbdc44e3cbefcc28779c Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Tue, 8 May 2012 17:47:25 +0200 Subject: [PATCH 076/128] Minor commenting unused code --- main/inc/lib/course.lib.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/main/inc/lib/course.lib.php b/main/inc/lib/course.lib.php index 19d6a55846..c880cbcf6c 100644 --- a/main/inc/lib/course.lib.php +++ b/main/inc/lib/course.lib.php @@ -434,7 +434,7 @@ class CourseManager { } $status = ($status == STUDENT || $status == COURSEMANAGER) ? $status : STUDENT; - $role_id = ($status == COURSEMANAGER) ? COURSE_ADMIN : NORMAL_COURSE_MEMBER; + //$role_id = ($status == COURSEMANAGER) ? COURSE_ADMIN : NORMAL_COURSE_MEMBER; // A preliminary check whether the user has bben already registered on the platform. if (Database::num_rows(@Database::query("SELECT status FROM ".Database::get_main_table(TABLE_MAIN_USER)." @@ -1661,10 +1661,8 @@ class CourseManager { $table_course = Database::get_main_table(TABLE_MAIN_COURSE); $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER); - $table_course_class = Database::get_main_table(TABLE_MAIN_COURSE_CLASS); - $user_role_table = Database::get_main_table(MAIN_USER_ROLE_TABLE); - $location_table = Database::get_main_table(MAIN_LOCATION_TABLE); - $role_right_location_table = Database::get_main_table(MAIN_ROLE_RIGHT_LOCATION_TABLE); + $table_course_class = Database::get_main_table(TABLE_MAIN_COURSE_CLASS); + $table_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); $table_course_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY); @@ -1691,7 +1689,7 @@ class CourseManager { return; } $this_course = Database::fetch_array($res); - $db_name = $this_course['db_name']; + self::create_database_dump($code); if (!self::is_virtual_course_from_system_code($code)) { // If this is not a virtual course, look for virtual courses that depend on this one, if any @@ -1813,8 +1811,7 @@ class CourseManager { $sql = "DELETE FROM $table_stats_links WHERE links_cours_id = '".$code."'"; Database::query($sql); $sql = "DELETE FROM $table_stats_uploads WHERE upload_cours_id = '".$code."'"; - Database::query($sql); - + Database::query($sql); global $_configuration; if ($_configuration['multiple_access_urls']) { From 57c757dd3744981577829d5adb26c435c052d336 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Tue, 8 May 2012 17:48:45 +0200 Subject: [PATCH 077/128] Adding gradebook_block platform setting + adding c_id in the track_e_default table see #4635 --- main/inc/lib/events.lib.inc.php | 77 ++++++++++++--------- main/install/db_main.sql | 7 +- main/install/db_stats.sql | 1 + main/install/migrate-db-1.8.8-1.9.0-pre.sql | 7 +- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/main/inc/lib/events.lib.inc.php b/main/inc/lib/events.lib.inc.php index 62c7c38592..33b94b6ff0 100644 --- a/main/inc/lib/events.lib.inc.php +++ b/main/inc/lib/events.lib.inc.php @@ -562,7 +562,7 @@ function exercise_attempt_hotspot($exe_id, $question_id, $answer_id, $correct, $ * @param integer User ID (defaults to null) * @param string Course code (defaults to null) */ -function event_system($event_type, $event_value_type, $event_value, $datetime = null, $user_id=null, $course_code=null) { +function event_system($event_type, $event_value_type, $event_value, $datetime = null, $user_id = null, $course_code = null) { global $_user; global $TABLETRACK_DEFAULT; @@ -579,18 +579,25 @@ function event_system($event_type, $event_value_type, $event_value, $datetime = unset($event_value['avatar']); unset($event_value['password']); unset($event_value['lastLogin']); - unset($event_value['picture_uri']); - + unset($event_value['picture_uri']); $event_value = serialize($event_value); } } + $event_value = Database::escape_string($event_value); $user_id = Database::escape_string($user_id); $course_code = Database::escape_string($course_code); + $course_info = api_get_course_info($course_code); + + $course_id = null; + if (!empty($course_info)) { + $course_id = $course_info['real_id']; + } if (!isset($datetime)) { $datetime = api_get_utc_datetime(); } + $datetime = Database::escape_string($datetime); if(!isset($user_id)) { @@ -599,17 +606,19 @@ function event_system($event_type, $event_value_type, $event_value, $datetime = if(!isset($course_code)) { $course_code = ''; } + $sql = "INSERT INTO $TABLETRACK_DEFAULT (default_user_id, default_cours_code, + c_id, default_date, default_event_type, default_value_type, default_value ) - VALUES - ('$user_id.', + VALUES('$user_id.', '$course_code', + '$course_id', '$datetime', '$event_type', '$event_value_type', @@ -617,37 +626,37 @@ function event_system($event_type, $event_value_type, $event_value, $datetime = $res = Database::query($sql); //Sending notifications to users - $send_event_setting = api_get_setting('activate_send_event_by_mail'); - if (!empty($send_event_setting) && $send_event_setting == 'true') { - global $language_file; - - //prepare message - list($message, $subject) = get_event_message_and_subject($event_type); - $mail_body=$message; - if ( is_array($notification_infos) ){ - foreach ($notification_infos as $variable => $value) { - $mail_body = str_replace('%'.$variable.'%',$value,$mail_body); - } - } + $send_event_setting = api_get_setting('activate_send_event_by_mail'); + if (!empty($send_event_setting) && $send_event_setting == 'true') { + global $language_file; + + //prepare message + list($message, $subject) = get_event_message_and_subject($event_type); + $mail_body=$message; + if (is_array($notification_infos)) { + foreach ($notification_infos as $variable => $value) { + $mail_body = str_replace('%'.$variable.'%',$value,$mail_body); + } + } - //prepare mail common variables - if(empty($subject)) { - $subject = $event_type; - } - $mail_subject = '['.api_get_setting('siteName').'] '.$subject; - $sender_name = api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS); - $email_admin = api_get_setting('emailAdministrator'); - $emailfromaddr = api_get_setting('emailAdministrator'); - $emailfromname = api_get_setting('siteName'); - - //Send mail to all subscribed users - $users_arr = get_users_subscribed_to_event($event_type); - foreach ($users_arr as $user) { - $recipient_name = api_get_person_name($user['firstname'], $user['lastname']); - $email = $user['email']; - @api_mail($recipient_name, $email, $mail_subject, $mail_body, $sender_name, $email_admin); + //prepare mail common variables + if(empty($subject)) { + $subject = $event_type; + } + $mail_subject = '['.api_get_setting('siteName').'] '.$subject; + $sender_name = api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS); + $email_admin = api_get_setting('emailAdministrator'); + $emailfromaddr = api_get_setting('emailAdministrator'); + $emailfromname = api_get_setting('siteName'); + + //Send mail to all subscribed users + $users_arr = get_users_subscribed_to_event($event_type); + foreach ($users_arr as $user) { + $recipient_name = api_get_person_name($user['firstname'], $user['lastname']); + $email = $user['email']; + @api_mail($recipient_name, $email, $mail_subject, $mail_body, $sender_name, $email_admin); + } } - } return true; } diff --git a/main/install/db_main.sql b/main/install/db_main.sql index d0e62e1ec4..a886e4f3a9 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -858,7 +858,8 @@ VALUES ('teachers_can_change_grade_model_settings', NULL, 'radio', 'Gradebook', 'true', 'TeachersCanChangeGradeModelSettingsTitle', 'TeachersCanChangeGradeModelSettingsComment', NULL, NULL, 1), ('shibboleth_description', NULL, 'radio', 'Shibboleth', 'false', 'ShibbolethMainActivateTitle', 'ShibbolethMainActivateComment', NULL, NULL, 0), ('facebook_description', NULL, 'radio', 'Facebook', 'false', 'FacebookMainActivateTitle', 'FacebookMainActivateComment', NULL, NULL, 0), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17763','DatabaseVersion','', NULL, NULL, 0); +('gradebook_locking_enabled', NULL, 'radio', 'Gradebook', 'false', 'GradebookEnableLockingTitle', 'GradebookEnableLockingComment', NULL, NULL, 0), +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17769','DatabaseVersion','', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), @@ -1196,7 +1197,9 @@ VALUES ('teachers_can_change_score_settings', 'true', 'Yes'), ('teachers_can_change_score_settings', 'false', 'No'), ('teachers_can_change_grade_model_settings', 'true', 'Yes'), -('teachers_can_change_grade_model_settings', 'false', 'No'); +('teachers_can_change_grade_model_settings', 'false', 'No'), +('gradebook_locking_enabled', 'true', 'Yes'), +('gradebook_locking_enabled', 'false', 'No'); UNLOCK TABLES; /* ('activate_send_event_by_mail', 'true', 'Yes'), diff --git a/main/install/db_stats.sql b/main/install/db_stats.sql index bdbb9b9ee6..7a768b131f 100644 --- a/main/install/db_stats.sql +++ b/main/install/db_stats.sql @@ -85,6 +85,7 @@ CREATE TABLE track_e_default ( default_event_type varchar(20) NOT NULL default '', default_value_type varchar(20) NOT NULL default '', default_value text NOT NULL, + c_id int unsigned default NULL, PRIMARY KEY (default_id) ); diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index ed2ed2a3b9..57f6a43443 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -100,6 +100,10 @@ INSERT INTO settings_current (variable, subkey, type, category, selected_value, INSERT INTO settings_options (variable, value, display_text) VALUES ('teachers_can_change_grade_model_settings', 'true', 'Yes'); INSERT INTO settings_options (variable, value, display_text) VALUES ('teachers_can_change_grade_model_settings', 'false', 'No'); +INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('gradebook_locking_enabled', NULL, 'radio', 'Gradebook', 'false', 'GradebookEnableLockingTitle', 'GradebookEnableLockingComment', NULL, NULL, 0); +INSERT INTO settings_options (variable, value, display_text) VALUES ('gradebook_locking_enabled', 'true', 'Yes'); +INSERT INTO settings_options (variable, value, display_text) VALUES ('gradebook_locking_enabled', 'false', 'No'); + INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('allow_users_to_change_email_with_no_password', NULL, 'radio', 'User', 'false', 'AllowUsersToChangeEmailWithNoPasswordTitle', 'AllowUsersToChangeEmailWithNoPasswordComment', NULL, NULL, 0); INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_users_to_change_email_with_no_password', 'true', 'Yes'); INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_users_to_change_email_with_no_password', 'false', 'No'); @@ -190,7 +194,7 @@ DELETE FROM settings_current WHERE variable = 'use_document_title'; DELETE FROM settings_options WHERE variable = 'use_document_title'; -- Do not move this query -UPDATE settings_current SET selected_value = '1.9.0.17763' WHERE variable = 'chamilo_database_version'; +UPDATE settings_current SET selected_value = '1.9.0.17769' WHERE variable = 'chamilo_database_version'; -- xxSTATSxx ALTER TABLE track_e_exercices ADD COLUMN questions_to_check TEXT NOT NULL DEFAULT ''; @@ -203,6 +207,7 @@ ALTER TABLE stored_values_stack ADD KEY (user_id, sco_id, course_id, sv_key, sta ALTER TABLE stored_values_stack ADD UNIQUE (user_id, sco_id, course_id, sv_key, stack_order); ALTER TABLE track_e_attempt ADD COLUMN filename VARCHAR(255) DEFAULT NULL; +ALTER TABLE track_e_default ADD COLUMN c_id INTEGER DEFAULT NULL; -- xxUSERxx From 905de2cfe6fb474069f31229efe01ec103653584 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Tue, 8 May 2012 18:56:02 +0200 Subject: [PATCH 078/128] Removing scorm calls. Leaving just the table definition (needed when migrating from 1.6 to 1.8). Removing removescormDir() unused function see #4716 --- main/inc/lib/database.constants.inc.php | 2 +- main/inc/lib/database.lib.php | 15 ++------------- main/inc/lib/database.mysqli.lib.php | 12 ------------ main/newscorm/scorm.lib.php | 3 ++- tests/main/inc/lib/database.lib.test.php | 9 +-------- 5 files changed, 6 insertions(+), 35 deletions(-) mode change 100755 => 100644 main/newscorm/scorm.lib.php diff --git a/main/inc/lib/database.constants.inc.php b/main/inc/lib/database.constants.inc.php index 4b30e1acb7..63e51a2ab5 100644 --- a/main/inc/lib/database.constants.inc.php +++ b/main/inc/lib/database.constants.inc.php @@ -143,7 +143,7 @@ define('TABLE_STATISTIC_TRACK_COURSE_RANKING', 'track_course_ranking'); define('TABLE_MAIN_USER_REL_COURSE_VOTE', 'user_rel_course_vote'); -// SCORM database tables +// SCORM database tables this is used only during the migration from 1.6 to 1.8 see update-db-scorm-1.6.x-1.8.0.inc define('TABLE_SCORM_MAIN', 'scorm_main'); define('TABLE_SCORM_SCO_DATA', 'scorm_sco_data'); diff --git a/main/inc/lib/database.lib.php b/main/inc/lib/database.lib.php index f2942eb063..566e25ea89 100644 --- a/main/inc/lib/database.lib.php +++ b/main/inc/lib/database.lib.php @@ -17,6 +17,7 @@ * Constants definition */ require_once 'database.constants.inc.php'; + /** * Database class definition * @package chamilo.database @@ -182,19 +183,7 @@ class Database { } /** - * This generic method returns the correct and complete name of any scorm - * table of which you pass the short name as a parameter. Please, define - * table names as constants in this library and use them instead of directly - * using magic words in your tool code. - * - * @param string $short_table_name, the name of the table - */ - public static function get_scorm_table($short_table_name) { - return self::format_table_name(self::get_scorm_database(), $short_table_name); - } - - /** - * This generic method returns the correct and complete name of any scorm + * This generic method returns the correct and complete name of any user * table of which you pass the short name as a parameter. Please, define * table names as constants in this library and use them instead of directly * using magic words in your tool code. diff --git a/main/inc/lib/database.mysqli.lib.php b/main/inc/lib/database.mysqli.lib.php index 0fce048713..4689b04699 100644 --- a/main/inc/lib/database.mysqli.lib.php +++ b/main/inc/lib/database.mysqli.lib.php @@ -180,18 +180,6 @@ class Database { return self::format_table_name(self::get_statistic_database(), $short_table_name); } - /** - * This generic method returns the correct and complete name of any scorm - * table of which you pass the short name as a parameter. Please, define - * table names as constants in this library and use them instead of directly - * using magic words in your tool code. - * - * @param string $short_table_name, the name of the table - */ - public static function get_scorm_table($short_table_name) { - return self::format_table_name(self::get_scorm_database(), $short_table_name); - } - /** * This generic method returns the correct and complete name of any scorm * table of which you pass the short name as a parameter. Please, define diff --git a/main/newscorm/scorm.lib.php b/main/newscorm/scorm.lib.php old mode 100755 new mode 100644 index 73fb6102db..54c117eedf --- a/main/newscorm/scorm.lib.php +++ b/main/newscorm/scorm.lib.php @@ -18,6 +18,7 @@ * @param string Dir path * @return boolean True on success, false otherwise */ +/* function removescormDir($dir) { global $_course; if(!@$opendir = opendir($dir)) { @@ -61,7 +62,7 @@ function removescormDir($dir) { return false; } return true; -} +}*/ /** * This function removes a directory if it exists diff --git a/tests/main/inc/lib/database.lib.test.php b/tests/main/inc/lib/database.lib.test.php index 4d8222f1d6..a7356d9389 100755 --- a/tests/main/inc/lib/database.lib.test.php +++ b/tests/main/inc/lib/database.lib.test.php @@ -209,14 +209,7 @@ class TestDatabase extends UnitTestCase { $res=$this->dbase->get_scorm_database(); $this->assertTrue(is_string($res)); } - - function testGetScorm_table() { - $short_table_name=''; - $res=$this->dbase->get_scorm_table($short_table_name); - $this->assertTrue(is_string($res)); - $this->assertTrue($res); - } - + function testGetStatisticDatabase() { global $_configuration; $res=$this->dbase->get_statistic_database($_configuration); From 2f86a682cfa0505e53a51c2253857bb34aafa9f7 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Tue, 8 May 2012 14:07:35 -0500 Subject: [PATCH 079/128] Updated license text to better match present reality - relocated a few contributors --- documentation/credits.html | 3 +++ license.txt | 15 ++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) mode change 100755 => 100644 license.txt diff --git a/documentation/credits.html b/documentation/credits.html index 1c72acd4c5..54b55b79b2 100644 --- a/documentation/credits.html +++ b/documentation/credits.html @@ -592,6 +592,8 @@ There are too much translators to list them all. Please check http://translate.c
  • Erik Das (FKS), for bug reports to 1.8.8
  • Marc De Caluwé, for patches to 1.8.8.4
  • Alberto Montes, Contidos Dixitais, for CSS "sport_red" in 1.9
  • +
  • Bart Mollet, Hogeschool Gent, for patches in 1.6 & 1.8
  • +
  • Kristof Van Steenkiste & Sebastien Jacobs (initial Reservation plugin, 2007)
  • All the supporting parents, partners, children, friends, colleagues and sometimes students, of the very special geeks that we are, for their continous support and inspiration
  • @@ -626,6 +628,7 @@ These institutions and companies have either contributed to the Chamilo project
  • Table of contents
    now removed, replaced by learning path
  • +
  • Facultad de Matematicas, UADY (México) (original asynchronous Message plugin, was later dumped)

  • diff --git a/license.txt b/license.txt old mode 100755 new mode 100644 index c77167be32..622b3f7855 --- a/license.txt +++ b/license.txt @@ -1,15 +1,16 @@ -Chamilo - elearning and course management software +Chamilo LMS - elearning and course management software -Copyright (c) 2008-2010 Dokeos Latinoamérica SAC / BeezNest Latino SAC -Copyright (c) 2004-2009 Dokeos SPRL +Copyright (c) 2008-2012 BeezNest Latino SAC, Peru & BeezNest Belgium SPRL, Belgium +Copyright (c) 2012 Université de Genève, Switzerland +Copyright (c) 2010-2012 Université de Grenoble, France +Copyright (c) 2011-2012 CBlue SPRL, Belgium +Copyright (c) Juan Carlos Raña (independent), Spain +Copyright (c) 2004-2009 Dokeos SPRL, Belgium Copyright (c) 2003-2007 Ghent University (UGent) -Copyright (c) 2001 Universite catholique de Louvain (UCL) +Copyright (c) 2001-2004 Universite catholique de Louvain (UCL) Copyright (c) 2003-2008 Vrije Universiteit Brussel (VUB) Copyright (c) 2004-2008 Hoogeschool Gent (HoGent) -Copyright (c) Bart Mollet, Hogeschool Gent -Copyright (c) Facultad de Matematicas, UADY (México) (Message plugin) -Copyright (c) Kristof Van Steenkiste & Sebastien Jacobs (Reservation plugin) For a full list of contributors detaining copyrights over parts of the Chamilo software, see "documentation/credits.html". From f0076330a453839aa62d7aafa81cecb2e595cbff Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Wed, 9 May 2012 09:12:22 +0200 Subject: [PATCH 080/128] #4694 add feedback during installation --- main/inc/lib/log.class.php | 27 ++++- main/install/i_database.class.php | 30 ++++- main/install/update-db-1.8.5-1.8.6.inc.php | 96 +++++++-------- main/install/update-db-1.8.6-1.8.6.1.inc.php | 48 ++++---- .../install/update-db-1.8.6.1-1.8.6.2.inc.php | 78 ++++++------ main/install/update-db-1.8.6.2-1.8.7.inc.php | 6 - main/install/update-db-1.8.7-1.8.8.inc.php | 114 +++++++++--------- main/install/update-db-1.8.8-1.9.0.inc.php | 78 ++++++------ main/install/update-files-1.8.5-1.8.6.inc.php | 10 +- .../update-files-1.8.6.1-1.8.6.2.inc.php | 12 +- 10 files changed, 263 insertions(+), 236 deletions(-) diff --git a/main/inc/lib/log.class.php b/main/inc/lib/log.class.php index 64e9350262..aa5d67214f 100644 --- a/main/inc/lib/log.class.php +++ b/main/inc/lib/log.class.php @@ -2,10 +2,34 @@ use Monolog\Logger; +/** + * Since static constructors do not exist in php the line below serves as a + * substitute. + * + * Log is used by install which do not use autoload at the moment. If it becomes + * the case then the line below may/should be moved to the main autoloading + * function. + */ Log::register_autoload(); /** - * Description of log + * Provides access to the main log - i.e. stderr - and allows to register events. + * It is a facade to the monolog library: + * + * Log::error('message'); + * Log::warning('message'); + * ... + * + * + * Note: + * This class uses a static approach which has the benefit of being simpler but do + * no allow as much freedom as using an object approche. Another approach could be + * + * Chamilo::log()->error('message'); + * Chamilo::log()->warning('message'); + * + * To somewhat alleviate this issue the user can register a different logger if hew + * wants. * * @license see /license.txt * @author Laurent Opprecht for the Univesity of Geneva @@ -92,6 +116,7 @@ class Log $file = str_replace($root, '', $file); $file = trim($file, DIRECTORY_SEPARATOR); $line = $context['line']; + $line = str_pad($line, 4, ' ', STR_PAD_LEFT); $message = "[$file:$line] " . $message; self::logger()->addRecord($level, $message, $context); diff --git a/main/install/i_database.class.php b/main/install/i_database.class.php index eb318c020e..384fcc476c 100644 --- a/main/install/i_database.class.php +++ b/main/install/i_database.class.php @@ -1,24 +1,42 @@ + * @license see /license.txt + * @author Laurent Opprecht for the Univesity of Geneva */ class iDatabase extends Database { + private static $is_logging = true; + + static function is_logging() + { + return self::$is_logging; + } + + static function set_is_logging($value) + { + self::$is_logging = $value; + } + static function select_db($database_name, $connection = null) { - Log::notice(__FUNCTION__ . ' ' . $database_name, Log::frame(1)); + if (self::is_logging()) { + Log::notice(__FUNCTION__ . ' ' . $database_name, Log::frame(1)); + } parent::select_db($database_name, $connection); } static function query($query, $connection = null, $file = null, $line = null) { - Log::notice(__FUNCTION__ . ' ' . $query, Log::frame(1)); + if (self::is_logging()) { + Log::notice(__FUNCTION__ . ' ' . $query, Log::frame(1)); + } parent::query($query, $connection, $file, $line); } diff --git a/main/install/update-db-1.8.5-1.8.6.inc.php b/main/install/update-db-1.8.5-1.8.6.inc.php index e5602714bb..87775657fb 100644 --- a/main/install/update-db-1.8.5-1.8.6.inc.php +++ b/main/install/update-db-1.8.5-1.8.6.inc.php @@ -87,12 +87,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbNameForm,$query)"); + Log::notice("iDatabase::query($dbNameForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbNameForm, executed: $query"); } @@ -107,15 +107,15 @@ if (defined('SYSTEM_INSTALLATION')) { // Filling the access_url_rel_user table with access_url_id by default = 1 $query = "SELECT user_id FROM $dbNameForm.user"; - $result_users = Database::query($query); - while ($row = Database::fetch_array($result_users, 'NUM')) { + $result_users = iDatabase::query($query); + while ($row = iDatabase::fetch_array($result_users, 'NUM')) { $user_id = $row[0]; $sql = "INSERT INTO $dbNameForm.access_url_rel_user SET user_id=$user_id, access_url_id=1"; - $res = Database::query($sql); + $res = iDatabase::query($sql); //Updating user image $query = "SELECT picture_uri FROM $dbNameForm.user WHERE user_id=$user_id"; - $res = Database::query($query); - $picture_uri = Database::fetch_array($res, 'NUM'); + $res = iDatabase::query($query); + $picture_uri = iDatabase::fetch_array($res, 'NUM'); $file = $picture_uri[0]; $dir = api_get_path(SYS_CODE_PATH).'upload/users/'; $image_repository = file_exists($dir.$file) ? $dir.$file : $dir.$user_id.'/'.$file; @@ -167,10 +167,10 @@ if (defined('SYSTEM_INSTALLATION')) { } // Filling the access_url_rel_session table with access_url_id by default = 1 $query = "SELECT id FROM $dbNameForm.session"; - $result = Database::query($query); - while ($row = Database::fetch_array($result, 'NUM')) { + $result = iDatabase::query($query); + while ($row = iDatabase::fetch_array($result, 'NUM')) { $sql = "INSERT INTO $dbNameForm.access_url_rel_session SET session_id=".$row[0].", access_url_id=1"; - $res = Database::query($sql); + $res = iDatabase::query($sql); } // Since the parser of the migration DB does not work for this kind of inserts (HTML) we move it here @@ -209,7 +209,7 @@ if (defined('SYSTEM_INSTALLATION')) {

    \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); /* $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -259,7 +259,7 @@ if (defined('SYSTEM_INSTALLATION')) { \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); */ $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -299,7 +299,7 @@ if (defined('SYSTEM_INSTALLATION')) { \'); '; - $res = Database::query($sql); + $res = iDatabase::query($sql); $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES (\'TemplateTitleLeftList\', \'TemplateTitleListLeftListDescription\', \'leftlist.gif\', \' @@ -337,7 +337,7 @@ if (defined('SYSTEM_INSTALLATION')) {

    \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES (\'TemplateTitleLeftRightList\', \'TemplateTitleLeftRightListDescription\', \'leftrightlist.gif\', \' @@ -389,7 +389,7 @@ if (defined('SYSTEM_INSTALLATION')) { \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES (\'TemplateTitleRightList\', \'TemplateTitleRightListDescription\', \'rightlist.gif\', \' @@ -428,7 +428,7 @@ if (defined('SYSTEM_INSTALLATION')) {

    \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); /* $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -455,7 +455,7 @@ if (defined('SYSTEM_INSTALLATION')) { \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); */ $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -491,7 +491,7 @@ if (defined('SYSTEM_INSTALLATION')) { \'); '; - $res = Database::query($sql); + $res = iDatabase::query($sql); $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES (\'TemplateTitleDesc\', \'TemplateTitleCheckListDescription\', \'description.gif\', \' @@ -520,7 +520,7 @@ if (defined('SYSTEM_INSTALLATION')) { \'); '; - $res = Database::query($sql); + $res = iDatabase::query($sql); /* $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -561,7 +561,7 @@ if (defined('SYSTEM_INSTALLATION')) {

    \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); */ $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -627,7 +627,7 @@ if (defined('SYSTEM_INSTALLATION')) {

    \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); /* $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -670,7 +670,7 @@ if (defined('SYSTEM_INSTALLATION')) { \'); '; - $res = Database::query($sql); + $res = iDatabase::query($sql); */ $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -737,7 +737,7 @@ if (defined('SYSTEM_INSTALLATION')) { \'); '; - $res = Database::query($sql); + $res = iDatabase::query($sql); /* $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -771,7 +771,7 @@ if (defined('SYSTEM_INSTALLATION')) {

    \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); */ $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES @@ -838,7 +838,7 @@ if (defined('SYSTEM_INSTALLATION')) {
    \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES (\'TemplateTitleAudio\', \'TemplateTitleAudioDescription\', \'audiocomment.gif\', \' @@ -873,7 +873,7 @@ if (defined('SYSTEM_INSTALLATION')) {

    \');'; - $res = Database::query($sql); + $res = iDatabase::query($sql); $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES (\'TemplateTitleVideo\', \'TemplateTitleVideoDescription\', \'video.gif\', \' @@ -935,7 +935,7 @@ if (defined('SYSTEM_INSTALLATION')) { \'); '; - $res = Database::query($sql); + $res = iDatabase::query($sql); $sql = 'INSERT INTO '.$dbNameForm.'.system_template (title, comment, image, content) VALUES (\'TemplateTitleFlash\', \'TemplateTitleFlashDescription\', \'flash.gif\', \' @@ -959,11 +959,11 @@ if (defined('SYSTEM_INSTALLATION')) { \'); '; - $res = Database::query($sql); + $res = iDatabase::query($sql); // Check if course_module exists, as it was not installed in Dokeos 1.8.5 because of a broken query, and $sql = 'INSERT it if necessary $query = "SELECT * FROM $dbNameForm.course_module"; - $result = Database::query($query); + $result = iDatabase::query($query); if ($result === false) { //the course_module table doesn't exist, create it $sql = "CREATE TABLE $dbNameForm.course_module ( @@ -977,7 +977,7 @@ if (defined('SYSTEM_INSTALLATION')) { PRIMARY KEY (id) ) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); if ($result !== false) { $sql = "INSERT INTO $dbNameForm.course_module (name, link, image, `row`,`column`, position) VALUES ('calendar_event','calendar/agenda.php','agenda.gif',1,1,'basic'), @@ -1008,7 +1008,7 @@ if (defined('SYSTEM_INSTALLATION')) { ('gradebook','gradebook/index.php','gradebook.gif',2,2,'basic'), ('glossary','glossary/index.php','glossary.gif',2,1,'basic'), ('notebook','notebook/index.php','notebook.gif',2,1,'basic')"; - $res = Database::query($sql); + $res = iDatabase::query($sql); } } @@ -1026,12 +1026,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbStatsForm,$dblist)) { Log::error('Database '.$dbStatsForm.' was not found, skipping'); } else { - Database::select_db($dbStatsForm); + iDatabase::select_db($dbStatsForm); foreach ($s_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbStatsForm,$query)"); + Log::notice("iDatabase::query($dbStatsForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbStatsForm, executed: $query"); } @@ -1052,13 +1052,13 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbUserForm,$dblist)) { Log::error('Database '.$dbUserForm.' was not found, skipping'); } else { - Database::select_db($dbUserForm); + iDatabase::select_db($dbUserForm); foreach ($u_q_list as $query) { if ($only_test) { - error_log("Database::query($dbUserForm,$query)"); + error_log("iDatabase::query($dbUserForm,$query)"); error_log("In $dbUserForm, executed: $query"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); } } } @@ -1081,15 +1081,15 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { error_log('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); + iDatabase::select_db($dbNameForm); + $res = iDatabase::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); if ($res === false) { die('Error while querying the courses list in update_db-1.8.5-1.8.6.inc.php'); } - if (Database::num_rows($res) > 0) { + if (iDatabase::num_rows($res) > 0) { $i = 0; $list = array(); - while ($row = Database::fetch_array($res)) { + while ($row = iDatabase::fetch_array($res)) { $list[] = $row; $i++; } @@ -1100,7 +1100,7 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (!$singleDbForm) { //otherwise just use the main one - Database::select_db($row_course['db_name']); + iDatabase::select_db($row_course['db_name']); } Log::notice('Course db ' . $row_course['db_name']); @@ -1110,9 +1110,9 @@ if (defined('SYSTEM_INSTALLATION')) { } if ($only_test) { - Log::notice("Database::query(".$row_course['db_name'].",$query)"); + Log::notice("iDatabase::query(".$row_course['db_name'].",$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In ".$row_course['db_name'].", executed: $query"); } @@ -1128,11 +1128,11 @@ if (defined('SYSTEM_INSTALLATION')) { } // Shared documents folder $query = "INSERT INTO $t_d (path,title,filetype,size) VALUES ('/shared_folder','".get_lang('SharedDocumentsDirectory')."','folder','0')"; - $myres = Database::query($query); + $myres = iDatabase::query($query); if ($myres !== false) { - $doc_id = Database::insert_id(); + $doc_id = iDatabase::insert_id(); $query = "INSERT INTO $t_ip (tool,insert_user_id,insert_date,lastedit_date,ref,lastedit_type,lastedit_user_id,to_group_id,to_user_id,visibility) VALUES ('document',1,NOW(),NOW(),$doc_id,'FolderAdded',1,0,NULL,1)"; - $myres = Database::query($query); + $myres = iDatabase::query($query); } } } diff --git a/main/install/update-db-1.8.6-1.8.6.1.inc.php b/main/install/update-db-1.8.6-1.8.6.1.inc.php index 8f8b859d67..944915dc28 100644 --- a/main/install/update-db-1.8.6-1.8.6.1.inc.php +++ b/main/install/update-db-1.8.6-1.8.6.1.inc.php @@ -87,12 +87,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm,$dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); foreach($m_q_list as $query) { if ($only_test){ - Log::notice("Database::query($dbNameForm,$query)"); + Log::notice("iDatabase::query($dbNameForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbNameForm, executed: $query"); } @@ -116,12 +116,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbStatsForm,$dblist)) { Log::error('Database '.$dbStatsForm.' was not found, skipping'); } else { - Database::select_db($dbStatsForm); + iDatabase::select_db($dbStatsForm); foreach ($s_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbStatsForm,$query)"); + Log::notice("iDatabase::query($dbStatsForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbStatsForm, executed: $query"); } @@ -142,13 +142,13 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbUserForm, $dblist)) { Log::error('Database '.$dbUserForm.' was not found, skipping'); } else { - Database::select_db($dbUserForm); + iDatabase::select_db($dbUserForm); foreach ($u_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbUserForm,$query)"); + Log::notice("iDatabase::query($dbUserForm,$query)"); Log::notice("In $dbUserForm, executed: $query"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); } } } @@ -171,15 +171,15 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); + iDatabase::select_db($dbNameForm); + $res = iDatabase::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); if ($res === false) { die('Error while querying the courses list in update_db-1.8.6-1.8.6.1.inc.php'); } - if (Database::num_rows($res) > 0) { + if (iDatabase::num_rows($res) > 0) { $i = 0; $list = array(); - while ($row = Database::fetch_array($res)) { + while ($row = iDatabase::fetch_array($res)) { $list[] = $row; $i++; } @@ -190,7 +190,7 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (!$singleDbForm) { //otherwise just use the main one - Database::select_db($row_course['db_name']); + iDatabase::select_db($row_course['db_name']); } Log::notice('Course db ' . $row_course['db_name']); @@ -200,9 +200,9 @@ if (defined('SYSTEM_INSTALLATION')) { } if ($only_test) { - Log::notice("Database::query(".$row_course['db_name'].",$query)"); + Log::notice("iDatabase::query(".$row_course['db_name'].",$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In ".$row_course['db_name'].", executed: $query"); } @@ -219,11 +219,11 @@ if (defined('SYSTEM_INSTALLATION')) { // Update correct page_id to wiki table, actually only store 0 $query = "SELECT id, reflink FROM $t_wiki"; - $res_page = Database::query($query); + $res_page = iDatabase::query($query); $wiki_id = $reflink = array(); - if (Database::num_rows($res_page) > 0) { - while ($row_page = Database::fetch_row($res_page)) { + if (iDatabase::num_rows($res_page) > 0) { + while ($row_page = iDatabase::fetch_row($res_page)) { $wiki_id[] = $row_page[0]; $reflink[] = $row_page[1]; } @@ -236,19 +236,19 @@ if (defined('SYSTEM_INSTALLATION')) { foreach ($wiki_id as $key => $wiki_page) { $pag_id = $reflink_flip[$reflink[$key]]; $sql= "UPDATE $t_wiki SET page_id='".($pag_id + 1)."' WHERE id = '$wiki_page'"; - $res_update = Database::query($sql); + $res_update = iDatabase::query($sql); } } // Insert page_id into wiki_conf table, actually this table is empty $query = "SELECT DISTINCT page_id FROM $t_wiki ORDER BY page_id"; - $myres_wiki = Database::query($query); + $myres_wiki = iDatabase::query($query); - if (Database::num_rows($myres_wiki) > 0) { - while ($row_wiki = Database::fetch_row($myres_wiki)) { + if (iDatabase::num_rows($myres_wiki) > 0) { + while ($row_wiki = iDatabase::fetch_row($myres_wiki)) { $page_id = $row_wiki[0]; $query = "INSERT INTO ".$t_wiki_conf." (page_id, task, feedback1, feedback2, feedback3, fprogress1, fprogress2, fprogress3) VALUES ('".$page_id."','','','','','','','')"; - $myres_wiki_conf = Database::query($query); + $myres_wiki_conf = iDatabase::query($query); } } diff --git a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php index 64d0d958df..85b501309c 100644 --- a/main/install/update-db-1.8.6.1-1.8.6.2.inc.php +++ b/main/install/update-db-1.8.6.1-1.8.6.2.inc.php @@ -87,12 +87,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm,$dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbNameForm,$query)"); + Log::notice("iDatabase::query($dbNameForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbNameForm, executed: $query"); } @@ -110,21 +110,21 @@ if (defined('SYSTEM_INSTALLATION')) { FROM session_rel_course ORDER BY id_session, course_code"; - $res = Database::query($sql); + $res = iDatabase::query($sql); if ($res === false) { - Log::error('Could not query session course coaches table: '.Database::error()); + Log::error('Could not query session course coaches table: '.iDatabase::error()); } else { // For each coach found, add him as a course coach in the // session_rel_course_rel_user table - while ($row = Database::fetch_array($res)) { + while ($row = iDatabase::fetch_array($res)) { // Check whether coach is a student $sql = "SELECT 1 FROM session_rel_course_rel_user WHERE id_session='{$row[id_session]}' AND course_code='{$row[course_code]}' AND id_user='{$row[id_coach]}'"; - $rs = Database::query($sql); + $rs = iDatabase::query($sql); - if (Database::num_rows($rs) > 0) { + if (iDatabase::num_rows($rs) > 0) { $sql_upd = "UPDATE session_rel_course_rel_user SET status=2 WHERE id_session='{$row[id_session]}' AND course_code='{$row[course_code]}' AND id_user='{$row[id_coach]}'"; } else { @@ -132,10 +132,10 @@ if (defined('SYSTEM_INSTALLATION')) { VALUES ('{$row[id_session]}','{$row[course_code]}','{$row[id_coach]}',2)"; } - $rs_coachs = Database::query($sql_ins); + $rs_coachs = iDatabase::query($sql_ins); if ($rs_coachs === false) { - Log::error('Could not move course coach to new table: '.Database::error()); + Log::error('Could not move course coach to new table: '.iDatabase::error()); } } @@ -144,34 +144,34 @@ if (defined('SYSTEM_INSTALLATION')) { // Remove duplicated rows for 'show_tutor_data' AND 'show_teacher_data' into settings_current table $sql = "SELECT id FROM settings_current WHERE variable='show_tutor_data' ORDER BY id"; - $rs_chk_id1 = Database::query($sql); + $rs_chk_id1 = iDatabase::query($sql); if ($rs_chk_id1 === false) { - Log::error('Could not query settings_current ids table: '.Database::error()); + Log::error('Could not query settings_current ids table: '.iDatabase::error()); } else { $i = 1; - while ($row_id1 = Database::fetch_array($rs_chk_id1)) { + while ($row_id1 = iDatabase::fetch_array($rs_chk_id1)) { $id = $row_id1['id']; if ($i > 1) { $sql_del = "DELETE FROM settings_current WHERE id = '$id'"; - Database::query($sql_del); + iDatabase::query($sql_del); } $i++; } } $sql = "SELECT id FROM settings_current WHERE variable='show_teacher_data' ORDER BY id"; - $rs_chk_id2 = Database::query($sql); + $rs_chk_id2 = iDatabase::query($sql); if ($rs_chk_id2 === false) { - Log::error('Could not query settings_current ids table: '.Database::error()); + Log::error('Could not query settings_current ids table: '.iDatabase::error()); } else { $i = 1; - while ($row_id2 = Database::fetch_array($rs_chk_id2)) { + while ($row_id2 = iDatabase::fetch_array($rs_chk_id2)) { $id = $row_id2['id']; if ($i > 1) { $sql_del = "DELETE FROM settings_current WHERE id = '$id'"; - Database::query($sql_del); + iDatabase::query($sql_del); } $i++; } @@ -192,12 +192,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm,$dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbNameForm,$query)"); + Log::notice("iDatabase::query($dbNameForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbNameForm, executed: $query"); } @@ -220,12 +220,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbStatsForm, $dblist)) { Log::error('Database '.$dbStatsForm.' was not found, skipping'); } else { - Database::select_db($dbStatsForm); + iDatabase::select_db($dbStatsForm); foreach ($s_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbStatsForm,$query)"); + Log::notice("iDatabase::query($dbStatsForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbStatsForm, executed: $query"); } @@ -246,13 +246,13 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbUserForm,$dblist)) { Log::error('Database '.$dbUserForm.' was not found, skipping'); } else { - Database::select_db($dbUserForm); + iDatabase::select_db($dbUserForm); foreach ($u_q_list as $query) { if ($only_test){ - Log::notice("Database::query($dbUserForm,$query)"); + Log::notice("iDatabase::query($dbUserForm,$query)"); Log::notice("In $dbUserForm, executed: $query"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); } } } @@ -275,15 +275,15 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); + iDatabase::select_db($dbNameForm); + $res = iDatabase::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); if ($res === false) { die('Error while querying the courses list in update_db-1.8.6.1-1.8.6.2.inc.php'); } - if (Database::num_rows($res) > 0) { + if (iDatabase::num_rows($res) > 0) { $i = 0; $list = array(); - while ($row = Database::fetch_array($res)) { + while ($row = iDatabase::fetch_array($res)) { $list[] = $row; $i++; } @@ -294,7 +294,7 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (!$singleDbForm) { //otherwise just use the main one - Database::select_db($row_course['db_name']); + iDatabase::select_db($row_course['db_name']); } Log::notice('Course db ' . $row_course['db_name']); @@ -304,9 +304,9 @@ if (defined('SYSTEM_INSTALLATION')) { } if ($only_test) { - Log::error("Database::query(".$row_course['db_name'].",$query)"); + Log::error("iDatabase::query(".$row_course['db_name'].",$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::error("In ".$row_course['db_name'].", executed: $query"); } @@ -323,16 +323,16 @@ if (defined('SYSTEM_INSTALLATION')) { // Get all ids and update description_type field with them from course_description table $sql_sel = "SELECT id FROM $t_course_description"; - $rs_sel = Database::query($sql_sel); + $rs_sel = iDatabase::query($sql_sel); if ($rs_sel === false) { - Log::error('Could not query course_description ids table: '.Database::error()); + Log::error('Could not query course_description ids table: '.iDatabase::error()); } else { - if (Database::num_rows($rs_sel) > 0) { - while ($row_ids = Database::fetch_array($rs_sel)) { + if (iDatabase::num_rows($rs_sel) > 0) { + while ($row_ids = iDatabase::fetch_array($rs_sel)) { $description_id = $row_ids['id']; $sql_upd = "UPDATE $t_course_description SET description_type='$description_id' WHERE id='$description_id'"; - Database::query($sql_upd); + iDatabase::query($sql_upd); } } } diff --git a/main/install/update-db-1.8.6.2-1.8.7.inc.php b/main/install/update-db-1.8.6.2-1.8.7.inc.php index 2221eee3fa..f6971c139b 100644 --- a/main/install/update-db-1.8.6.2-1.8.7.inc.php +++ b/main/install/update-db-1.8.6.2-1.8.7.inc.php @@ -254,7 +254,6 @@ if (defined('SYSTEM_INSTALLATION')) { Log::error('Database ' . $dbStatsForm . ' was not found, skipping'); } else { iDatabase::select_db($dbStatsForm); - Log::notice('Database: statistics'); foreach ($s_q_list as $query) { if ($only_test) { @@ -272,14 +271,12 @@ if (defined('SYSTEM_INSTALLATION')) { $tables = iDatabase::get_tables($dbStatsForm); foreach ($tables as $table) { $query = "ALTER TABLE `" . $table . "` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"; - Log::notice('Database: statistics, Table: '. $table); $res = iDatabase::query($query); if ($res === false) { Log::error('Error in ' . $query . ': ' . iDatabase::error()); } } $query = "ALTER DATABASE `" . $dbStatsForm . "` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"; - Log::notice('Database: statistics - change default char set'); $res = iDatabase::query($query); if ($res === false) { Log::error('Error in ' . $query . ': ' . iDatabase::error()); @@ -301,7 +298,6 @@ if (defined('SYSTEM_INSTALLATION')) { //getting the type question id $sql_question = "SELECT type FROM $my_course_db.quiz_question where id = $question_id"; - Log::notice('Database: '. $my_course_db); $res_question = iDatabase::query($sql_question); $row = iDatabase::fetch_array($res_question); $type = $row['type']; @@ -339,7 +335,6 @@ if (defined('SYSTEM_INSTALLATION')) { Log::error('Database ' . $dbUserForm . ' was not found, skipping'); } else { iDatabase::select_db($dbUserForm); - Log::notice('Database: user'); foreach ($u_q_list as $query) { if ($only_test) { Log::notice("Database::query($dbUserForm,$query)"); @@ -406,7 +401,6 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one iDatabase::select_db($row_course['db_name']); } - Log::notice('Course db ' . $row_course['db_name']); foreach ($c_q_list as $query) { if ($singleDbForm) { diff --git a/main/install/update-db-1.8.7-1.8.8.inc.php b/main/install/update-db-1.8.7-1.8.8.inc.php index b02accea3b..25ef85f6be 100644 --- a/main/install/update-db-1.8.7-1.8.8.inc.php +++ b/main/install/update-db-1.8.7-1.8.8.inc.php @@ -87,17 +87,17 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); foreach ($m_q_list as $query){ if ($only_test) { - Log::notice("Database::query($dbNameForm,$query)"); + Log::notice("iDatabase::query($dbNameForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbNameForm, executed: $query"); } if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in '.$query.': '.iDatabase::error()); } } } @@ -116,12 +116,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm,$dblist)) { error_log('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); foreach ($m_q_list as $query) { if ($only_test) { - error_log("Database::query($dbNameForm,$query)"); + error_log("iDatabase::query($dbNameForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { error_log("In $dbNameForm, executed: $query"); } @@ -144,18 +144,18 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbStatsForm, $dblist)){ Log::error('Database '.$dbStatsForm.' was not found, skipping'); } else { - Database::select_db($dbStatsForm); + iDatabase::select_db($dbStatsForm); foreach ($s_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbStatsForm,$query)"); + Log::notice("iDatabase::query($dbStatsForm,$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In $dbStatsForm, executed: $query"); } if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in '.$query.': '.iDatabase::error()); } } } @@ -177,15 +177,15 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbUserForm,$dblist)) { Log::error('Database '.$dbUserForm.' was not found, skipping'); } else { - Database::select_db($dbUserForm); + iDatabase::select_db($dbUserForm); foreach ($u_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbUserForm,$query)"); + Log::notice("iDatabase::query($dbUserForm,$query)"); Log::notice("In $dbUserForm, executed: $query"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in '.$query.': '.iDatabase::error()); } } } @@ -208,15 +208,15 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif(!in_array($dbNameForm, $dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); + iDatabase::select_db($dbNameForm); + $res = iDatabase::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); if ($res === false) { die('Error while querying the courses list in update_db-1.8.6.2-1.8.7.inc.php'); } - if (Database::num_rows($res) > 0) { + if (iDatabase::num_rows($res) > 0) { $i = 0; $list = array(); - while ($row = Database::fetch_array($res)) { + while ($row = iDatabase::fetch_array($res)) { $list[] = $row; $i++; } @@ -227,7 +227,7 @@ if (defined('SYSTEM_INSTALLATION')) { * without a database name */ if (!$singleDbForm) { // otherwise just use the main one - Database::select_db($row_course['db_name']); + iDatabase::select_db($row_course['db_name']); } Log::notice('Course db ' . $row_course['db_name']); @@ -237,14 +237,14 @@ if (defined('SYSTEM_INSTALLATION')) { } if ($only_test) { - Log::notice("Database::query(".$row_course['db_name'].",$query)"); + Log::notice("iDatabase::query(".$row_course['db_name'].",$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In ".$row_course['db_name'].", executed: $query"); } if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in '.$query.': '.iDatabase::error()); } } } @@ -264,35 +264,35 @@ if (defined('SYSTEM_INSTALLATION')) { $query = "SELECT DISTINCT path as exercise_id, lp_item_id, lp_view_id, user_id, v.lp_id FROM $table_lp_item_view iv INNER JOIN $table_lp_view v ON v.id = iv.lp_view_id INNER JOIN $table_lp_item i ON i.id = lp_item_id WHERE item_type = 'quiz'"; - $result = Database::query($query); + $result = iDatabase::query($query); - if (Database::num_rows($result) > 0) { - while ($row = Database::fetch_array($result,'ASSOC')) { + if (iDatabase::num_rows($result) > 0) { + while ($row = iDatabase::fetch_array($result,'ASSOC')) { $sql = "SELECT exe_id FROM $dbNameForm.track_e_exercices WHERE exe_user_id = {$row['user_id']} AND exe_cours_id = '{$row_course['code']}' AND exe_exo_id = {$row['exercise_id']} AND orig_lp_id = {$row['lp_id']} AND orig_lp_item_id = {$row['lp_item_id']} "; - $sub_result = Database::query($sql); + $sub_result = iDatabase::query($sql); $exe_list = array(); - while ($sub_row = Database::fetch_array($sub_result,'ASSOC')) { + while ($sub_row = iDatabase::fetch_array($sub_result,'ASSOC')) { $exe_list[] = $sub_row['exe_id']; } $sql = "SELECT iv.id, iv.view_count FROM $table_lp_item_view iv INNER JOIN $table_lp_view v ON v.id = iv.lp_view_id INNER JOIN $table_lp_item i ON i.id = lp_item_id WHERE item_type = 'quiz' AND user_id = {$row['user_id']} AND path = {$row['exercise_id']} "; - $sub_result = Database::query($sql); + $sub_result = iDatabase::query($sql); $lp_item_view_id_list = array(); - while ($sub_row = Database::fetch_array($sub_result,'ASSOC')) { + while ($sub_row = iDatabase::fetch_array($sub_result,'ASSOC')) { $lp_item_view_id_list[] = $sub_row['id']; } $i = 0; foreach($exe_list as $exe_id) { $lp_item_view_id = $lp_item_view_id_list[$i]; $update = "UPDATE $dbNameForm.track_e_exercices SET orig_lp_item_view_id = '$lp_item_view_id' WHERE exe_id = $exe_id "; - Database::query($update); + iDatabase::query($update); $i++; } } @@ -303,49 +303,49 @@ if (defined('SYSTEM_INSTALLATION')) { //Adding notifications options $sql = "INSERT INTO $dbNameForm.user_field (field_type, field_variable, field_display_text, field_visible, field_changeable, field_default_value) values (4, 'mail_notify_invitation', 'MailNotifyInvitation',1,1,'1') "; - $result = Database::query($sql); - $id = Database::insert_id(); + $result = iDatabase::query($sql); + $id = iDatabase::insert_id(); $sql = "INSERT INTO $dbNameForm.user_field_options (field_id, option_value, option_display_text, option_order) values ($id, '1', 'AtOnce',1) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); $sql = "INSERT INTO $dbNameForm.user_field_options (field_id, option_value, option_display_text, option_order) values ($id, '8', 'Daily',2) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); $sql = "INSERT INTO $dbNameForm.user_field_options (field_id, option_value, option_display_text, option_order) values ($id, '0', 'No',3) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); $sql = "INSERT INTO $dbNameForm.user_field (field_type, field_variable, field_display_text, field_visible, field_changeable, field_default_value) values (4, 'mail_notify_message', 'MailNotifyMessage',1,1,'1')"; - $result = Database::query($sql); - $id = Database::insert_id(); + $result = iDatabase::query($sql); + $id = iDatabase::insert_id(); $sql = "INSERT INTO $dbNameForm.user_field_options (field_id, option_value, option_display_text, option_order) values ($id, '1', 'AtOnce',1) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); $sql = "INSERT INTO $dbNameForm.user_field_options (field_id, option_value, option_display_text, option_order) values ($id, '8', 'Daily',2) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); $sql = "INSERT INTO $dbNameForm.user_field_options (field_id, option_value, option_display_text, option_order) values ($id, '0', 'No',3) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); $sql = "INSERT INTO $dbNameForm.user_field (field_type, field_variable, field_display_text, field_visible, field_changeable, field_default_value) values (4, 'mail_notify_group_message','MailNotifyGroupMessage',1,1,'1') "; - $result = Database::query($sql); - $id = Database::insert_id(); + $result = iDatabase::query($sql); + $id = iDatabase::insert_id(); $sql = "INSERT INTO $dbNameForm.user_field_options (field_id, option_value, option_display_text, option_order) values ($id, '1', 'AtOnce',1) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); $sql = "INSERT INTO $dbNameForm.user_field_options (field_id, option_value, option_display_text, option_order) values ($id, '8', 'Daily',2) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); $sql = "INSERT INTO $dbNameForm.user_field_options (field_id, option_value, option_display_text, option_order) values ($id, '0', 'No',3) "; - $result = Database::query($sql); + $result = iDatabase::query($sql); //Fixing table access_url_rel_course if the platform have courses that were created in Dok€os 1.8.5 if (!isset($_configuration['multiple_access_urls']) || $_configuration['multiple_access_urls'] == false) { $sql = "SELECT code FROM $dbNameForm.course"; - $result = Database::query($sql); - while ($row = Database::fetch_array($result)) { + $result = iDatabase::query($sql); + while ($row = iDatabase::fetch_array($result)) { //Adding course to default URL just in case - $sql = "INSERT INTO $dbNameForm.access_url_rel_course SET course_code = '".Database::escape_string($row['code'])."', access_url_id = '1' "; - Database::query($sql); + $sql = "INSERT INTO $dbNameForm.access_url_rel_course SET course_code = '".iDatabase::escape_string($row['code'])."', access_url_id = '1' "; + iDatabase::query($sql); } } } @@ -366,12 +366,12 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); + iDatabase::select_db($dbNameForm); + $res = iDatabase::query("SELECT code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL"); if ($res === false) { die('Error while querying the courses list in update_db-1.8.7-1.8.8.inc.php'); } - if (Database::num_rows($res) > 0) { + if (iDatabase::num_rows($res) > 0) { $i = 0; - while ($row = Database::fetch_array($res)) { + while ($row = iDatabase::fetch_array($res)) { $list[] = $row; $i++; } @@ -383,7 +383,7 @@ if (defined('SYSTEM_INSTALLATION')) { if ($singleDbForm) { $prefix_course = $prefix.$row['db_name']."_"; } else { - Database::select_db($row['db_name']); + iDatabase::select_db($row['db_name']); } foreach($c_q_list as $query) { @@ -391,9 +391,9 @@ if (defined('SYSTEM_INSTALLATION')) { $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix$2$3", $query); } if ($only_test) { - Log::notice("Database::query(".$row['db_name'].",$query)"); + Log::notice("iDatabase::query(".$row['db_name'].",$query)"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($log) { Log::notice("In ".$row['db_name'].", executed: $query"); } diff --git a/main/install/update-db-1.8.8-1.9.0.inc.php b/main/install/update-db-1.8.8-1.9.0.inc.php index f2e20f59f7..5c3ac9530d 100755 --- a/main/install/update-db-1.8.8-1.9.0.inc.php +++ b/main/install/update-db-1.8.8-1.9.0.inc.php @@ -56,7 +56,6 @@ if (defined('SYSTEM_INSTALLATION')) { // If this script has been included by index.php, not update_courses.php, so // that we want to change the main databases as well... $only_test = false; - $log = 0; if (defined('SYSTEM_INSTALLATION')) { if ($singleDbForm) { $dbStatsForm = $dbNameForm; @@ -85,17 +84,14 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbNameForm, $dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); foreach ($m_q_list as $query){ if ($only_test) { - Log::notice("Database::query($dbNameForm,$query)"); + Log::notice("iDatabase::query($dbNameForm,$query)"); } else { - $res = Database::query($query); - if ($log) { - Log::notice("In $dbNameForm, executed: $query"); - } + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in '.$query.': '.iDatabase::error()); } } } @@ -115,18 +111,15 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbStatsForm, $dblist)){ Log::error('Database '.$dbStatsForm.' was not found, skipping'); } else { - Database::select_db($dbStatsForm); + iDatabase::select_db($dbStatsForm); foreach ($s_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbStatsForm,$query)"); + Log::notice("iDatabase::query($dbStatsForm,$query)"); } else { - $res = Database::query($query); - if ($log) { - Log::notice("In $dbStatsForm, executed: $query"); - } + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in '.$query.': '.iDatabase::error()); } } } @@ -165,12 +158,12 @@ if (defined('SYSTEM_INSTALLATION')) { ); if ($dbNameForm != $dbStatsForm) { - Database::select_db($dbStatsForm); + iDatabase::select_db($dbStatsForm); foreach($stats_table as $stat_table) { $sql = "ALTER TABLE $dbStatsForm.$stat_table RENAME $dbNameForm.$stat_table"; - Database::query($sql); + iDatabase::query($sql); } - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); } @@ -188,15 +181,15 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif (!in_array($dbUserForm,$dblist)) { Log::error('Database '.$dbUserForm.' was not found, skipping'); } else { - Database::select_db($dbUserForm); + iDatabase::select_db($dbUserForm); foreach ($u_q_list as $query) { if ($only_test) { - Log::notice("Database::query($dbUserForm,$query)"); + Log::notice("iDatabase::query($dbUserForm,$query)"); Log::notice("In $dbUserForm, executed: $query"); } else { - $res = Database::query($query); + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in '.$query.': '.iDatabase::error()); } } } @@ -212,12 +205,12 @@ if (defined('SYSTEM_INSTALLATION')) { ); if ($dbNameForm != $dbUserForm) { - Database::select_db($dbUserForm); + iDatabase::select_db($dbUserForm); foreach($users_table as $table) { $sql = "ALTER TABLE $dbUserForm.$table RENAME $dbNameForm.$table"; - Database::query($sql); + iDatabase::query($sql); } - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); } } @@ -243,17 +236,17 @@ if (defined('SYSTEM_INSTALLATION')) { } elseif(!in_array($dbNameForm, $dblist)) { Log::error('Database '.$dbNameForm.' was not found, skipping'); } else { - Database::select_db($dbNameForm); - $res = Database::query("SELECT id, code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); + iDatabase::select_db($dbNameForm); + $res = iDatabase::query("SELECT id, code,db_name,directory,course_language FROM course WHERE target_course_code IS NULL ORDER BY code"); if ($res === false) { die('Error while querying the courses list in update_db-1.8.6.2-1.8.7.inc.php'); } $errors = array(); - if (Database::num_rows($res) > 0) { + if (iDatabase::num_rows($res) > 0) { $i = 0; $list = array(); - while ($row = Database::fetch_array($res)) { + while ($row = iDatabase::fetch_array($res)) { $list[] = $row; $i++; } @@ -262,7 +255,7 @@ if (defined('SYSTEM_INSTALLATION')) { // Now use the $c_q_list if (!$singleDbForm) { // otherwise just use the main one - Database::select_db($row_course['db_name']); + iDatabase::select_db($row_course['db_name']); } Log::notice('Course db ' . $row_course['db_name']); @@ -271,14 +264,11 @@ if (defined('SYSTEM_INSTALLATION')) { $query = preg_replace('/^(UPDATE|ALTER TABLE|CREATE TABLE|DROP TABLE|INSERT INTO|DELETE FROM)\s+(\w*)(.*)$/', "$1 $prefix{$row_course['db_name']}_$2$3", $query); } if ($only_test) { - Log::notice("Database::query(".$row_course['db_name'].",$query)"); + Log::notice("iDatabase::query(".$row_course['db_name'].",$query)"); } else { - $res = Database::query($query); - if ($log) { - Log::notice("In ".$row_course['db_name'].", executed: $query"); - } + $res = iDatabase::query($query); if ($res === false) { - Log::error('Error in '.$query.': '.Database::error()); + Log::error('Error in '.$query.': '.iDatabase::error()); } } } @@ -388,18 +378,18 @@ if (defined('SYSTEM_INSTALLATION')) { if (!$singleDbForm) { // otherwise just use the main one - Database::select_db($row_course['db_name']); + iDatabase::select_db($row_course['db_name']); } else { - Database::select_db($dbNameForm); + iDatabase::select_db($dbNameForm); } //Count of rows $sql = "SELECT count(*) FROM $old_table"; - $result = Database::query($sql); + $result = iDatabase::query($sql); $old_count = 0; if ($result) { - $row = Database::fetch_row($result); + $row = iDatabase::fetch_row($result); $old_count = $row[0]; } else { Log::error("Seems that the table $old_table doesn't exists "); @@ -407,13 +397,13 @@ if (defined('SYSTEM_INSTALLATION')) { Log::notice("# rows in $old_table: $old_count"); $sql = "SELECT * FROM $old_table"; - $result = Database::query($sql); + $result = iDatabase::query($sql); $count = 0; - while($row = Database::fetch_array($result, 'ASSOC')) { + while($row = iDatabase::fetch_array($result, 'ASSOC')) { $row['c_id'] = $course_id; - Database::select_db($dbNameForm); - $id = Database::insert($new_table, $row); + iDatabase::select_db($dbNameForm); + $id = iDatabase::insert($new_table, $row); if (is_numeric($id)) { $count++; } else { diff --git a/main/install/update-files-1.8.5-1.8.6.inc.php b/main/install/update-files-1.8.5-1.8.6.inc.php index 8426e79423..2f27733b45 100644 --- a/main/install/update-files-1.8.5-1.8.6.inc.php +++ b/main/install/update-files-1.8.5-1.8.6.inc.php @@ -58,16 +58,16 @@ if (defined('SYSTEM_INSTALLATION')) { //$tbl_course = Database :: get_main_table(TABLE_MAIN_COURSE); //// Linking (The following line is disabled, connection has been already done) - //$res = @Database::connect(array('server' => $dbHostForm, 'username' => $dbUsernameForm, 'password' => $dbPassForm)); - //Database::select_db($dbNameForm, $link); - Database::select_db($dbNameForm); + //$res = @iDatabase::connect(array('server' => $dbHostForm, 'username' => $dbUsernameForm, 'password' => $dbPassForm)); + //iDatabase::select_db($dbNameForm, $link); + iDatabase::select_db($dbNameForm); $db_name = $dbNameForm; $sql = "SELECT * FROM $db_name.course"; Log::notice('Getting courses for files updates: ' . $sql); - $result = Database::query($sql); + $result = iDatabase::query($sql); - while ($courses_directories = Database::fetch_array($result)) { + while ($courses_directories = iDatabase::fetch_array($result)) { $currentCourseRepositorySys = $sys_course_path . $courses_directories['directory'] . '/'; diff --git a/main/install/update-files-1.8.6.1-1.8.6.2.inc.php b/main/install/update-files-1.8.6.1-1.8.6.2.inc.php index fbeadb5870..0ad9dab364 100644 --- a/main/install/update-files-1.8.6.1-1.8.6.2.inc.php +++ b/main/install/update-files-1.8.6.1-1.8.6.2.inc.php @@ -53,17 +53,17 @@ if (defined('SYSTEM_INSTALLATION')) { $perm = api_get_permissions_for_new_directories(); // The following line is disabled, connection has been already done - //$link = Database::connect(array('server' => $dbHostForm, 'username' => $dbUsernameForm, 'password' => $dbPassForm)); - //Database::select_db($dbNameForm, $link); - Database::select_db($dbNameForm); + //$link = iDatabase::connect(array('server' => $dbHostForm, 'username' => $dbUsernameForm, 'password' => $dbPassForm)); + //iDatabase::select_db($dbNameForm, $link); + iDatabase::select_db($dbNameForm); $db_name = $dbNameForm; $sql = "SELECT * FROM $db_name.course"; Log::notice('Getting courses for files updates: ' . $sql); - $result = Database::query($sql); + $result = iDatabase::query($sql); - if (Database::num_rows($result) > 0) { - while ($courses_directories = Database::fetch_array($result)) { + if (iDatabase::num_rows($result) > 0) { + while ($courses_directories = iDatabase::fetch_array($result)) { $currentCourseRepositorySys = $sys_course_path . $courses_directories['directory'] . '/'; // upload > announcements if (!is_dir($currentCourseRepositorySys . "upload/announcements")) { From 13189c68f25f0c144520627b7dd6644d1ef09a28 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 11:14:14 +0200 Subject: [PATCH 081/128] Fixing update_db_course function see #4722 --- main/install/update-db-1.8.8-1.9.0.inc.php | 5 +-- main/webservices/registration.soap.php | 36 ++++++++------- .../announcements/announcements.inc.test.php | 44 ------------------- .../main/inc/lib/add_course.lib.inc.test.php | 26 +---------- 4 files changed, 23 insertions(+), 88 deletions(-) diff --git a/main/install/update-db-1.8.8-1.9.0.inc.php b/main/install/update-db-1.8.8-1.9.0.inc.php index 51eb5c5286..bb2d7b889a 100755 --- a/main/install/update-db-1.8.8-1.9.0.inc.php +++ b/main/install/update-db-1.8.8-1.9.0.inc.php @@ -235,13 +235,12 @@ if (defined('SYSTEM_INSTALLATION')) { } Database::select_db($dbNameForm); } - } - + } //Adds the c_XXX courses tables see #3910 require_once api_get_path(LIBRARY_PATH).'add_course.lib.inc.php'; global $_configuration; - update_Db_course(); + create_course_tables(); $prefix = ''; if ($singleDbForm) { diff --git a/main/webservices/registration.soap.php b/main/webservices/registration.soap.php index 83d3000b0e..e54e2b55d9 100644 --- a/main/webservices/registration.soap.php +++ b/main/webservices/registration.soap.php @@ -2044,7 +2044,7 @@ function WSCreateCourse($params) { $orig_course_id_value[] = $course_param['original_course_id_value']; $visibility = null; - if($course_param['visibility'] && $course_param['visibility'] >= 0 && $course_param['visibility'] <= 3) { + if ($course_param['visibility'] && $course_param['visibility'] >= 0 && $course_param['visibility'] <= 3) { $visibility = $course_param['visibility']; } $extra_list = $course_param['extra']; @@ -2236,7 +2236,7 @@ function WSCreateCourseByTitle($params) { $results = array(); $orig_course_id_value = array(); - foreach($courses_params as $course_param) { + foreach ($courses_params as $course_param) { $title = $course_param['title']; $category_code = 'LANG'; // TODO: A hard-coded value. @@ -2305,23 +2305,27 @@ function WSCreateCourseByTitle($params) { $sql_check = sprintf('SELECT * FROM '.$table_course.' WHERE visual_code = "%s"', Database :: escape_string($wanted_code)); $result_check = Database::query($sql_check); // I don't know why this api function doesn't work... if (Database::num_rows($result_check) < 1) { - if (sizeof($keys)) { - $visual_code = $keys['currentCourseCode']; - $code = $keys['currentCourseId']; - $db_name = $keys['currentCourseDbName']; - $directory = $keys['currentCourseRepository']; - $expiration_date = time() + $firstExpirationDelay; - prepare_course_repository($directory, $code); - update_Db_course($db_name); - $pictures_array = fill_course_repository($directory); - fill_Db_course($db_name, $directory, $course_language, $pictures_array); - $return = register_course($code, $visual_code, $directory, $db_name, $tutor_name, $category_code, $title, $course_language, api_get_user_id(), $expiration_date); + + $params = array(); + + $params['title'] = $title; + $params['wanted_code'] = $wanted_code; + $params['category_code'] = $category_code; + $params['tutor_name'] = $tutor_name; + $params['course_language'] = $course_language; + $params['user_id'] = api_get_user_id(); + $params['visibility'] = $visibility; + + $course_info = create_course($params); + + if (!empty($course_info)) { + $course_code = $course_info['code']; // Save new fieldlabel into course_field table. $field_id = CourseManager::create_course_extra_field($original_course_id_name, 1, $original_course_id_name); // Save the external system's id into user_field_value table. - $res = CourseManager::update_course_extra_field_value($code, $original_course_id_name, $original_course_id_value); + $res = CourseManager::update_course_extra_field_value($course_code, $original_course_id_name, $original_course_id_value); if (is_array($extra_list) && count($extra_list) > 0) { foreach ($extra_list as $extra) { @@ -2330,11 +2334,11 @@ function WSCreateCourseByTitle($params) { // Save new fieldlabel into course_field table. $field_id = CourseManager::create_course_extra_field($extra_field_name, 1, $extra_field_name); // Save the external system's id into course_field_value table. - $res = CourseManager::update_course_extra_field_value($code, $extra_field_name, $extra_field_value); + $res = CourseManager::update_course_extra_field_value($course_code, $extra_field_name, $extra_field_value); } } } - $results[] = $code; + $results[] = $course_code; continue; } else { diff --git a/tests/main/announcements/announcements.inc.test.php b/tests/main/announcements/announcements.inc.test.php index c1faa7ec86..d7c008680b 100755 --- a/tests/main/announcements/announcements.inc.test.php +++ b/tests/main/announcements/announcements.inc.test.php @@ -11,50 +11,6 @@ class TestAnnouncements extends UnitTestCase { function TestAnnouncements(){ $this->UnitTestCase('Displays one specific announcement test'); } - /*public function Testdisplay_announcement(){ - global $_user, $dateFormatLong, $_course; - global $error_msg; - ob_start(); - //create course - $courseSysCode= '142'; - $courseScreenCode='142'; - $courseRepository='142'; - $courseDbName='dokeos_142'; - $titular='R. F. Wolfgan'; - $category='1'; - $title='prueba111'; - $course_language='english'; - $uidCreator='1'; - global $course_code; - $course_code = $courseSysCode; - prepare_course_repository($courseRepository,$courseSysCode); - update_Db_course($courseDbName); - $pictures_array=fill_course_repository($courseRepository); - fill_Db_course($courseDbName, $courseRepository, $course_language,$pictures_array); - $res1 = register_course($courseSysCode, $courseScreenCode, $courseRepository, $courseDbName, $titular, $category, $title, $course_language, $uidCreator, $expiration_date = "", $teachers=array()); - $_course = api_get_course_info($courseSysCode); - - // display announcement in the course added - $announcements_id= 1; - $res2 = display_announcement($announcements_id); - ob_end_clean(); - $this->assertTrue(is_numeric($res1)); - $res3 = CourseManager::delete_course($courseSysCode); - - //var_dump($res1); - //var_dump($res2); - - } - - public function Testshow_to_form(){ - $to_already_selected = ""; - - $_SESSION['_cid'] = 'CURSO1'; - - $res = show_to_form($to_already_selected); - $this->assertTrue(is_null($res)); - //var_dump($res); - }*/ public function Testconstruct_not_selected_select_form(){ $courseSysCode= '123'; diff --git a/tests/main/inc/lib/add_course.lib.inc.test.php b/tests/main/inc/lib/add_course.lib.inc.test.php index 17dd02f060..343929c8f0 100755 --- a/tests/main/inc/lib/add_course.lib.inc.test.php +++ b/tests/main/inc/lib/add_course.lib.inc.test.php @@ -69,31 +69,7 @@ class TestAddCourse extends UnitTestCase { $res = define_course_keys(generate_course_code($wantedCode), null, null, null,null, null); $this->assertTrue($res); } - -/* // 26 excepciones - function TestPrepareCourseRepository(){ - //umask(0); // This function is not thread-safe. - $perm = '0777'; - $courseRepository = 'C16'; - $courseId = 'COD16'; - $res = prepare_course_repository($courseRepository, $courseId); - $res1 = CourseManager::delete_course('C16'); - - - - - $this->assertTrue($res===0); - } - // Problemas con este archivo - falta analizar esta función - function TestUpdateDbCourse(){ - global $_configuration; - $dbcourse = array('courseDbName'=> 'COD16'); - $res = update_Db_course($dbcourse['courseDbName']); - $this->assertTrue($res===0); - //var_dump($res); - } -*/ - + function TestBrowseFolders(){ $browse = array('path'=>'','file'=>'','media'=>''); $res = browse_folders($browse['path'], $browse['files'],$browse['media']); From 5ed0ae29f67d74719cac913d2602399a5c791424 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Wed, 9 May 2012 11:23:03 +0200 Subject: [PATCH 082/128] #4726 missing indexes --- main/inc/lib/add_course.lib.inc.php | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/main/inc/lib/add_course.lib.inc.php b/main/inc/lib/add_course.lib.inc.php index b6f64c27bf..a1a8a476c8 100644 --- a/main/inc/lib/add_course.lib.inc.php +++ b/main/inc/lib/add_course.lib.inc.php @@ -599,7 +599,8 @@ function create_course_tables($course_db_name = null) { $add_to_all_tables thread_id int default NULL, user_id int default NULL, - post_id int default NULL + post_id int default NULL, + PRIMARY KEY ( c_id, thread_id, user_id, post_id ) )" . $charset_clause; Database::query($sql); @@ -624,7 +625,8 @@ function create_course_tables($course_db_name = null) { thread_id int, post_id int, KEY user_id (user_id), - KEY forum_id (forum_id) + KEY forum_id (forum_id), + PRIMARY KEY ( c_id, user_id, forum_id, thread_id, post_id ), )" . $charset_clause; Database::query($sql); @@ -1035,7 +1037,8 @@ function create_course_tables($course_db_name = null) { startdate_assig datetime NOT NULL default '0000-00-00 00:00:00', enddate_assig datetime NOT NULL default '0000-00-00 00:00:00', delayedsubmit int NOT NULL default 0, - KEY page_id (page_id) + KEY page_id (page_id), + PRIMARY KEY ( c_id, page_id ) )" . $charset_clause; Database::query($sql); @@ -1058,7 +1061,8 @@ function create_course_tables($course_db_name = null) { type text NOT NULL, group_id int DEFAULT NULL, session_id smallint default 0, - KEY (c_id, id) + KEY (c_id, id), + PRIMARY KEY ( c_id, id, user_id ) )" . $charset_clause; Database::query($sql); @@ -1091,7 +1095,8 @@ function create_course_tables($course_db_name = null) { user_id int unsigned NOT NULL default '0', last_connection datetime NOT NULL default '0000-00-00 00:00:00', session_id INT NOT NULL default 0, - to_group_id INT NOT NULL default 0 + to_group_id INT NOT NULL default 0, + PRIMARY KEY ( `c_id`, `user_id`, `last_connection` ) )" . $charset_clause; Database::query($sql); @@ -1652,7 +1657,8 @@ function create_course_tables($course_db_name = null) { $add_to_all_tables role_id int NOT NULL default 0, scope varchar( 20 ) NOT NULL default 'course', - group_id int NOT NULL default 0 + group_id int NOT NULL default 0, + PRIMARY KEY (group_id ) )" . $charset_clause; if (!Database::query($sql)) { @@ -1665,7 +1671,8 @@ function create_course_tables($course_db_name = null) { role_id int NOT NULL default 0, tool varchar( 250 ) NOT NULL default '', action varchar( 50 ) NOT NULL default '', - default_perm tinyint NOT NULL default 0 + default_perm tinyint NOT NULL default 0, + PRIMARY KEY ( c_id, role_id, tool, action ) )" . $charset_clause; if (!Database::query($sql)) { @@ -1677,7 +1684,8 @@ function create_course_tables($course_db_name = null) { $add_to_all_tables role_id int NOT NULL default 0, scope varchar( 20 ) NOT NULL default 'course', - user_id int NOT NULL default 0 + user_id int NOT NULL default 0, + PRIMARY KEY ( c_id, role_id, user_id ) )" . $charset_clause; if (!Database::query($sql)) { From 775682d5175ff988b08af64ac54bc7a291f436e6 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Wed, 9 May 2012 11:33:49 +0200 Subject: [PATCH 083/128] #4725 Missing tables after upgrade --- main/install/migrate-db-1.8.8-1.9.0-pre.sql | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index 57f6a43443..3466d6a4f6 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -189,6 +189,19 @@ INSERT INTO settings_options(variable,value,display_text) VALUES ('page_after_lo ALTER TABLE settings_current ADD COLUMN access_url_locked INTEGER NOT NULL DEFAULT 0; +-- skills + +CREATE TABLE IF NOT EXISTS skill ( id int NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, short_code varchar(100) NOT NULL, description TEXT NOT NULL, access_url_id int NOT NULL, icon varchar(255) NOT NULL, PRIMARY KEY (id)); +INSERT INTO skill (name) VALUES ('Root'); + +CREATE TABLE IF NOT EXISTS skill_rel_gradebook ( id int NOT NULL AUTO_INCREMENT, gradebook_id int NOT NULL, skill_id int NOT NULL, type varchar(10) NOT NULL, PRIMARY KEY (id)); +CREATE TABLE IF NOT EXISTS skill_rel_skill ( skill_id int NOT NULL, parent_id int NOT NULL, relation_type int NOT NULL, level int NOT NULL); +INSERT INTO skill_rel_skill VALUES(1, 0, 0, 0); + +CREATE TABLE IF NOT EXISTS skill_rel_user ( id int NOT NULL AUTO_INCREMENT, user_id int NOT NULL, skill_id int NOT NULL, acquired_skill_at datetime NOT NULL DEFAULT '0000-00-00 00:00:00',assigned_by int NOT NULL,PRIMARY KEY (id)); +CREATE TABLE IF NOT EXISTS skill_profile ( id INTEGER NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, description TEXT NOT NULL, PRIMARY KEY (id)); +CREATE TABLE IF NOT EXISTS skill_rel_profile ( id INTEGER NOT NULL AUTO_INCREMENT, skill_id INTEGER NOT NULL, profile_id INTEGER NOT NULL, PRIMARY KEY (id)); + -- Removing use_document_title DELETE FROM settings_current WHERE variable = 'use_document_title'; DELETE FROM settings_options WHERE variable = 'use_document_title'; From 410cca1aec4c7c039c67e41a167698a1fcbe375f Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Wed, 9 May 2012 11:34:53 +0200 Subject: [PATCH 084/128] #4722 update_db_course do not exists --- main/install/update-db-1.8.8-1.9.0.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/install/update-db-1.8.8-1.9.0.inc.php b/main/install/update-db-1.8.8-1.9.0.inc.php index c6e3428c27..85d0941324 100755 --- a/main/install/update-db-1.8.8-1.9.0.inc.php +++ b/main/install/update-db-1.8.8-1.9.0.inc.php @@ -235,7 +235,7 @@ if (defined('SYSTEM_INSTALLATION')) { //Adds the c_XXX courses tables see #3910 require_once api_get_path(LIBRARY_PATH).'add_course.lib.inc.php'; global $_configuration; - update_Db_course(); + create_course_tables(); $prefix = ''; if ($singleDbForm) { From 9e4c35cc6ff680fd87e72aa876a1d1e77a74af75 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 12:05:51 +0200 Subject: [PATCH 085/128] if user_id is empty get the current user_id --- main/inc/lib/events.lib.inc.php | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/main/inc/lib/events.lib.inc.php b/main/inc/lib/events.lib.inc.php index 33b94b6ff0..c25c347cf1 100644 --- a/main/inc/lib/events.lib.inc.php +++ b/main/inc/lib/events.lib.inc.php @@ -13,19 +13,16 @@ */ /* INIT SECTION */ - - $TABLETRACK_LOGIN = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LOGIN); $TABLETRACK_OPEN = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_OPEN); $TABLETRACK_ACCESS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ACCESS); $course_tracking_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); $TABLETRACK_DOWNLOADS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS); -$TABLETRACK_UPLOADS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_UPLOADS); +$TABLETRACK_UPLOADS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_UPLOADS); $TABLETRACK_LINKS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LINKS); $TABLETRACK_EXERCICES = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES); -//$TABLETRACK_SUBSCRIPTIONS = $_configuration['statistics_database'].".track_e_subscriptions"; // this table is never use $TABLETRACK_LASTACCESS = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); //for "what's new" notification -$TABLETRACK_DEFAULT = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_DEFAULT); +$TABLETRACK_DEFAULT = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_DEFAULT); /* FUNCTIONS */ @@ -563,7 +560,6 @@ function exercise_attempt_hotspot($exe_id, $question_id, $answer_id, $correct, $ * @param string Course code (defaults to null) */ function event_system($event_type, $event_value_type, $event_value, $datetime = null, $user_id = null, $course_code = null) { - global $_user; global $TABLETRACK_DEFAULT; $event_type = Database::escape_string($event_type); @@ -586,25 +582,27 @@ function event_system($event_type, $event_value_type, $event_value, $datetime = $event_value = Database::escape_string($event_value); $user_id = Database::escape_string($user_id); - $course_code = Database::escape_string($course_code); + $course_info = api_get_course_info($course_code); $course_id = null; + $course_code = null; + if (!empty($course_info)) { $course_id = $course_info['real_id']; + $course_code = $course_info['code']; } + $course_code = Database::escape_string($course_code); + if (!isset($datetime)) { $datetime = api_get_utc_datetime(); } $datetime = Database::escape_string($datetime); - if(!isset($user_id)) { - $user_id = 0; - } - if(!isset($course_code)) { - $course_code = ''; + if (!isset($user_id)) { + $user_id = api_get_user_id(); } $sql = "INSERT INTO $TABLETRACK_DEFAULT @@ -625,7 +623,7 @@ function event_system($event_type, $event_value_type, $event_value, $datetime = '$event_value')"; $res = Database::query($sql); - //Sending notifications to users + //Sending notifications to users @todo check this $send_event_setting = api_get_setting('activate_send_event_by_mail'); if (!empty($send_event_setting) && $send_event_setting == 'true') { global $language_file; @@ -635,13 +633,13 @@ function event_system($event_type, $event_value_type, $event_value, $datetime = $mail_body=$message; if (is_array($notification_infos)) { foreach ($notification_infos as $variable => $value) { - $mail_body = str_replace('%'.$variable.'%',$value,$mail_body); + $mail_body = str_replace('%'.$variable.'%',$value,$mail_body); } } //prepare mail common variables - if(empty($subject)) { - $subject = $event_type; + if (empty($subject)) { + $subject = $event_type; } $mail_subject = '['.api_get_setting('siteName').'] '.$subject; $sender_name = api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS); From cbaeb61fd019600c5cc15e0c4046651b20f9a2c2 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 12:09:08 +0200 Subject: [PATCH 086/128] Fixing course_code --- main/inc/lib/events.lib.inc.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/main/inc/lib/events.lib.inc.php b/main/inc/lib/events.lib.inc.php index c25c347cf1..6eac342418 100644 --- a/main/inc/lib/events.lib.inc.php +++ b/main/inc/lib/events.lib.inc.php @@ -582,19 +582,19 @@ function event_system($event_type, $event_value_type, $event_value, $datetime = $event_value = Database::escape_string($event_value); $user_id = Database::escape_string($user_id); - + $course_info = api_get_course_info($course_code); - $course_id = null; - $course_code = null; - if (!empty($course_info)) { $course_id = $course_info['real_id']; $course_code = $course_info['code']; + + $course_code = Database::escape_string($course_code); + } else { + $course_id = null; + $course_code = null; } - $course_code = Database::escape_string($course_code); - if (!isset($datetime)) { $datetime = api_get_utc_datetime(); } From 3bb85b114a95294cb4fe8018bc926e96907c911a Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Wed, 9 May 2012 12:09:12 +0200 Subject: [PATCH 087/128] #4694 add feedback during installation --- main/install/i_database.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/main/install/i_database.class.php b/main/install/i_database.class.php index 384fcc476c..ed60334905 100644 --- a/main/install/i_database.class.php +++ b/main/install/i_database.class.php @@ -35,6 +35,7 @@ class iDatabase extends Database static function query($query, $connection = null, $file = null, $line = null) { if (self::is_logging()) { + $query = str_replace("\n", '', $query); Log::notice(__FUNCTION__ . ' ' . $query, Log::frame(1)); } From 72e863b430f5ff1a02c33a4f1744cc495a540e81 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Wed, 9 May 2012 12:09:52 +0200 Subject: [PATCH 088/128] #4554 Shibboleth Authentication --- .../auth/shibboleth/test/shibboleth_test_helper.class.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main/auth/shibboleth/test/shibboleth_test_helper.class.php b/main/auth/shibboleth/test/shibboleth_test_helper.class.php index 8e178e381a..3b68f5f395 100644 --- a/main/auth/shibboleth/test/shibboleth_test_helper.class.php +++ b/main/auth/shibboleth/test/shibboleth_test_helper.class.php @@ -109,4 +109,12 @@ class ShibbolethTestHelper $_SERVER['persistent-id'] = 'idp!viewer!' . md5($id); } + public function setup_new_minimal_data() + { + $id = uniqid(); + $_SERVER['Shib-SwissEP-UniqueID'] = 'usr_' . $id; + $_SERVER['Shib-InetOrgPerson-givenName'] = 'John'; + $_SERVER['Shib-Person-surname'] = 'Doe' . $id; + } + } \ No newline at end of file From 38c25e12f7700095001ce2947be06dfbe123fc4a Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Wed, 9 May 2012 12:10:25 +0200 Subject: [PATCH 089/128] #4554 Shibboleth Authentication --- main/auth/shibboleth/login.php | 1 + 1 file changed, 1 insertion(+) diff --git a/main/auth/shibboleth/login.php b/main/auth/shibboleth/login.php index 501866b668..3b05b40805 100644 --- a/main/auth/shibboleth/login.php +++ b/main/auth/shibboleth/login.php @@ -28,5 +28,6 @@ include_once(dirname(__FILE__) . '/init.php'); //ShibbolethTest::helper()->setup_new_staff(); //ShibbolethTest::helper()->setup_new_teacher(); //ShibbolethTest::helper()->setup_new_student(); +//ShibbolethTest::helper()->setup_new_minimal_data(); ShibbolethController::instance()->login(); \ No newline at end of file From dbe0d408b158fab8c5158364d88225b183e74b70 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 13:54:20 +0200 Subject: [PATCH 090/128] Turning off strict_variables in Twig configuration see #4727 --- main/admin/index.php | 23 ++++++++++-- main/inc/lib/template.lib.php | 37 +++++++++---------- .../template/default/admin/settings_index.tpl | 4 +- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/main/admin/index.php b/main/admin/index.php index 7a551711b0..b60803c64d 100644 --- a/main/admin/index.php +++ b/main/admin/index.php @@ -91,6 +91,7 @@ if (api_is_platform_admin()) { ); } $blocks['users']['items'] = $items; +$blocks['users']['extra'] = null; if (api_is_platform_admin()) { /* Courses */ @@ -126,6 +127,7 @@ if (api_is_platform_admin()) { $items[] = array('url'=>'ldap_import_students.php', 'label' => get_lang('ImportLDAPUsersIntoCourse')); } $blocks['courses']['items'] = $items; + $blocks['courses']['extra'] = null; /* Platform */ $blocks['platform']['icon'] = Display::return_icon('platform.png', get_lang('Platform'), array(), ICON_SIZE_MEDIUM, false); @@ -162,6 +164,7 @@ if (api_is_platform_admin()) { $items[] = array('url'=>'legal_add.php', 'label' => get_lang('TermsAndConditions')); } $blocks['platform']['items'] = $items; + $blocks['platform']['extra'] = null; } /* Sessions */ @@ -195,6 +198,7 @@ if (api_get_setting('use_session_mode') == 'true') { $items[] = array('url'=>'usergroups.php', 'label' => get_lang('Classes')); $blocks['sessions']['items'] = $items; + $blocks['sessions']['extra'] = null; } elseif (api_is_platform_admin()) { @@ -203,9 +207,9 @@ if (api_get_setting('use_session_mode') == 'true') { $blocks['classes']['label'] = api_ucfirst(get_lang('AdminClasses')); $search_form = ' '; + + + '; $blocks['classes']['search_form'] = $search_form; $items = array(); $items[] = array('url'=>'class_list.php', 'label' => get_lang('ClassList')); @@ -215,6 +219,8 @@ if (api_get_setting('use_session_mode') == 'true') { $items[] = array('url'=>'subscribe_class2course.php', 'label' => get_lang('AddClassesToACourse')); $blocks['classes']['items'] = $items; + $blocks['classes']['extra'] = null; + } /* Settings */ @@ -239,6 +245,9 @@ if (api_is_platform_admin()) { //$items[] = array('url'=>'statistics/index.php?action=activities', 'label' => get_lang('ImportantActivities')); $blocks['settings']['items'] = $items; + $blocks['settings']['extra'] = null; + + $blocks['settings']['search_form'] = null; /* Extensions */ /* @@ -266,6 +275,8 @@ if (api_is_platform_admin()) { $items[] = array('url'=>'skills_gradebook.php', 'label' => get_lang('SkillsAndGradebooks')); $blocks['skills']['items'] = $items; + $blocks['skills']['extra'] = null; + $blocks['skills']['search_form'] = null; @@ -285,7 +296,9 @@ if (api_is_platform_admin()) { $items[] = array('url'=>'../../documentation/optimization.html', 'label' => get_lang('OptimizationGuide')); $items[] = array('url'=>'http://www.chamilo.org/extensions', 'label' => get_lang('ChamiloExtensions')); - $blocks['chamilo']['items'] = $items; + $blocks['chamilo']['items'] = $items; + $blocks['chamilo']['extra'] = null; + $blocks['chamilo']['search_form'] = null; // Try to display a maximum before we check the chamilo version and all that. //session_write_close(); //close session to avoid blocking concurrent access @@ -296,6 +309,8 @@ if (api_is_platform_admin()) { $blocks['version_check']['icon'] = Display::return_icon('logo.gif', 'Chamilo.org', array(), ICON_SIZE_SMALL, false); $blocks['version_check']['label'] = get_lang('VersionCheck'); $blocks['version_check']['extra'] = version_check(); + $blocks['version_check']['search_form'] = null; + $blocks['version_check']['items'] = null; } $tpl = new Template(); diff --git a/main/inc/lib/template.lib.php b/main/inc/lib/template.lib.php index 49bce70e52..16e02e1552 100644 --- a/main/inc/lib/template.lib.php +++ b/main/inc/lib/template.lib.php @@ -50,7 +50,7 @@ class Template { 'debug' => true, 'auto_reload' => true, 'optimizations' => 0, // turn on optimizations with -1 - 'strict_variables' => true, //If set to false, Twig will silently ignore invalid variables + 'strict_variables' => false, //If set to false, Twig will silently ignore invalid variables ); } else { $options = array ( @@ -229,20 +229,21 @@ class Template { $this->assign('show_toolbar', $show_toolbar); //Only if course is available - if (!empty($this->course_id) && $this->user_is_logged_in) { - + $show_course_shortcut = null; + $show_course_navigation_menu = null; + + if (!empty($this->course_id) && $this->user_is_logged_in) { if (api_get_setting('show_toolshortcuts') != 'false') { //Course toolbar - $course_tool = CourseHome::show_navigation_tool_shortcuts(); - $this->assign('show_course_shortcut', $course_tool); - } - + $show_course_shortcut = CourseHome::show_navigation_tool_shortcuts(); + } if (api_get_setting('show_navigation_menu') != 'false') { //Course toolbar - $course_tool = CourseHome::show_navigation_menu(); - $this->assign('show_course_navigation_menu', $course_tool); - } - } + $show_course_navigation_menu = CourseHome::show_navigation_menu(); + } + } + $this->assign('show_course_shortcut', $show_course_shortcut); + $this->assign('show_course_navigation_menu', $show_course_navigation_menu); } function get_template($name) { @@ -524,13 +525,12 @@ class Template { $this->assign('notification_menu', $notification); $this->assign('menu', $menu); $this->assign('breadcrumb', $breadcrumb); - + + $extra_header = null; if (!api_is_platform_admin()) { $extra_header = trim(api_get_setting('header_extra_content')); - if (!empty($extra_header)) { - $this->assign('header_extra_content', $extra_header); - } - } + } + $this->assign('header_extra_content', $extra_header); if ($this->show_header == 1) { header('Content-Type: text/html; charset='.api_get_system_encoding()); @@ -626,10 +626,7 @@ class Template { function set_plugin_region($plugin_region) { if (!empty($plugin_region)) { $content = $this->plugin->load_region($plugin_region, $this); - if (!empty($content)) { - //Assigning the plugin with the template - $this->assign('plugin_'.$plugin_region, $content); - } + $this->assign('plugin_'.$plugin_region, $content); } return null; } diff --git a/main/template/default/admin/settings_index.tpl b/main/template/default/admin/settings_index.tpl index df4fec85a2..8578c79e17 100644 --- a/main/template/default/admin/settings_index.tpl +++ b/main/template/default/admin/settings_index.tpl @@ -21,10 +21,10 @@ $(function() { {% for block_item in blocks %}
    -

    {{block_item.icon}} {{block_item.label}}

    +

    {{block_item.icon}} {{block_item.label}}

    {{ block_item.search_form }} -
    +
    {% if block_item.items is not null %}
      {% for url in block_item.items %} From 1b59b0580879a786643b249443c3f8f5c4ef4fc8 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 14:27:34 +0200 Subject: [PATCH 091/128] Moving code inside the lib folder, moving install, uninstall code in a class see BT#3123 --- plugin/bbb/config.php | 13 +-- plugin/bbb/course_install.php | 40 +------- plugin/bbb/end.php | 5 + plugin/bbb/install.php | 62 +----------- plugin/bbb/lang/english.php | 4 +- plugin/bbb/{ => lib}/bbb.lib.php | 3 + plugin/bbb/{ => lib}/bbb_api.php | 0 plugin/bbb/lib/bbb_plugin.class.php | 140 +++++++++++++++++++++++++++- plugin/bbb/listing.php | 4 +- plugin/bbb/plugin.php | 4 +- plugin/bbb/start.php | 4 +- plugin/bbb/uninstall.php | 33 +------ 12 files changed, 166 insertions(+), 146 deletions(-) rename plugin/bbb/{ => lib}/bbb.lib.php (99%) rename plugin/bbb/{ => lib}/bbb_api.php (100%) diff --git a/plugin/bbb/config.php b/plugin/bbb/config.php index 971274ee60..043cf9a674 100644 --- a/plugin/bbb/config.php +++ b/plugin/bbb/config.php @@ -3,9 +3,10 @@ /* bbb parameters that will be registered in the course settings */ -$variables = array( 'big_blue_button_meeting_name', - 'big_blue_button_attendee_password', - 'big_blue_button_moderator_password', - 'big_blue_button_welcome_message', - 'big_blue_button_max_students_allowed' -); \ No newline at end of file +require_once '../../main/inc/global.inc.php'; + +require_once 'lib/bbb_plugin.class.php'; +require_once api_get_path(LIBRARY_PATH) . 'plugin.class.php'; +require_once 'lib/bbb.lib.php'; +require_once 'lib/bbb_api.php'; +require_once 'lib/bbb_plugin.class.php'; diff --git a/plugin/bbb/course_install.php b/plugin/bbb/course_install.php index bbf0ddae06..ccbade1022 100644 --- a/plugin/bbb/course_install.php +++ b/plugin/bbb/course_install.php @@ -6,43 +6,9 @@ /** * Initialization */ +require 'config.php'; -$t_course = Database::get_course_table(TABLE_COURSE_SETTING); // $course_id is set in the add_course.lib.inc.php -if (!empty($course_id)) { - - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_welcome_message','','plugins')"; - $r = Database::query($sql_course); - - /* - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_meeting_name','','plugins')"; - $r = Database::query($sql_course); - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_attendee_password','','plugins')"; - $r = Database::query($sql_course); - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_moderator_password','','plugins')"; - $r = Database::query($sql_course); - - //New BBB settings - - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_max_students_allowed','','plugins')"; - $r = Database::query($sql_course); - - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_open_new_window','','plugins')"; - $r = Database::query($sql_course); - - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_student_must_wait_until_moderator','','plugins')"; - $r = Database::query($sql_course); - - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_join_start_date','','plugins')"; - $r = Database::query($sql_course); - - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_join_end_date','','plugins')"; - $r = Database::query($sql_course);*/ - - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, 'big_blue_button_record_and_store','','plugins')"; - $r = Database::query($sql_course); - - $t_tool = Database::get_course_table(TABLE_TOOL_LIST); - $sql_course = "INSERT INTO $t_tool VALUES ($course_id, NULL, 'videoconference','../../plugin/bbb/start.php','visio.gif','".string2binary(api_get_setting('course_create_active_tools', 'videoconference'))."','0','squaregrey.gif','NO','_self','plugin','0')"; - $r = Database::query($sql_course); +if (!empty($course_id)) { + BBBPlugin::create()->course_install($course_id); } diff --git a/plugin/bbb/end.php b/plugin/bbb/end.php index 8587e866dd..6306926a3a 100644 --- a/plugin/bbb/end.php +++ b/plugin/bbb/end.php @@ -6,6 +6,11 @@ /** * Initialization */ + +//@todo check if this script is used +exit; + + require_once '../../main/inc/global.inc.php'; require_once 'bbb.lib.php'; //The script receives the course_code (cidReq), which allows it to get the corresponding data diff --git a/plugin/bbb/install.php b/plugin/bbb/install.php index bec79ad2e3..3b5bba2956 100644 --- a/plugin/bbb/install.php +++ b/plugin/bbb/install.php @@ -8,63 +8,5 @@ * Initialization */ -require 'config.php'; - -$t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT); -$t_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS); -/** - * Queries - */ -$sql = "INSERT INTO $t_settings (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable, access_url_locked) VALUES - ('bbb_plugin', '', 'radio', 'Extra', 'false', 'BigBlueButtonEnableTitle','BigBlueButtonEnableComment',NULL,NULL, 1, 1)"; -Database::query($sql); -$sql = "INSERT INTO $t_options (variable, value, display_text) VALUES ('bbb_plugin', 'true', 'Yes')"; -Database::query($sql); -$sql = "INSERT INTO $t_options (variable, value, display_text) VALUES ('bbb_plugin', 'false', 'No')"; -Database::query($sql); -$sql = "INSERT INTO $t_settings (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable, access_url_locked) VALUES - ('bbb_plugin_host', '', 'textfield', 'Extra', '192.168.0.100', 'BigBlueButtonHostTitle','BigBlueButtonHostComment',NULL,NULL, 1,1)"; -Database::query($sql); -$sql = "INSERT INTO $t_settings (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable, access_url_locked) VALUES - ('bbb_plugin_salt', '', 'textfield', 'Extra', '', 'BigBlueButtonSecuritySaltTitle','BigBlueButtonSecuritySaltComment',NULL,NULL, 1,1)"; -Database::query($sql); - -$table = Database::get_main_table('plugin_bbb_meeting'); -$sql = "CREATE TABLE $table ( - id INT unsigned NOT NULL auto_increment PRIMARY KEY, - c_id INT unsigned NOT NULL DEFAULT 0, - meeting_name VARCHAR(255) NOT NULL DEFAULT '', - attendee_pw VARCHAR(255) NOT NULL DEFAULT '', - moderator_pw VARCHAR(255) NOT NULL DEFAULT '', - record INT NOT NULL DEFAULT 0, - status INT NOT NULL DEFAULT 0, - created_at VARCHAR(255) NOT NULL, - calendar_id INT DEFAULT 0, - welcome_msg VARCHAR(255) NOT NULL DEFAULT '')"; -Database::query($sql); - -// Update existing courses to add conference settings -$t_courses = Database::get_main_table(TABLE_MAIN_COURSE); -$sql = "SELECT id, code FROM $t_courses ORDER BY id"; -$res = Database::query($sql); -while ($row = Database::fetch_assoc($res)) { - $course_id = $row['id']; - - foreach ($variables as $variable) { - $sql = "SELECT value FROM $t_course WHERE c_id = $course_id AND variable = '$variable' "; - $result = Database::query($sql); - if (!Database::num_rows($result)) { - $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, '$variable','','plugins')"; - $r = Database::query($sql_course); - } - } - - - $t_tool = Database::get_course_table(TABLE_TOOL_LIST); - $sql = "SELECT name FROM $t_tool WHERE c_id = $course_id AND name = 'videoconference' "; - $result = Database::query($sql); - if (!Database::num_rows($result)) { - $sql_course = "INSERT INTO $t_tool VALUES ($course_id, NULL, 'videoconference','../../plugin/bbb/start.php','visio.gif','".string2binary(api_get_setting('course_create_active_tools', 'videoconference'))."','0','squaregrey.gif','NO','_self','plugin','0')"; - $r = Database::query($sql_course); - } -} \ No newline at end of file +require_once 'config.php'; +BBBPlugin::create()->install(); \ No newline at end of file diff --git a/plugin/bbb/lang/english.php b/plugin/bbb/lang/english.php index fe7b7e97eb..758e0a6a4c 100644 --- a/plugin/bbb/lang/english.php +++ b/plugin/bbb/lang/english.php @@ -7,8 +7,8 @@ */ //Needed in order to show the plugin title -$strings['plugin_title'] = "BigBlueButton"; -$strings['plugin_comment'] = "Open Source Videoconference tool"; +$strings['plugin_title'] = "BigBlueButton (BBB)"; +$strings['plugin_comment'] = "Adds a videoconference room Chamilo courses"; $strings['Videoconference'] = "Videoconference"; $strings['MeetingOpened'] = "Meeting opened"; diff --git a/plugin/bbb/bbb.lib.php b/plugin/bbb/lib/bbb.lib.php similarity index 99% rename from plugin/bbb/bbb.lib.php rename to plugin/bbb/lib/bbb.lib.php index 317d2d5241..5528b64f2c 100644 --- a/plugin/bbb/bbb.lib.php +++ b/plugin/bbb/lib/bbb.lib.php @@ -270,4 +270,7 @@ class bbb { function is_server_running() { return BigBlueButtonBN::isServerRunning($this->url); } + + + } \ No newline at end of file diff --git a/plugin/bbb/bbb_api.php b/plugin/bbb/lib/bbb_api.php similarity index 100% rename from plugin/bbb/bbb_api.php rename to plugin/bbb/lib/bbb_api.php diff --git a/plugin/bbb/lib/bbb_plugin.class.php b/plugin/bbb/lib/bbb_plugin.class.php index 9b6318c838..7ee9dc7207 100644 --- a/plugin/bbb/lib/bbb_plugin.class.php +++ b/plugin/bbb/lib/bbb_plugin.class.php @@ -1,7 +1,14 @@ variables as $variable) { + $sql = "SELECT value FROM $t_course WHERE c_id = $course_id AND variable = '$variable' "; + $result = Database::query($sql); + if (!Database::num_rows($result)) { + $sql_course = "INSERT INTO $t_course (c_id, variable,value,category) VALUES ($course_id, '$variable','','plugins')"; + $r = Database::query($sql_course); + } + } + $t_tool = Database::get_course_table(TABLE_TOOL_LIST); + $sql = "SELECT name FROM $t_tool WHERE c_id = $course_id AND name = 'videoconference' "; + $result = Database::query($sql); + if (!Database::num_rows($result)) { + $sql_course = "INSERT INTO $t_tool VALUES ($course_id, NULL, 'videoconference','../../plugin/bbb/start.php','visio.gif','".string2binary(api_get_setting('course_create_active_tools', 'videoconference'))."','0','squaregrey.gif','NO','_self','plugin','0')"; + $r = Database::query($sql_course); + } + } + } + + function uninstall() { + $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT); + $t_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS); + + $sql = "DELETE FROM $t_settings WHERE variable = 'bbb_plugin'"; + Database::query($sql); + $sql = "DELETE FROM $t_options WHERE variable = 'bbb_plugin'"; + Database::query($sql); + $sql = "DELETE FROM $t_settings WHERE variable = 'bbb_plugin_host'"; + Database::query($sql); + $sql = "DELETE FROM $t_settings WHERE variable = 'bbb_plugin_salt'"; + Database::query($sql); + $sql = "DROP TABLE IF EXISTS plugin_bbb_meeting"; + Database::query($sql); + // update existing courses to add conference settings + $t_courses = Database::get_main_table(TABLE_MAIN_COURSE); + $sql = "SELECT id, code FROM $t_courses ORDER BY id"; + $res = Database::query($sql); + while ($row = Database::fetch_assoc($res)) { + $t_course = Database::get_course_table(TABLE_COURSE_SETTING); + // $variables is loaded in the config.php file + foreach ($this->variables as $variable) { + $sql_course = "DELETE FROM $t_course WHERE c_id = " . $row['id'] . " AND variable = '$variable'"; + $r = Database::query($sql_course); + } + + $t_tool = Database::get_course_table(TABLE_TOOL_LIST); + $sql_course = "DELETE FROM $t_tool WHERE c_id = " . $row['id'] . " AND link = '../../plugin/bbb/start.php'"; + $r = Database::query($sql_course); + } + } } \ No newline at end of file diff --git a/plugin/bbb/listing.php b/plugin/bbb/listing.php index 7c5b4277a6..7d59b77e39 100644 --- a/plugin/bbb/listing.php +++ b/plugin/bbb/listing.php @@ -9,9 +9,7 @@ $course_plugin = 'bbb'; -require_once '../../main/inc/global.inc.php'; -require_once 'bbb.lib.php'; -require_once 'bbb_api.php'; +require_once 'config.php'; $tool_name = get_lang('Videoconference'); $tpl = new Template($tool_name); diff --git a/plugin/bbb/plugin.php b/plugin/bbb/plugin.php index ece0986cbf..0b24ed9070 100644 --- a/plugin/bbb/plugin.php +++ b/plugin/bbb/plugin.php @@ -1,6 +1,4 @@ get_info(); \ No newline at end of file diff --git a/plugin/bbb/start.php b/plugin/bbb/start.php index db369352fb..aa0c922e45 100644 --- a/plugin/bbb/start.php +++ b/plugin/bbb/start.php @@ -6,9 +6,7 @@ /** * Initialization */ -require_once '../../main/inc/global.inc.php'; -require_once 'bbb.lib.php'; -require_once 'bbb_api.php'; +require_once 'config.php'; $tool_name = get_lang('Videoconference'); $tpl = new Template($tool_name); diff --git a/plugin/bbb/uninstall.php b/plugin/bbb/uninstall.php index 5b697d328a..4167a208a2 100644 --- a/plugin/bbb/uninstall.php +++ b/plugin/bbb/uninstall.php @@ -9,34 +9,5 @@ /** * Queries */ -require 'config.php'; - -$t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT); -$t_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS); - -$sql = "DELETE FROM $t_settings WHERE variable = 'bbb_plugin'"; -Database::query($sql); -$sql = "DELETE FROM $t_options WHERE variable = 'bbb_plugin'"; -Database::query($sql); -$sql = "DELETE FROM $t_settings WHERE variable = 'bbb_plugin_host'"; -Database::query($sql); -$sql = "DELETE FROM $t_settings WHERE variable = 'bbb_plugin_salt'"; -Database::query($sql); -$sql = "DROP TABLE IF EXISTS plugin_bbb_meeting"; -Database::query($sql); -// update existing courses to add conference settings -$t_courses = Database::get_main_table(TABLE_MAIN_COURSE); -$sql = "SELECT id, code FROM $t_courses ORDER BY id"; -$res = Database::query($sql); -while ($row = Database::fetch_assoc($res)) { - $t_course = Database::get_course_table(TABLE_COURSE_SETTING); - // $variables is loaded in the config.php file - foreach ($variables as $variable) { - $sql_course = "DELETE FROM $t_course WHERE c_id = " . $row['id'] . " AND variable = '$variable'"; - $r = Database::query($sql_course); - } - - $t_tool = Database::get_course_table(TABLE_TOOL_LIST); - $sql_course = "DELETE FROM $t_tool WHERE c_id = " . $row['id'] . " AND link = '../../plugin/bbb/start.php'"; - $r = Database::query($sql_course); -} +require_once 'config.php'; +BBBPlugin::create()->uninstall(); \ No newline at end of file From eba2c1c6c9f612bb0a43a5f914fb7cb77f0737fa Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 14:34:56 +0200 Subject: [PATCH 092/128] Don't load the other language if it's already loaded --- main/inc/lib/plugin.lib.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/main/inc/lib/plugin.lib.php b/main/inc/lib/plugin.lib.php index f547e198b4..3baa3dbd14 100644 --- a/main/inc/lib/plugin.lib.php +++ b/main/inc/lib/plugin.lib.php @@ -148,23 +148,26 @@ class AppPlugin { //1. Loading english if exists $english_path = $root.$plugin_name."/lang/english.php"; - + if (is_readable($english_path)) { - include $english_path; - foreach ($strings as $key => $string) { + include $english_path; + foreach ($strings as $key => $string) { //$$key = $string; - $GLOBALS[$key] = $string; + $GLOBALS[$key] = $string; } } //2. Loading the system language - $path = $root.$plugin_name."/lang/$language_interface.php"; - if (is_readable($path)) { - include $path; - if (!empty($strings)) { - foreach ($strings as $key => $string) { - //$$key = $string; - $GLOBALS[$key] = $string; + if ($language_interface != 'english') { + $path = $root.$plugin_name."/lang/$language_interface.php"; + + if (is_readable($path)) { + include $path; + if (!empty($strings)) { + foreach ($strings as $key => $string) { + //$$key = $string; + $GLOBALS[$key] = $string; + } } } } From 358196866c6d5495645fc58ef8a61a375939b247 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 14:35:32 +0200 Subject: [PATCH 093/128] Adding $course_plugin variable that will load the plugin lang variables --- plugin/bbb/listing.php | 4 +--- plugin/bbb/start.php | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/plugin/bbb/listing.php b/plugin/bbb/listing.php index 7d59b77e39..23079d55c7 100644 --- a/plugin/bbb/listing.php +++ b/plugin/bbb/listing.php @@ -7,10 +7,8 @@ * Initialization */ -$course_plugin = 'bbb'; - +$course_plugin = 'bbb'; //needed in order to load the plugin lang variables require_once 'config.php'; - $tool_name = get_lang('Videoconference'); $tpl = new Template($tool_name); diff --git a/plugin/bbb/start.php b/plugin/bbb/start.php index aa0c922e45..22633b985d 100644 --- a/plugin/bbb/start.php +++ b/plugin/bbb/start.php @@ -6,11 +6,11 @@ /** * Initialization */ -require_once 'config.php'; +$course_plugin = 'bbb'; //needed in order to load the plugin lang variables +require_once 'config.php'; $tool_name = get_lang('Videoconference'); $tpl = new Template($tool_name); - $bbb = new bbb(); if ($bbb) { @@ -41,7 +41,7 @@ if ($bbb) { header('location: '.$url); exit; } - } else { + } else { $message = Display::return_message(get_lang('ServerIsNotRunning'), 'warning'); } } else { From cc9c06dfcfac80657002960f86ad629d9ff5658b Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 14:52:39 +0200 Subject: [PATCH 094/128] Adding spanish lang variables + fixing slash when loading files --- plugin/rss/lang/english.php | 4 ++-- plugin/rss/lang/french.php | 4 ++-- plugin/rss/lang/spanish.php | 9 +++++++++ plugin/rss/plugin.php | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 plugin/rss/lang/spanish.php diff --git a/plugin/rss/lang/english.php b/plugin/rss/lang/english.php index e98e541feb..d01478bea9 100644 --- a/plugin/rss/lang/english.php +++ b/plugin/rss/lang/english.php @@ -6,8 +6,8 @@ * @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html * @author Laurent Opprecht */ -$strings['plugin_title'] = "Rss"; -$strings['plugin_comment'] = "Display rss content."; +$strings['plugin_title'] = "RSS"; +$strings['plugin_comment'] = "Display RSS content."; $strings['rss'] = "Rss"; $strings['block_title'] = "Block title"; diff --git a/plugin/rss/lang/french.php b/plugin/rss/lang/french.php index 92ec942b4b..2a7b1518f2 100644 --- a/plugin/rss/lang/french.php +++ b/plugin/rss/lang/french.php @@ -6,8 +6,8 @@ * @author Laurent Opprecht */ -$strings['plugin_title'] = "Rss"; -$strings['plugin_comment'] = "Affiche le contenu de flux rss."; +$strings['plugin_title'] = "RSS (Flux)"; +$strings['plugin_comment'] = "Affiche le contenu de flux RSS."; $strings['title'] = "Titre"; $strings['no_rss'] = "Veuillez configurer"; \ No newline at end of file diff --git a/plugin/rss/lang/spanish.php b/plugin/rss/lang/spanish.php new file mode 100644 index 0000000000..2ab440a93a --- /dev/null +++ b/plugin/rss/lang/spanish.php @@ -0,0 +1,9 @@ +get_info(); From d83af2c27aad3a862a059f1096cef8615ea60821 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 14:57:52 +0200 Subject: [PATCH 095/128] Adding tabs in the plugin settings --- main/admin/settings.lib.php | 7 +++---- main/admin/settings.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/main/admin/settings.lib.php b/main/admin/settings.lib.php index 9a019333dc..2e28457e89 100644 --- a/main/admin/settings.lib.php +++ b/main/admin/settings.lib.php @@ -81,7 +81,7 @@ function handle_regions() { } function handle_extensions() { - echo ''; + echo Display::page_subheader(get_lang('ConfigureExtensions')); echo ''.get_lang('Ppt2lp').''; } @@ -105,10 +105,10 @@ function handle_plugins() { $all_plugins = $plugin_obj->read_plugins_from_path(); $installed_plugins = $plugin_obj->get_installed_plugins(); - $not_installed = array_diff($all_plugins, $installed_plugins); + //Plugins NOT installed - echo ''; + echo Display::page_subheader(get_lang('Plugins')); echo '
      '; echo ''; echo ''; @@ -167,7 +167,6 @@ function handle_plugins() { echo '
      '; echo '
      '; echo '
      '; - echo '
      '; } /** diff --git a/main/admin/settings.php b/main/admin/settings.php index a838f3a5b8..b0587bea39 100644 --- a/main/admin/settings.php +++ b/main/admin/settings.php @@ -378,9 +378,38 @@ if (!empty($_GET['category'])) { Display :: display_confirmation_message(get_lang('DashboardPluginsHaveBeenUpdatedSucesslly')); } } + + + + echo ''; + + + echo '
      '; + + echo ''; + + echo '
      '; handle_plugins(); + echo '
      '; + + echo '
      '; DashboardManager::handle_dashboard_plugins(); + echo '
      '; + + echo '
      '; handle_extensions(); + echo '
      '; + + echo '
      '; + break; case 'stylesheets': // Displaying the extensions: Stylesheets. From f054b0533f6134ff92d860a5d82f1e8ca80a7012 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 14:58:09 +0200 Subject: [PATCH 096/128] Using page_subheader --- main/inc/lib/dashboard.lib.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/main/inc/lib/dashboard.lib.php b/main/inc/lib/dashboard.lib.php index 8e7f0ea32b..883fc2dd8d 100644 --- a/main/inc/lib/dashboard.lib.php +++ b/main/inc/lib/dashboard.lib.php @@ -26,14 +26,12 @@ class DashboardManager { */ public static function handle_dashboard_plugins() { - $table_settings_current = Database :: get_main_table(TABLE_MAIN_SETTINGS_CURRENT); - /* We scan the plugin directory. Each folder is a potential plugin. */ $dashboard_pluginpath = api_get_path(SYS_PLUGIN_PATH).'dashboard/'; $possibleplugins = self::get_posible_dashboard_plugins_path(); $table_cols = array('name', 'version', 'description'); - echo ''; + echo Display::page_subheader(get_lang('DashboardPlugins')); echo '
      '; echo ''; echo ''; From cd48757bbb598730fe4c04fbf272f5c42e7a9e09 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 15:02:11 +0200 Subject: [PATCH 097/128] api_get_path(SYS_PLUGIN_PATH) already contains a slash --- main/inc/lib/plugin.class.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/main/inc/lib/plugin.class.php b/main/inc/lib/plugin.class.php index 6baa703641..8fd2003d13 100644 --- a/main/inc/lib/plugin.class.php +++ b/main/inc/lib/plugin.class.php @@ -63,9 +63,8 @@ class Plugin { } function get_css() { - $name = $this->get_name(); - $root = api_get_path(SYS_PLUGIN_PATH); - $path = "$root/$name/resources/$name.css"; + $name = $this->get_name(); + $path = api_get_path(SYS_PLUGIN_PATH)."$name/resources/$name.css"; if (!is_readable($path)) { return ''; } From 3936d8850e77019faf4577cd9345792a0aef5834 Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Wed, 9 May 2012 15:02:37 +0200 Subject: [PATCH 098/128] #4694 add feedback during installation --- main/inc/lib/log.class.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/main/inc/lib/log.class.php b/main/inc/lib/log.class.php index aa5d67214f..e9f4a1eb13 100644 --- a/main/inc/lib/log.class.php +++ b/main/inc/lib/log.class.php @@ -106,8 +106,7 @@ class Log */ if (!isset($context['file'])) { $trace = debug_backtrace(); - array_shift($trace); - $trace = reset($trace); + $trace = $trace[1]; $context['file'] = $trace['file']; $context['line'] = $trace['line']; } From 8e72442a1ce4b17bc8f5e2715dcee55120dad10f Mon Sep 17 00:00:00 2001 From: Laurent Opprecht Date: Wed, 9 May 2012 15:28:23 +0200 Subject: [PATCH 099/128] #4694 add feedback during installation --- main/install/i_database.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/install/i_database.class.php b/main/install/i_database.class.php index ed60334905..55ba326c07 100644 --- a/main/install/i_database.class.php +++ b/main/install/i_database.class.php @@ -29,7 +29,7 @@ class iDatabase extends Database if (self::is_logging()) { Log::notice(__FUNCTION__ . ' ' . $database_name, Log::frame(1)); } - parent::select_db($database_name, $connection); + return parent::select_db($database_name, $connection); } static function query($query, $connection = null, $file = null, $line = null) @@ -39,7 +39,7 @@ class iDatabase extends Database Log::notice(__FUNCTION__ . ' ' . $query, Log::frame(1)); } - parent::query($query, $connection, $file, $line); + return parent::query($query, $connection, $file, $line); } } \ No newline at end of file From 3414a8aa8b9dc180f3b3bedc3d27ecc17d755135 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 16:01:01 +0200 Subject: [PATCH 100/128] Now we can add boolean (yes, no) options in a plugin settings, all BBB settings are now moved to the plugin see BT#3123 --- main/admin/configure_plugin.php | 2 +- main/course_info/infocours.php | 2 +- main/inc/lib/display.lib.php | 1 - main/inc/lib/plugin.class.php | 42 +++++++++++++++++++++-------- plugin/bbb/lang/english.php | 12 ++++++++- plugin/bbb/lib/bbb.lib.php | 6 ++--- plugin/bbb/lib/bbb_plugin.class.php | 38 +++++++++++++------------- plugin/search_course/plugin.php | 2 +- plugin/static/plugin.php | 2 +- 9 files changed, 67 insertions(+), 40 deletions(-) diff --git a/main/admin/configure_plugin.php b/main/admin/configure_plugin.php index 1018550d2d..6ce247a884 100644 --- a/main/admin/configure_plugin.php +++ b/main/admin/configure_plugin.php @@ -24,7 +24,6 @@ if (empty($plugin_info)) { $installed_plugins = $plugin_obj->get_installed_plugins(); - if (!in_array($plugin_name, $installed_plugins)) { api_not_allowed(); } @@ -49,6 +48,7 @@ if (isset($plugin_info['settings_form'])) { if (isset($form)) { if ($form->validate()) { $values = $form->exportValues(); + //api_delete_category_settings_by_subkey($plugin_name); $access_url_id = api_get_current_access_url_id(); api_delete_settings_params(array('category = ? AND access_url = ? AND subkey = ? AND type = ? and variable <> ?' => diff --git a/main/course_info/infocours.php b/main/course_info/infocours.php index fecb35b889..99f497930b 100644 --- a/main/course_info/infocours.php +++ b/main/course_info/infocours.php @@ -42,7 +42,7 @@ $course_code = $_course['sysCode']; $course_access_settings = CourseManager :: get_access_settings($course_code); $video_conference_enabled = false; -if (api_get_setting('bbb_plugin') == 'true') { +if (api_get_setting('bbb_tool_enable') == 'true') { $video_conference_enabled = true; } diff --git a/main/inc/lib/display.lib.php b/main/inc/lib/display.lib.php index 8c80ace433..6bf7350ca2 100644 --- a/main/inc/lib/display.lib.php +++ b/main/inc/lib/display.lib.php @@ -781,7 +781,6 @@ class Display { $lis = ''; $i = 1; foreach ($header_list as $item) { - $item =self::tag('a', $item, array('href'=>'#'.$id.'-'.$i)); $lis .=self::tag('li', $item, $ul_attributes); $i++; diff --git a/main/inc/lib/plugin.class.php b/main/inc/lib/plugin.class.php index 8fd2003d13..15b1e3301b 100644 --- a/main/inc/lib/plugin.class.php +++ b/main/inc/lib/plugin.class.php @@ -29,6 +29,7 @@ class Plugin { $result['comment'] = $this->get_comment(); $result['version'] = $this->get_version(); $result['author'] = $this->get_author(); + if ($form = $this->get_settings_form()) { $result['settings_form'] = $form; foreach ($this->fields as $name => $type) { @@ -84,30 +85,45 @@ class Plugin { $defaults = array(); foreach ($this->fields as $name => $type) { $value = $this->get($name); + $defaults[$name] = $value; - $type = $type ? $type : 'text'; - if ($type == 'wysiwyg') { - $result->add_html_editor($name, $this->get_lang($name)); - } else { - $result->addElement($type, $name, $this->get_lang($name)); + $type = isset($type) ? $type : 'text'; + + $help = null; + if ($this->get_lang_plugin_exists($name.'_help')) { + $help = $this->get_lang($name.'_help'); + } + + switch ($type) { + case 'html': + $result->addElement('html', $this->get_lang($name)); + break; + case 'wysiwyg': + $result->add_html_editor($name, $this->get_lang($name)); + break; + case 'text': + $result->addElement($type, $name, array($this->get_lang($name), $help)); + break; + case 'boolean': + $group = array(); + $group[] = $result->createElement('radio', $name, '', get_lang('Yes'), 'true'); + $group[] = $result->createElement('radio', $name, '', get_lang('No'), 'false'); + $result->addGroup($group, null, array($this->get_lang($name), $help)); + break; } } $result->setDefaults($defaults); - $result->addElement('style_submit_button', 'submit_button', $this->get_lang('Save')); return $result; } - function get($name) { - $content = ''; - $title = 'Static'; - $settings = $this->get_settings(); + function get($name) { + $settings = $this->get_settings(); foreach ($settings as $setting) { if ($setting['variable'] == ($this->get_name() . '_' . $name)) { return $setting['selected_value']; } } - return false; } @@ -122,6 +138,10 @@ class Plugin { } private $strings = null; + + public function get_lang_plugin_exists($name) { + return isset($this->strings[$name]); + } public function get_lang($name) { if (is_null($this->strings)) { diff --git a/plugin/bbb/lang/english.php b/plugin/bbb/lang/english.php index 758e0a6a4c..33126e9901 100644 --- a/plugin/bbb/lang/english.php +++ b/plugin/bbb/lang/english.php @@ -32,4 +32,14 @@ $strings['RecordList'] = "Record list"; $strings['ServerIsNotRunning'] = "Videoconference server is not running"; $strings['ServerIsNotConfigured'] = "Videoconference server is not configured"; -$strings['XUsersOnLine'] = "%s user(s) online"; \ No newline at end of file +$strings['XUsersOnLine'] = "%s user(s) online"; + +$strings['host'] = 'BigBlueButton server host'; +$strings['host_help'] = 'This is the name of the server where your BigBlueButton server is running. Might be localhost, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com)'; + +$strings['salt'] = 'Security key of the BigBlueButton server'; +$strings['salt_help'] = 'This is the security key of your BigBlueButton server, which will allow your server to authentify the Chamilo installation. Refer to the BigBlueButton documentation to locate it.'; + +$strings['tool_enable'] = 'BigBlueButton videoconference tool enabled'; +$strings['tool_enable_help'] = "Choose whether you want to enable the BigBlueButton videoconference tool. + Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Students will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please set one up or ask the Chamilo official providers for a quote. BigBlueButton is a free (as in freedom *and* beer), but its installation requires a set of technical skills that might not be immediately available to all. You can install it on your own or seek professional help to assist you or do it for you. This help, however, will generate a certain cost. In the pure logic of the free software, we offer you the tools to make your work easier and recommend professionals (the Chamilo Official Providers) that will be able to help you if this were too difficult.
      "; \ No newline at end of file diff --git a/plugin/bbb/lib/bbb.lib.php b/plugin/bbb/lib/bbb.lib.php index 5528b64f2c..77a3398968 100644 --- a/plugin/bbb/lib/bbb.lib.php +++ b/plugin/bbb/lib/bbb.lib.php @@ -25,9 +25,9 @@ class bbb { $bbb_settings[$setting['variable']] = $setting['selected_value']; } } - $bbb_plugin = $bbb_settings['bbb_plugin'] === 'true'; - $bbb_host = $bbb_settings['bbb_plugin_host']; - $bbb_salt = $bbb_settings['bbb_plugin_salt']; + $bbb_plugin = $bbb_settings['bbb_tool_enable'] === 'true'; + $bbb_host = $bbb_settings['bbb_host']; + $bbb_salt = $bbb_settings['bbb_salt']; $course_code = api_get_course_id(); diff --git a/plugin/bbb/lib/bbb_plugin.class.php b/plugin/bbb/lib/bbb_plugin.class.php index 7ee9dc7207..1879cfef88 100644 --- a/plugin/bbb/lib/bbb_plugin.class.php +++ b/plugin/bbb/lib/bbb_plugin.class.php @@ -2,11 +2,12 @@ class BBBPlugin extends Plugin { - public $variables = array( 'big_blue_button_meeting_name', + public $variables = array( + 'big_blue_button_meeting_name', 'big_blue_button_attendee_password', 'big_blue_button_moderator_password', 'big_blue_button_welcome_message', - 'big_blue_button_max_students_allowed' + 'big_blue_button_max_students_allowed', ); static function create() { @@ -15,7 +16,7 @@ class BBBPlugin extends Plugin } protected function __construct() { - parent::__construct('2.0', 'Julio Montoya, Yannick Warnier'); + parent::__construct('2.0', 'Julio Montoya, Yannick Warnier', array('tool_enable' => 'boolean', 'host' =>'text', 'salt' => 'text')); } function course_install($course_id) { @@ -60,23 +61,7 @@ class BBBPlugin extends Plugin } function install() { - $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT); - $t_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS); $t_course = Database::get_course_table(TABLE_COURSE_SETTING); - - $sql = "INSERT INTO $t_settings (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable, access_url_locked) VALUES - ('bbb_plugin', '', 'radio', 'Extra', 'false', 'BigBlueButtonEnableTitle','BigBlueButtonEnableComment',NULL,NULL, 1, 1)"; - Database::query($sql); - $sql = "INSERT INTO $t_options (variable, value, display_text) VALUES ('bbb_plugin', 'true', 'Yes')"; - Database::query($sql); - $sql = "INSERT INTO $t_options (variable, value, display_text) VALUES ('bbb_plugin', 'false', 'No')"; - Database::query($sql); - $sql = "INSERT INTO $t_settings (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable, access_url_locked) VALUES - ('bbb_plugin_host', '', 'textfield', 'Extra', '192.168.0.100', 'BigBlueButtonHostTitle','BigBlueButtonHostComment',NULL,NULL, 1,1)"; - Database::query($sql); - $sql = "INSERT INTO $t_settings (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable, access_url_locked) VALUES - ('bbb_plugin_salt', '', 'textfield', 'Extra', '', 'BigBlueButtonSecuritySaltTitle','BigBlueButtonSecuritySaltComment',NULL,NULL, 1,1)"; - Database::query($sql); $table = Database::get_main_table('plugin_bbb_meeting'); $sql = "CREATE TABLE $table ( @@ -119,7 +104,18 @@ class BBBPlugin extends Plugin function uninstall() { $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT); - $t_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS); + $t_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS); + + //New settings + + $sql = "DELETE FROM $t_settings WHERE variable = 'bbb_tool_enable'"; + Database::query($sql); + $sql = "DELETE FROM $t_settings WHERE variable = 'bbb_salt'"; + Database::query($sql); + $sql = "DELETE FROM $t_settings WHERE variable = 'bbb_host'"; + Database::query($sql); + + //Old settings $sql = "DELETE FROM $t_settings WHERE variable = 'bbb_plugin'"; Database::query($sql); @@ -129,8 +125,10 @@ class BBBPlugin extends Plugin Database::query($sql); $sql = "DELETE FROM $t_settings WHERE variable = 'bbb_plugin_salt'"; Database::query($sql); + $sql = "DROP TABLE IF EXISTS plugin_bbb_meeting"; Database::query($sql); + // update existing courses to add conference settings $t_courses = Database::get_main_table(TABLE_MAIN_COURSE); $sql = "SELECT id, code FROM $t_courses ORDER BY id"; diff --git a/plugin/search_course/plugin.php b/plugin/search_course/plugin.php index 13e5d7c6c5..e2099a9afd 100644 --- a/plugin/search_course/plugin.php +++ b/plugin/search_course/plugin.php @@ -5,7 +5,7 @@ * @author Laurent Opprecht */ -require_once api_get_path(LIBRARY_PATH) . '/plugin.class.php'; +require_once api_get_path(LIBRARY_PATH) . 'plugin.class.php'; require_once dirname(__FILE__) . '/lib/search_course_plugin.class.php'; $plugin_info = SearchCoursePlugin::create()->get_info(); \ No newline at end of file diff --git a/plugin/static/plugin.php b/plugin/static/plugin.php index 0f35efd14f..011e20bd16 100644 --- a/plugin/static/plugin.php +++ b/plugin/static/plugin.php @@ -6,7 +6,7 @@ * @author Laurent Opprecht */ -require_once api_get_path(LIBRARY_PATH) . '/plugin.class.php'; +require_once api_get_path(LIBRARY_PATH) . 'plugin.class.php'; require_once dirname(__FILE__) . '/lib/static_plugin.class.php'; $plugin_info = StaticPlugin::create()->get_info(); \ No newline at end of file From 1255905b5aec9e66ddd5fab66107db1458f44962 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 16:35:45 +0200 Subject: [PATCH 101/128] BBB plugin settings are now managed by the plugin class. Click "configure" in order to setup the BBB plugin see BT#3123 --- plugin/bbb/config.php | 6 +----- plugin/bbb/lang/english.php | 8 ++++---- plugin/bbb/lib/bbb.lib.php | 34 ++++++++++++++-------------------- plugin/bbb/start.php | 2 +- 4 files changed, 20 insertions(+), 30 deletions(-) diff --git a/plugin/bbb/config.php b/plugin/bbb/config.php index 043cf9a674..a8e79220ec 100644 --- a/plugin/bbb/config.php +++ b/plugin/bbb/config.php @@ -4,9 +4,5 @@ /* bbb parameters that will be registered in the course settings */ require_once '../../main/inc/global.inc.php'; - -require_once 'lib/bbb_plugin.class.php'; -require_once api_get_path(LIBRARY_PATH) . 'plugin.class.php'; require_once 'lib/bbb.lib.php'; -require_once 'lib/bbb_api.php'; -require_once 'lib/bbb_plugin.class.php'; +require_once 'lib/bbb_api.php'; \ No newline at end of file diff --git a/plugin/bbb/lang/english.php b/plugin/bbb/lang/english.php index 33126e9901..fc3fe33fdd 100644 --- a/plugin/bbb/lang/english.php +++ b/plugin/bbb/lang/english.php @@ -34,11 +34,11 @@ $strings['ServerIsNotConfigured'] = "Videoconference server is not configured"; $strings['XUsersOnLine'] = "%s user(s) online"; -$strings['host'] = 'BigBlueButton server host'; -$strings['host_help'] = 'This is the name of the server where your BigBlueButton server is running. Might be localhost, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com)'; +$strings['host'] = 'BigBlueButton host'; +$strings['host_help'] = 'This is the name of the server where your BigBlueButton server is running. Might be localhost, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com).'; -$strings['salt'] = 'Security key of the BigBlueButton server'; -$strings['salt_help'] = 'This is the security key of your BigBlueButton server, which will allow your server to authentify the Chamilo installation. Refer to the BigBlueButton documentation to locate it.'; +$strings['salt'] = 'BigBlueButton salt'; +$strings['salt_help'] = 'This is the security key of your BigBlueButton server, which will allow your server to authentify the Chamilo installation. Refer to the BigBlueButton documentation to locate it. Try bbb-conf --salt'; $strings['tool_enable'] = 'BigBlueButton videoconference tool enabled'; $strings['tool_enable_help'] = "Choose whether you want to enable the BigBlueButton videoconference tool. diff --git a/plugin/bbb/lib/bbb.lib.php b/plugin/bbb/lib/bbb.lib.php index 77a3398968..63721ef83b 100644 --- a/plugin/bbb/lib/bbb.lib.php +++ b/plugin/bbb/lib/bbb.lib.php @@ -1,10 +1,12 @@ get('tool_enable'); + $bbb_host = $plugin->get('host'); + $bbb_salt = $plugin->get('salt'); $course_code = api_get_course_id(); $this->logout_url = api_get_path(WEB_COURSE_PATH).$course_code; - if ($bbb_plugin) { + if ($bbb_plugin == true) { $user_info = api_get_user_info(); $this->user_complete_name = $user_info['complete_name']; $this->salt = $bbb_salt; $this->url = $bbb_host.'/bigbluebutton/'; - $this->table = Database::get_main_table('plugin_bbb_meeting'); - return true; - } - return false; + $this->table = Database::get_main_table('plugin_bbb_meeting'); + $this->plugin_enabled = true; + } } function is_teacher() { @@ -270,7 +267,4 @@ class bbb { function is_server_running() { return BigBlueButtonBN::isServerRunning($this->url); } - - - } \ No newline at end of file diff --git a/plugin/bbb/start.php b/plugin/bbb/start.php index 22633b985d..aa5d59dbfb 100644 --- a/plugin/bbb/start.php +++ b/plugin/bbb/start.php @@ -13,7 +13,7 @@ $tool_name = get_lang('Videoconference'); $tpl = new Template($tool_name); $bbb = new bbb(); -if ($bbb) { +if ($bbb->plugin_enabled) { if ($bbb->is_server_running()) { if (isset($_GET['launch']) && $_GET['launch'] == 1) { From e5f9680ac82e475b372d9663ae62cf7aa274ec96 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 16:38:24 +0200 Subject: [PATCH 102/128] Minor adding gradebook_locking_enabled validations (not finished yet) see BT#4080 --- main/gradebook/gradebook_add_cat.php | 15 ---- .../gradebook/lib/gradebook_functions.inc.php | 5 ++ main/inc/lib/events.lib.inc.php | 22 +++++- main/inc/lib/main_api.lib.php | 68 ++++++------------- 4 files changed, 43 insertions(+), 67 deletions(-) diff --git a/main/gradebook/gradebook_add_cat.php b/main/gradebook/gradebook_add_cat.php index a1ac7736e7..d28d3e9dfd 100644 --- a/main/gradebook/gradebook_add_cat.php +++ b/main/gradebook/gradebook_add_cat.php @@ -97,21 +97,6 @@ if ($_in_course) { } $catadd->set_course_code(api_get_course_id()); -/* -$models = api_get_settings_options('grading_model'); -$course_grading_model_id = api_get_course_setting('course_grading_model'); -$grading_model = ''; -if (!empty($course_grading_model_id)) { - foreach($models as $option) { - if (intval($option['id']) == $course_grading_model_id) { - $grading_model = $option['value']; - } - } -} - -$grading_contents = api_grading_model_functions($grading_model, 'to_array'); -*/ - $form = new CatForm(CatForm :: TYPE_ADD, $catadd, 'add_cat_form', null, api_get_self() . '?selectcat='.$get_select_cat); diff --git a/main/gradebook/lib/gradebook_functions.inc.php b/main/gradebook/lib/gradebook_functions.inc.php index 2f20d5ca05..84e61e3e56 100644 --- a/main/gradebook/lib/gradebook_functions.inc.php +++ b/main/gradebook/lib/gradebook_functions.inc.php @@ -209,6 +209,11 @@ function build_edit_icons_cat($cat, $selectcat) { if (api_is_allowed_to_edit(null, true)) { + //Locking button + if (api_get_setting('gradebook_locking_enabled') == 'true') { + //$modify_icons .= ' '.Display::return_icon('lock.png', get_lang('Lock'),'',ICON_SIZE_SMALL).''; + } + //PDF $modify_icons .= ' '.Display::return_icon('pdf.png', get_lang('ExportToPDF'),'',ICON_SIZE_SMALL).''; diff --git a/main/inc/lib/events.lib.inc.php b/main/inc/lib/events.lib.inc.php index 6eac342418..82434f6af8 100644 --- a/main/inc/lib/events.lib.inc.php +++ b/main/inc/lib/events.lib.inc.php @@ -549,6 +549,22 @@ function exercise_attempt_hotspot($exe_id, $question_id, $answer_id, $correct, $ return $result = Database::query($sql); } +/** + * + * @param type $status LOG_GRADEBOOK_LOCKED - LOG_GRADEBOOK_UNLOCKED + * @param type $course_id + * @param type $session_id + * @param type $item_id + * @param type $tool_id + * @return boolean + */ +function event_change_gradebook_lock_status($status, $course_code, $gradebook_id) { + if (api_get_setting('gradebook_locking_enabled') == 'true') { + event_system($status, LOG_GRADEBOOK_ID, $gradebook_id, null, null, $course_code); + } + return false; +} + /** * @author Yannick Warnier * @desc Record information for common (or admin) events (in the track_e_default table) @@ -580,9 +596,7 @@ function event_system($event_type, $event_value_type, $event_value, $datetime = } } - $event_value = Database::escape_string($event_value); - $user_id = Database::escape_string($user_id); - + $event_value = Database::escape_string($event_value); $course_info = api_get_course_info($course_code); if (!empty($course_info)) { @@ -605,6 +619,8 @@ function event_system($event_type, $event_value_type, $event_value, $datetime = $user_id = api_get_user_id(); } + $user_id = intval($user_id); + $sql = "INSERT INTO $TABLETRACK_DEFAULT (default_user_id, default_cours_code, diff --git a/main/inc/lib/main_api.lib.php b/main/inc/lib/main_api.lib.php index 7f1496f37f..8897384244 100644 --- a/main/inc/lib/main_api.lib.php +++ b/main/inc/lib/main_api.lib.php @@ -155,6 +155,11 @@ define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable'); define('LOG_CAREER_ID', 'career_id'); define('LOG_PROMOTION_ID', 'promotion_id'); +define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked'); +define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked'); +define('LOG_GRADEBOOK_ID', 'gradebook_id'); + + // Specification for usernames: // 1. ASCII-letters, digits, "." (dot), "_" (underscore) are acceptable, 40 characters maximum length. // 2. Empty username is formally valid, but it is reserved for the anonymous user. @@ -4235,7 +4240,7 @@ function & api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $u $sql .= " ORDER BY 1,2 ASC"; } $result = Database::store_result(Database::query($sql)); - return $result; + return $result; } /** @@ -5637,7 +5642,6 @@ function api_get_jquery_libraries_js($libraries) { return $js; } - /** * Returns the course's URL * @@ -5647,7 +5651,6 @@ function api_get_jquery_libraries_js($libraries) { * @return mixed The URL of the course or null if something does not work * @author Julio Montoya */ - function api_get_course_url($course_code = null, $session_id = null) { $session_url = ''; if (empty($course_code)) { @@ -5707,7 +5710,6 @@ function api_get_home_path() { return $home; } - function api_get_course_table_condition($and = true) { $course_id = api_get_course_int_id(); $condition = ''; @@ -5718,48 +5720,16 @@ function api_get_course_table_condition($and = true) { return $condition; } -function api_grading_model_functions($grading_model, $action = 'to_array') { - $return = null; - if (empty($grading_model)) { - return null; - } - $elements = array('A','B','C','D','E','F','G','H','I','J','K','L','M'); - - if (in_array($action, array('to_array', 'decorate'))) { - $parts = explode('/', $grading_model); - $return['denominator'] = $parts[1]; - $sums = explode('+', $parts[0]); - - $j = 0; - foreach($sums as $item) { - $item = explode('*', $item); - $per = 0; - if (!empty($return['denominator'])) { - $per = $item[0]/$return['denominator']*100; - } - $return['items'][] =array( 'letter' => $elements[$j], - 'value' => $item[0], - 'percentage'=> $per.'%'); - $j++; - } - - if ($action == 'decorate') { - $return_value = ''; - $items = $return['items']; - $j = 1; - foreach ($items as $item) { - $letter = $item['letter']; - $value = $item['value']; - - $sum = '+'; - if (count($items) == $j){ - $sum = ''; - } - $return_value = $return_value.' '.$value.'*'.$letter." $sum "; - $j++; - } - $return = ' ('.$return_value.') / '.$return['denominator']; - } - } - return $return; -} +/** + * + * @param int Course id + * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH + * @param int the item id (tool id, exercise id, lp id) + * + */ +function api_course_item_is_blocked_by_gradebook($course_id, $tool_id, $item_id) { + if (api_get_setting('gradebook_locking_enabled') == 'true') { + //$course_id + } + return false; +} \ No newline at end of file From 12067b289080f4688db0e2382b98f9d47cd06fb8 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Wed, 9 May 2012 10:53:30 -0500 Subject: [PATCH 103/128] Added gray icons for unlock - refs BT#4080 --- main/img/icons/22/unlock_na.png | Bin 0 -> 534 bytes main/img/icons/32/unlock_na.png | Bin 0 -> 882 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 main/img/icons/22/unlock_na.png create mode 100644 main/img/icons/32/unlock_na.png diff --git a/main/img/icons/22/unlock_na.png b/main/img/icons/22/unlock_na.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3f5c7ebe887ae77bb425541627b58b944f4782 GIT binary patch literal 534 zcmV+x0_pvUP)Px#0%A)?L;(MXkIcUS000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iye-4>K|= zAjN|K00EjwL_t(2&wbH7OCwPf#_|7X45*;#wpuWq3W6-Q7WxGY><8HR4HRuGL@h*d zEfib}Um)9UwHv`+t1T9m6|vSRs2J2tVq#{J+Y7^5e{zdo2MhyljnH zOMQu6gd)YXY|or}J5qm%PuG(vxe+ZQB1*30K-QN7EGAw~?nzl{QjiC^m#kEzEPJvt z6JX10V_~4@-(0MNTYi(tID8x!VUQ@_$j8?*^)@=Z&r}lQu`aS4az48lUyWZ*9NQOk z@rg>pGd^~vhAHuv!phezfQ{3a=|9{sgfrEIUHU0;ft&VLcG5X=bmRI55b-PXlOhl7 zpZR;ZD5^NkxHfwf<4tNP%2b>2k26|C8+99aH`)266)kbi9b==DC+a&X>gT*EpZUQ1 zx#t)2R-kdg00001b5ch_0Itp) z=>Px#0%A)?L;(MXkIcUS000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iye-4>KQb z|C#mx00Q<&L_t(Y$BmWAYZO5ghrjO3Oi+Ro6;X)`L=TEv22?z{fEN)I{{ZzOcoIPc zMG!$nMO@H>;6V`)grK+}c+!I!(cqd0t`oPoj3krU(p}YE&qI2ao@B;(O+(RLzwgz1 z{i|vOL8ujHSDjiz1gqA2!5R@)&p6%6PHTg;crwBOeviKM_ROUeeuIEx8|{lT;|b;< zfX_$X^C^?wfA|6l69zE4ghN|TN>W5bj3{wMM8uc3azgfZGJ&T501j+DCjBC!Wk~)= zzkHKE`7KIBl5#}0?PUUXof7u7+I?H%b5LX%*B9z4S-<`g2~ zrs$oCcsq&=uenF+=9h;}URy`+rg<$LL|8<3OKSUrcWAt#q6*+`o)2V5ax4F6PxosE z$#Y}*6?Hi}U06zjH!Eo+TL##b^6jl^_Cg#KUHrJ&{gUr|rJtWqyT0$}B}a;O%(S-Y z#LAiwKqqEkaPauZtGf)4B8NgzxPE&ulV%8r)4qUMSr-C0w#LUnljXx#GPpsr1lM_! zp@6|dHxVuCLOpPXzHl55g9aZ};XLs~$fNM^EbOxLLV(T}t5)~U)#Jo+v*gf~2JsLK z3O{Vcs;^+~chN&L7J|cYwet;X)OLzg?F|DMGFpo0La?SIJgbT z(|jgJAwm?p1jyr|8Ui>Z@yX*_BVH&0G+qM*}`yZlX!UH5OASHP0Xwqwv!{z|D?uircwq z?a|mS8jiuMkIs_hulPlP#dxMJS?kAY|H{kJ^BkAI{H7rC4;_W!^7@B0P5=M^07*qo IM6N<$f+_Zms{jB1 literal 0 HcmV?d00001 From 6120b1a9ef8360387947b287dc85b17db6e941d0 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 17:58:23 +0200 Subject: [PATCH 104/128] Minor adding comment --- main/inc/lib/template.lib.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main/inc/lib/template.lib.php b/main/inc/lib/template.lib.php index 16e02e1552..a08c36d83d 100644 --- a/main/inc/lib/template.lib.php +++ b/main/inc/lib/template.lib.php @@ -468,8 +468,11 @@ class Template { global $this_section; + //@todo minify CSS and JS + $this->assign('css_file_to_string', $css_file_to_string); - $this->assign('js_file_to_string', $js_file_to_string); + $this->assign('js_file_to_string', $js_file_to_string); + $this->assign('text_direction', api_get_text_direction()); $this->assign('section_name', 'section-'.$this_section); From c4353108e0318a1eb35490a10c3ed38d3596382a Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 18:02:19 +0200 Subject: [PATCH 105/128] Adding "locked" field in the gradebook_link table see BT#4080 --- main/install/db_main.sql | 7 ++++--- main/install/migrate-db-1.8.8-1.9.0-pre.sql | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/main/install/db_main.sql b/main/install/db_main.sql index a886e4f3a9..c861b0b43a 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -859,7 +859,7 @@ VALUES ('shibboleth_description', NULL, 'radio', 'Shibboleth', 'false', 'ShibbolethMainActivateTitle', 'ShibbolethMainActivateComment', NULL, NULL, 0), ('facebook_description', NULL, 'radio', 'Facebook', 'false', 'FacebookMainActivateTitle', 'FacebookMainActivateComment', NULL, NULL, 0), ('gradebook_locking_enabled', NULL, 'radio', 'Gradebook', 'false', 'GradebookEnableLockingTitle', 'GradebookEnableLockingComment', NULL, NULL, 0), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17769','DatabaseVersion','', NULL, NULL, 0); +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17825','DatabaseVersion','', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), @@ -1357,7 +1357,7 @@ CREATE TABLE IF NOT EXISTS gradebook_evaluation ( created_at DATETIME NOT NULL default '0000-00-00 00:00:00', weight FLOAT NOT NULL, max float unsigned NOT NULL, - visible tinyint NOT NULL, + visible int NOT NULL, type varchar(40) NOT NULL default 'evaluation', locked int NOT NULL DEFAULT 0, PRIMARY KEY (id) @@ -1372,7 +1372,8 @@ CREATE TABLE IF NOT EXISTS gradebook_link ( category_id int NOT NULL, created_at DATETIME NOT NULL default '0000-00-00 00:00:00', weight float NOT NULL, - visible tinyint NOT NULL, + visible int NOT NULL, + locked int NOT NULL DEFAULT 0, PRIMARY KEY (id) ); DROP TABLE IF EXISTS gradebook_result; diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index 3466d6a4f6..f926edfb66 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -119,6 +119,7 @@ INSERT INTO settings_options (variable, value, display_text) VALUES ('enable_hel ALTER TABLE gradebook_category MODIFY COLUMN weight FLOAT NOT NULL; ALTER TABLE gradebook_link MODIFY COLUMN weight FLOAT NOT NULL; +ALTER TABLE gradebook_link ADD COLUMN locked INT DEFAULT 0; INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('allow_hr_skills_management', NULL, 'radio', 'Gradebook', 'true', 'AllowHRSkillsManagementTitle', 'AllowHRSkillsManagementComment', NULL, NULL, 1); INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_hr_skills_management', 'true', 'Yes'); @@ -207,7 +208,7 @@ DELETE FROM settings_current WHERE variable = 'use_document_title'; DELETE FROM settings_options WHERE variable = 'use_document_title'; -- Do not move this query -UPDATE settings_current SET selected_value = '1.9.0.17769' WHERE variable = 'chamilo_database_version'; +UPDATE settings_current SET selected_value = '1.9.0.17825' WHERE variable = 'chamilo_database_version'; -- xxSTATSxx ALTER TABLE track_e_exercices ADD COLUMN questions_to_check TEXT NOT NULL DEFAULT ''; From bb4728293d42e5b1f4c4532c7c10c76503e3df43 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 18:11:59 +0200 Subject: [PATCH 106/128] Fixing evaluation::load query --- main/gradebook/lib/be/evaluation.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/gradebook/lib/be/evaluation.class.php b/main/gradebook/lib/be/evaluation.class.php index 4d00772b15..e2fb359e23 100644 --- a/main/gradebook/lib/be/evaluation.class.php +++ b/main/gradebook/lib/be/evaluation.class.php @@ -139,7 +139,7 @@ class Evaluation implements GradebookItem */ public function load ($id = null, $user_id = null, $course_code = null, $category_id = null, $visible = null, $locked = null) { $tbl_grade_evaluations = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_EVALUATION); - $sql = 'SELECT id,name,description,user_id,course_code,category_id,created_at,weight,max,visible,type,locked FROM '.$tbl_grade_evaluations; + $sql = 'SELECT * FROM '.$tbl_grade_evaluations; $paramcount = 0; if (isset ($id)) { $sql.= ' WHERE id = '.intval($id); @@ -172,7 +172,7 @@ class Evaluation implements GradebookItem if (isset ($locked)) { if ($paramcount != 0) $sql .= ' AND'; else $sql .= ' WHERE'; - $sql .= ' visible = '.intval($locked); + $sql .= ' locked = '.intval($locked); $paramcount ++; } $result = Database::query($sql); From 0f7b5b5e7d0d46884170d83844d63667649e2907 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 18:26:52 +0200 Subject: [PATCH 107/128] Adding the lock flag in the gradebook_category table see BT#4080 --- main/install/db_main.sql | 3 ++- main/install/migrate-db-1.8.8-1.9.0-pre.sql | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/main/install/db_main.sql b/main/install/db_main.sql index c861b0b43a..ff23578596 100644 --- a/main/install/db_main.sql +++ b/main/install/db_main.sql @@ -859,7 +859,7 @@ VALUES ('shibboleth_description', NULL, 'radio', 'Shibboleth', 'false', 'ShibbolethMainActivateTitle', 'ShibbolethMainActivateComment', NULL, NULL, 0), ('facebook_description', NULL, 'radio', 'Facebook', 'false', 'FacebookMainActivateTitle', 'FacebookMainActivateComment', NULL, NULL, 0), ('gradebook_locking_enabled', NULL, 'radio', 'Gradebook', 'false', 'GradebookEnableLockingTitle', 'GradebookEnableLockingComment', NULL, NULL, 0), -('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17825','DatabaseVersion','', NULL, NULL, 0); +('chamilo_database_version',NULL,'textfield',NULL, '1.9.0.17828','DatabaseVersion','', NULL, NULL, 0); /* ('show_tabs', 'custom_tab_1', 'checkbox', 'Platform', 'true', 'ShowTabsTitle', 'ShowTabsComment', NULL, 'TabsCustom1', 1), @@ -1344,6 +1344,7 @@ CREATE TABLE IF NOT EXISTS gradebook_category ( certif_min_score int DEFAULT NULL, session_id int DEFAULT NULL, document_id int unsigned DEFAULT NULL, + locked int NOT NULL DEFAULT 0, PRIMARY KEY (id) ); DROP TABLE IF EXISTS gradebook_evaluation; diff --git a/main/install/migrate-db-1.8.8-1.9.0-pre.sql b/main/install/migrate-db-1.8.8-1.9.0-pre.sql index f926edfb66..ee18c14a38 100755 --- a/main/install/migrate-db-1.8.8-1.9.0-pre.sql +++ b/main/install/migrate-db-1.8.8-1.9.0-pre.sql @@ -120,6 +120,7 @@ INSERT INTO settings_options (variable, value, display_text) VALUES ('enable_hel ALTER TABLE gradebook_category MODIFY COLUMN weight FLOAT NOT NULL; ALTER TABLE gradebook_link MODIFY COLUMN weight FLOAT NOT NULL; ALTER TABLE gradebook_link ADD COLUMN locked INT DEFAULT 0; +ALTER TABLE gradebook_category ADD COLUMN locked INT DEFAULT 0; INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('allow_hr_skills_management', NULL, 'radio', 'Gradebook', 'true', 'AllowHRSkillsManagementTitle', 'AllowHRSkillsManagementComment', NULL, NULL, 1); INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_hr_skills_management', 'true', 'Yes'); @@ -208,7 +209,7 @@ DELETE FROM settings_current WHERE variable = 'use_document_title'; DELETE FROM settings_options WHERE variable = 'use_document_title'; -- Do not move this query -UPDATE settings_current SET selected_value = '1.9.0.17825' WHERE variable = 'chamilo_database_version'; +UPDATE settings_current SET selected_value = '1.9.0.17828' WHERE variable = 'chamilo_database_version'; -- xxSTATSxx ALTER TABLE track_e_exercices ADD COLUMN questions_to_check TEXT NOT NULL DEFAULT ''; From f85de3c9fdbd4d956cb78c4a32be14f7d22e934f Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Wed, 9 May 2012 18:50:22 +0200 Subject: [PATCH 108/128] Adding lock support for categories, removing single evaluation lock see BT#4080 --- main/gradebook/index.php | 35 ++++++++++++- main/gradebook/lib/be/abstractlink.class.php | 27 ++++++++-- main/gradebook/lib/be/category.class.php | 50 ++++++++++++++++++- main/gradebook/lib/be/evallink.class.php | 2 +- main/gradebook/lib/be/evaluation.class.php | 20 +++----- .../gradebook/lib/fe/gradebooktable.class.php | 2 +- .../gradebook/lib/gradebook_functions.inc.php | 15 ++++-- main/inc/lib/events.lib.inc.php | 19 +------ 8 files changed, 126 insertions(+), 44 deletions(-) diff --git a/main/gradebook/index.php b/main/gradebook/index.php index 92f4cf8aa9..585a21f16f 100644 --- a/main/gradebook/index.php +++ b/main/gradebook/index.php @@ -49,6 +49,15 @@ $htmlHeadXtra[] = ''; - - echo '
      '; - - echo ''; - - echo '
      '; - handle_plugins(); - echo '
      '; - - echo '
      '; - DashboardManager::handle_dashboard_plugins(); - echo '
      '; - - echo '
      '; - handle_extensions(); - echo '
      '; - - echo '
      '; - + echo ''; + + echo '
      '; + handle_plugins(); + echo '
      '; + + echo '
      '; + DashboardManager::handle_dashboard_plugins(); + echo '
      '; + + echo '
      '; + handle_extensions(); + echo '
      '; + echo ''; break; - case 'stylesheets': + case 'Stylesheets': // Displaying the extensions: Stylesheets. handle_stylesheets(); break; From d4b7fd5c8c6f6606ea16a538250a18617ba649a0 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Thu, 10 May 2012 11:21:35 +0200 Subject: [PATCH 114/128] Minor - fixing footer --- main/template/default/layout/footer.tpl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/main/template/default/layout/footer.tpl b/main/template/default/layout/footer.tpl index e8d679d0cf..cbb4cd0cdd 100644 --- a/main/template/default/layout/footer.tpl +++ b/main/template/default/layout/footer.tpl @@ -6,7 +6,7 @@
      {{session_teachers}}
      - {% endif %} + {% endif %} {% if teachers is not null %}
      @@ -20,7 +20,7 @@ {{plugin_footer_left}}
      {% endif %} -   +   {% endif %} +  
      + $html='
      - '; - $form -> addElement ('html', $html); + + $form -> addElement ('label', get_lang('MakeCorrespond').'
      ', $html); if ($nb_matches < 1) { $nb_matches = 1; @@ -146,13 +139,8 @@ class Matching extends Question { $form -> addGroup($group); - // DISPLAY OPTIONS //// - $html=' -
      -
      -
      -


      -
      '.get_lang('Number').' @@ -110,9 +103,9 @@ class Matching extends Question { '.get_lang('Weighting').'
      + // DISPLAY OPTIONS + $html='
      '; - $form -> addElement ('html', $html); + //$form -> addElement ('html', $html); + $form -> addElement ('label', null, $html); if ($nb_options < 1) { $nb_options = 1; diff --git a/main/exercice/multiple_answer.class.php b/main/exercice/multiple_answer.class.php index 7bba077b47..bfc3100e2f 100644 --- a/main/exercice/multiple_answer.class.php +++ b/main/exercice/multiple_answer.class.php @@ -46,13 +46,7 @@ class MultipleAnswer extends Question { $obj_ex = $_SESSION['objExercise']; - $html=' -
      -
      - '.get_lang('Answers').'
      -
      -
      -
      '.get_lang('Number').' @@ -160,9 +148,9 @@ class Matching extends Question { -
      + $html='
      '; - $form -> addElement ('html', $html); + $form -> addElement ('label', get_lang('Answers').'
      ', $html); $defaults = array(); $correct = 0; diff --git a/main/exercice/multiple_answer_combination.class.php b/main/exercice/multiple_answer_combination.class.php index baaed773f1..f95df6d1b0 100644 --- a/main/exercice/multiple_answer_combination.class.php +++ b/main/exercice/multiple_answer_combination.class.php @@ -44,13 +44,7 @@ class MultipleAnswerCombination extends Question { $nb_answers = isset($_POST['nb_answers']) ? $_POST['nb_answers'] : 2; $nb_answers += (isset($_POST['lessAnswers']) ? -1 : (isset($_POST['moreAnswers']) ? 1 : 0)); $obj_ex = $_SESSION['objExercise']; - $html=' -
      -
      - '.get_lang('Answers').'
      -
      -
      -
      '.get_lang('Number').' @@ -73,7 +67,7 @@ class MultipleAnswer extends Question { '.get_lang('Weighting').'
      + $html= '
      '; } $html .= ''; - - $form -> addElement ('html', $html); + $form -> addElement ('label', get_lang('Answers').'
      ', $html); $defaults = array(); $correct = 0; diff --git a/main/exercice/multiple_answer_true_false.class.php b/main/exercice/multiple_answer_true_false.class.php index feffa2a7f3..208dc28805 100644 --- a/main/exercice/multiple_answer_true_false.class.php +++ b/main/exercice/multiple_answer_true_false.class.php @@ -42,19 +42,7 @@ class MultipleAnswerTrueFalse extends Question { $nb_answers += (isset($_POST['lessAnswers']) ? -1 : (isset($_POST['moreAnswers']) ? 1 : 0)); $obj_ex = $_SESSION['objExercise']; - - $html.='
      -
      - '.get_lang('Answers').'
      -
      -
      '; - - $html2 ='
      -
      -
      -
      '; - - $form -> addElement ('html', $html2); + $form -> addElement ('html', '
      '.get_lang('Number').' @@ -66,8 +60,7 @@ class MultipleAnswerCombination extends Question { $html .=''.get_lang('Comment').'
      '); $renderer = & $form->defaultRenderer(); $defaults = array(); @@ -77,8 +65,7 @@ class MultipleAnswerTrueFalse extends Question { $form -> addElement('hidden', 'options_count', 3); $form -> addElement ('html', '
      '); - $form -> addElement ('html', '
    '); - + $html.=''; } $html .= ''; - $form -> addElement ('html', $html); - + $form -> addElement ('label', get_lang('Answers').'
    ', $html); $correct = 0; if (!empty($this -> id)) { diff --git a/main/exercice/unique_answer.class.php b/main/exercice/unique_answer.class.php index d7c7af5331..cc5d250b42 100644 --- a/main/exercice/unique_answer.class.php +++ b/main/exercice/unique_answer.class.php @@ -72,32 +72,26 @@ class UniqueAnswer extends Question { $feedback_title = ''; } - $html=' -
    -
    - '.get_lang('Answers').'
    -
    -
    -
    @@ -98,8 +85,7 @@ class MultipleAnswerTrueFalse extends Question { $html .=''.get_lang('Comment').'
    '.get_lang('Scenario').'
    - - - - - '.$comment_title.' - '.$feedback_title.' - - '; - - $form -> addElement ('html', $html); - + $html='
    - '.get_lang('Number').' - - '.get_lang('True').' - - '.get_lang('Answer').' - - '.get_lang('Weighting').' -
    + + + + + '.$comment_title.' + '.$feedback_title.' + + '; + + $form -> addElement ('label', get_lang('Answers').'
    ', $html); + $defaults = array(); $correct = 0; if(!empty($this -> id)) { @@ -219,7 +213,6 @@ class UniqueAnswer extends Question { $renderer->setElementTemplate('', 'lp'.$i); $renderer->setElementTemplate('', 'try'.$i); - $form -> addGroup($group, 'scenario', 'scenario'); $renderer->setGroupElementTemplate('
    {label}
    {element}
    ','scenario'); } @@ -228,7 +221,8 @@ class UniqueAnswer extends Question { } $form -> addElement ('html', '
    + '.get_lang('Number').' + + '.get_lang('True').' + + '.get_lang('Answer').' + + '.get_lang('Weighting').' +
    {error}
    {element}
    {error}
    {element}
    '); - $form -> addElement ('html', '
    '); + $form -> addElement ('html', '
    '); + $navigator_info = api_get_navigator(); global $text, $class, $show_quiz_edition; @@ -248,8 +242,8 @@ class UniqueAnswer extends Question { $renderer->setElementTemplate('{element} ','submitQuestion'); $renderer->setElementTemplate('{element} ','lessAnswers'); $renderer->setElementTemplate('{element} ','moreAnswers'); - - $form -> addElement ('html', ''); + + $form -> addElement ('html', ''); //We check the first radio button to be sure a radio button will be check if ($correct==0) { diff --git a/main/exercice/unique_answer_no_option.class.php b/main/exercice/unique_answer_no_option.class.php index 35d7d4a6cc..93e1660378 100644 --- a/main/exercice/unique_answer_no_option.class.php +++ b/main/exercice/unique_answer_no_option.class.php @@ -73,13 +73,7 @@ class UniqueAnswerNoOption extends Question { $feedback_title = ''.get_lang('Scenario').''; } - $html=' -
    -
    - '.get_lang('Answers').'
    -
    -
    - + $html='
    '; - - $form -> addElement ('html', $html); + $form -> addElement ('label', get_lang('Answers').'
    ', $html); $defaults = array(); $correct = 0; From cb922745eeac62a5ce4ba304fb72e433086d38b1 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Thu, 10 May 2012 14:57:33 +0200 Subject: [PATCH 118/128] Fixing hiding iframe --- main/newscorm/lp_view.php | 163 +++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 81 deletions(-) diff --git a/main/newscorm/lp_view.php b/main/newscorm/lp_view.php index 1548384a6b..bb138fca20 100644 --- a/main/newscorm/lp_view.php +++ b/main/newscorm/lp_view.php @@ -309,98 +309,99 @@ if (Database::num_rows($res_media) > 0) { while ($row_media= Database::fetch_array($res_media)) { if (!empty($row_media['audio'])) {$show_audioplayer = true; break;} } -} - +} ?> -
    - - -
    '.get_lang('Number').' @@ -96,8 +90,7 @@ class UniqueAnswerNoOption extends Question { '.get_lang('Weighting').'
    - - - - -
    - - - - - - -
    -
    +
    + +
    + + + - - - -
    -
    - get_preview_image()!='') { - $picture = getimagesize(api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/learning_path/images/'.$_SESSION['oLP']->get_preview_image()); - if($picture['1'] < 96) { $style = ' style="padding-top:'.((94 -$picture['1'])/2).'px;" '; } - $size = ($picture['0'] > 104 && $picture['1'] > 96 )? ' width="104" height="96" ': $style; - $my_path = api_get_path(WEB_COURSE_PATH).api_get_course_path().'/upload/learning_path/images/'.$_SESSION['oLP']->get_preview_image(); - echo ''; - } else { - echo Display :: display_icon('unknown_250_100.jpg'); - } - ?> + + + +
    +
    + get_preview_image()!='') { + $picture = getimagesize(api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/learning_path/images/'.$_SESSION['oLP']->get_preview_image()); + if($picture['1'] < 96) { $style = ' style="padding-top:'.((94 -$picture['1'])/2).'px;" '; } + $size = ($picture['0'] > 104 && $picture['1'] > 96 )? ' width="104" height="96" ': $style; + $my_path = api_get_path(WEB_COURSE_PATH).api_get_course_path().'/upload/learning_path/images/'.$_SESSION['oLP']->get_preview_image(); + echo ''; + } else { + echo Display :: display_icon('unknown_250_100.jpg'); + } + ?> +
    +
    + +
    + +
    +
    -
    - -
    - -
    + + +
    + get_author(); ?>
    -
    - - -
    - get_author(); ?> -
    - - -
    > - -
    - - - -
    -
    - get_html_toc(); ?> - - scorm_debug)) { //only show log ?> - -
    -
    -
    .
    + + +
    > + +
    + + + +
    +
    + get_html_toc(); ?> + + scorm_debug)) { //only show log ?> + +
    +
    +
    .
    +
    + +
    - -
    +
    - -
    - + - -
    -mode == 'fullscreen') { - echo ''; - } else { - echo ''; - } -?> -
    - + +
    + mode == 'fullscreen') { + echo ''; + } else { + echo ''; + } + ?> +
    +
    selectTitle(); - $questionDescription= $objQuestionTmp->selectDescription(); + $objQuestionTmp = Question::read($questionId); $questionWeighting = $objQuestionTmp->selectWeighting(); $answerType = $objQuestionTmp->selectType(); - $quesId = $objQuestionTmp->selectId(); + if ($show_results) { // display question category, if any @@ -492,11 +484,11 @@ foreach ($questionList as $questionId) { } } - if ($show_results) { - + if ($show_results) { echo ''; - if ($is_allowedToEdit) { + if ($is_allowedToEdit && $locked == false) { + echo ''; } - // display the last post name -// if ($row['user_id'] == '0') { -// $name = prepare4display($row['thread_poster_name']); -// } else { -// $name = api_get_person_name($row['firstname'], $row['lastname']); -// } if ($row['last_poster_user_id'] == '0') { $name = $row['poster_name']; @@ -404,7 +403,13 @@ if (is_array($threads)) { if ($origin != 'learnpath') { if (api_is_allowed_to_edit(false, true) && !(api_is_course_coach() && $current_forum['session_id'] != $_SESSION['id_session'])) { echo ''.Display::return_icon('edit.png', get_lang('Edit'), array(), ICON_SIZE_SMALL).''; - echo '".Display::return_icon('delete.png', get_lang('Delete'), array(), ICON_SIZE_SMALL).''; + + if (api_resource_is_locked_by_gradebook($row['thread_id'])) { + echo Display::return_icon('delete_na.png', get_lang('Delete'), array(), ICON_SIZE_SMALL); + } else { + echo '".Display::return_icon('delete.png', get_lang('Delete'), array(), ICON_SIZE_SMALL).''; + } + display_visible_invisible_icon('thread', $row['thread_id'], $row['visibility'], array('forum' => $my_forum, 'origin' => $origin, 'gidReq' => $_SESSION['toolgroup'])); display_lock_unlock_icon('thread', $row['thread_id'], $row['locked'], array('forum' => $my_forum, 'origin' => $origin, 'gidReq' => $_SESSION['toolgroup'])); echo ''.Display::return_icon('move.png', get_lang('MoveThread'), array(), ICON_SIZE_SMALL).''; diff --git a/main/gradebook/gradebook_add_link.php b/main/gradebook/gradebook_add_link.php index b01d76bef3..6e39e55356 100644 --- a/main/gradebook/gradebook_add_link.php +++ b/main/gradebook/gradebook_add_link.php @@ -93,7 +93,7 @@ if (isset($_GET['typeselected']) && $_GET['typeselected'] != '0') { $res1 = Database::query($sql1); $rowtit = Database::fetch_row($res1); $course_id = api_get_course_id(); - $sql_l='SELECT count(*) FROM '.$tbl_link.' WHERE c_id = '.$course_info['real_id'].' AND ref_id='.$addvalues['select_link'].' and course_code="'.$course_id.'" and type=5;'; + $sql_l='SELECT count(*) FROM '.$tbl_link.' WHERE ref_id='.$addvalues['select_link'].' and course_code="'.$course_id.'" and type=5;'; $res_l=Database::query($sql_l); $row=Database::fetch_row($res_l); if ( $row[0]==0 ) { diff --git a/main/gradebook/gradebook_edit_eval.php b/main/gradebook/gradebook_edit_eval.php index 0d5e0ed974..c1b4037699 100644 --- a/main/gradebook/gradebook_edit_eval.php +++ b/main/gradebook/gradebook_edit_eval.php @@ -17,6 +17,9 @@ api_block_anonymous_users(); block_students(); $evaledit = Evaluation :: load($_GET['editeval']); +if ($evaledit[0]->is_locked() && !api_is_platform_admin()) { + api_not_allowed(); +} $form = new EvalForm(EvalForm :: TYPE_EDIT, $evaledit[0], null, 'edit_eval_form',null,api_get_self() . '?editeval=' . Security::remove_XSS($_GET['editeval'])); if ($form->validate()) { $values = $form->exportValues(); diff --git a/main/gradebook/gradebook_edit_link.php b/main/gradebook/gradebook_edit_link.php index 7c3e17c0e8..73c7fc1f38 100644 --- a/main/gradebook/gradebook_edit_link.php +++ b/main/gradebook/gradebook_edit_link.php @@ -19,12 +19,17 @@ api_block_anonymous_users(); block_students(); $tbl_grade_links = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_LINK); //selected name of database -$course_id = get_course_id_by_link_id($_GET['editlink']); +$course_id = get_course_id_by_link_id($_GET['editlink']); $tbl_forum_thread = Database :: get_course_table(TABLE_FORUM_THREAD); $tbl_work = Database :: get_course_table(TABLE_STUDENT_PUBLICATION); $tbl_attendance = Database :: get_course_table(TABLE_ATTENDANCE); $linkarray = LinkFactory :: load($_GET['editlink']); $link = $linkarray[0]; + +if ($link->is_locked() && !api_is_platform_admin()) { + api_not_allowed(); +} + $linkcat = isset($_GET['selectcat']) ? Security::remove_XSS($_GET['selectcat']):''; $linkedit = isset($_GET['editlink']) ? Security::remove_XSS($_GET['editlink']):''; @@ -53,23 +58,25 @@ if ($form->validate()) { $link->save(); //Update weight for attendance - $sql = 'SELECT ref_id FROM '.$tbl_grade_links.' WHERE c_id = '.$course_id.' AND id = '.intval($_GET['editlink']).' AND type='.LINK_ATTENDANCE; + $sql = 'SELECT ref_id FROM '.$tbl_grade_links.' WHERE id = '.intval($_GET['editlink']).' AND type='.LINK_ATTENDANCE; $rs_attendance = Database::query($sql); if (Database::num_rows($rs_attendance) > 0) { $row_attendance = Database::fetch_array($rs_attendance); $attendance_id = $row_attendance['ref_id']; - $upd_attendance = 'UPDATE '.$tbl_attendance.' SET attendance_weight ='.floatval($values['weight']).' WHERE c_id = '.$course_id.' AND id = '.intval($attendance_id); + $upd_attendance = 'UPDATE '.$tbl_attendance.' SET attendance_weight ='.floatval($final_weight).' WHERE c_id = '.$course_id.' AND id = '.intval($attendance_id); Database::query($upd_attendance); } //Update weight into forum thread - $sql_t = 'UPDATE '.$tbl_forum_thread.' SET thread_weight='.$values['weight'].' - WHERE c_id = '.$course_id.' AND thread_id=(SELECT ref_id FROM '.$tbl_grade_links.' WHERE id='.intval($_GET['editlink']).' and type=5 AND c_id = '.$course_id.' ) '; + $sql_t = 'UPDATE '.$tbl_forum_thread.' SET thread_weight='.$final_weight.' + WHERE c_id = '.$course_id.' AND thread_id=(SELECT ref_id FROM '.$tbl_grade_links.' WHERE id='.intval($_GET['editlink']).' and type=5) '; + Database::query($sql_t); //Update weight into student publication(work) - $sql_t = 'UPDATE '.$tbl_work.' SET weight='.$values['weight'].' - WHERE c_id = '.$course_id.' AND id = (SELECT ref_id FROM '.$tbl_grade_links.' WHERE c_id = '.$course_id.' AND id='.intval($_GET['editlink'] ).' AND type=3 )'; + $sql_t = 'UPDATE '.$tbl_work.' SET weight='.$final_weight.' + WHERE c_id = '.$course_id.' AND id = (SELECT ref_id FROM '.$tbl_grade_links.' WHERE id='.intval($_GET['editlink'] ).' AND type=3 )'; + Database::query($sql_t); header('Location: '.$_SESSION['gradebook_dest'].'?linkedited=&selectcat=' . $link->get_category_id()); exit; @@ -79,8 +86,7 @@ $interbreadcrumb[] = array ('url' => Security::remove_XSS($_SESSION['gradebook_d $htmlHeadXtra[] = ''; + +'; // Flag to allow for anonymous user - needs to be set before global.inc.php. $use_anonymous = true; diff --git a/main/survey/create_new_survey.php b/main/survey/create_new_survey.php index aae0d26c83..2df123fd9b 100644 --- a/main/survey/create_new_survey.php +++ b/main/survey/create_new_survey.php @@ -97,8 +97,10 @@ if ($_GET['action'] == 'edit' && isset($survey_id) && is_numeric($survey_id)) { $defaults['survey_id'] = $survey_id; $defaults['anonymous'] = $survey_data['anonymous']; - $gradebook_link_id = is_resource_in_course_gradebook($course_id, $gradebook_link_type, $survey_id, $session_id); - if ($gradebook_link_id) { + $link_info = is_resource_in_course_gradebook($course_id, $gradebook_link_type, $survey_id, $session_id); + $gradebook_link_id = $link_info['id']; + + if ($link_info) { if ($sql_result_array = Database::fetch_array(Database::query('SELECT weight FROM '.$table_gradebook_link.' WHERE id='.$gradebook_link_id))) { $defaults['survey_qualify_gradebook'] = $gradebook_link_id; $defaults['survey_weight'] = number_format($sql_result_array['weight'], 2, '.', ''); @@ -303,9 +305,10 @@ if ($form->validate()) { $date = time(); // TODO: Maybe time zones implementation is needed here. $visible = 1; // 1 = visible - $gradebook_link_id = is_resource_in_course_gradebook($course_id, $gradebook_link_type, $survey_id, $session_id); + $link_info = is_resource_in_course_gradebook($course_id, $gradebook_link_type, $survey_id, $session_id); + $gradebook_link_id = $link_info['id']; if (!$gradebook_link_id) { - add_resource_to_course_gradebook($course_id, $gradebook_link_type, $survey_id, $title_gradebook, $survey_weight, $max_score, $description_gradebook, time(), 1, $session_id); + add_resource_to_course_gradebook($course_id, $gradebook_link_type, $survey_id, $title_gradebook, $survey_weight, $max_score, $description_gradebook, 1, $session_id); } else { Database::query('UPDATE '.$table_gradebook_link.' SET weight='.$survey_weight.' WHERE id='.$gradebook_link_id); } diff --git a/main/work/work.lib.php b/main/work/work.lib.php index 7b6aad21bc..b9229c0a03 100644 --- a/main/work/work.lib.php +++ b/main/work/work.lib.php @@ -364,7 +364,9 @@ function display_student_publications_list($id, $link_target_parameter, $dateFor } if (empty($my_folder_data)) { - $work_in_gradebook_link_id = is_resource_in_course_gradebook(api_get_course_id(), 3 , $id, api_get_session_id()); + $link_info = is_resource_in_course_gradebook(api_get_course_id(), 3 , $id, api_get_session_id()); + $work_in_gradebook_link_id = $link_info['id']; + if ($work_in_gradebook_link_id) { if ($is_allowed_to_edit) if (intval($my_folder_data['qualification']) == 0) { @@ -466,7 +468,9 @@ function display_student_publications_list($id, $link_target_parameter, $dateFor $is_assignment = $row['has_properties']; $id2 = $row['id']; //work id - if ($is_allowed_to_edit) { + $locked = api_resource_is_locked_by_gradebook($id2); + + if ($is_allowed_to_edit && $locked == false) { // form edit directory if (!empty($edit_dir) && $edit_dir == $id2) { @@ -486,16 +490,11 @@ function display_student_publications_list($id, $link_target_parameter, $dateFor $form_folder->add_html_editor('description', get_lang('Description'), false, false, array('ToolbarSet' => 'work', 'Width' => '80%', 'Height' => '200')); $there_is_a_end_date = false; - $form_folder -> addElement('html', ' '); + '); $form_folder->addElement('html', ''; break; - case 'Stylesheets': + case 'Stylesheets': // Displaying the extensions: Stylesheets. handle_stylesheets(); break; From 9fdf61cc7b94593b67dfbeebf5c8b0d324389400 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Thu, 10 May 2012 19:32:17 +0200 Subject: [PATCH 128/128] Adding PDF export (wokrs but not finished yet) see BT#4080 --- main/gradebook/gradebook_flatview.php | 11 +- main/gradebook/index.php | 8 ++ .../lib/flatview_data_generator.class.php | 104 ++++++++---------- .../gradebook/lib/gradebook_functions.inc.php | 27 +++-- 4 files changed, 82 insertions(+), 68 deletions(-) diff --git a/main/gradebook/gradebook_flatview.php b/main/gradebook/gradebook_flatview.php index 1ffb6c5d62..3f9b3ac45a 100644 --- a/main/gradebook/gradebook_flatview.php +++ b/main/gradebook/gradebook_flatview.php @@ -99,13 +99,18 @@ $flatviewtable = new FlatViewTable($cat[0], $users, $alleval, $alllinks, true, $ $parameters=array('selectcat'=>intval($_GET['selectcat'])); $flatviewtable->set_additional_parameters($parameters); +if (isset($_GET['export_pdf']) && $_GET['export_pdf'] == 'category') { + $params = array(); + $params['only_total_category'] = true; + export_pdf_flatview($cat, $users, $alleval, $alllinks, $params); +} + if (isset($_GET['exportpdf'])) { $interbreadcrumb[] = array ( 'url' => api_get_self().'?selectcat=' . Security::remove_XSS($_GET['selectcat']), 'name' => get_lang('FlatView') ); - - $export_pdf_form = new DataForm(DataForm::TYPE_EXPORT_PDF, 'export_pdf_form', null, api_get_self().'?exportpdf=&offset='.intval($_GET['offset']).'&selectcat='.intval($_GET['selectcat']), '_blank', ''); + $export_pdf_form = new DataForm(DataForm::TYPE_EXPORT_PDF, 'export_pdf_form', null, api_get_self().'?exportpdf=&offset='.intval($_GET['offset']).'&selectcat='.intval($_GET['selectcat']), '_blank', ''); if ($export_pdf_form->validate()) { $params = $export_pdf_form->exportValues(); @@ -116,7 +121,7 @@ if (isset($_GET['exportpdf'])) { } if (isset ($_GET['print'])) { - $printable_data = get_printable_data ($cat[0], $users,$alleval, $alllinks); + $printable_data = get_printable_data ($cat[0], $users, $alleval, $alllinks); echo print_table($printable_data[1],$printable_data[0], get_lang('FlatView'), $cat[0]->get_name()); exit; } diff --git a/main/gradebook/index.php b/main/gradebook/index.php index 585a21f16f..543183c5f0 100644 --- a/main/gradebook/index.php +++ b/main/gradebook/index.php @@ -57,6 +57,14 @@ function lock_confirmation() { } } +function unlock_confirmation() { + if (confirm("' . get_lang('ConfirmToUnlockElement') . '?")) { + return true; + } else { + return false; + } +} + $(document).ready(function() { diff --git a/main/gradebook/lib/flatview_data_generator.class.php b/main/gradebook/lib/flatview_data_generator.class.php index 042ab53a67..d60fc26bfe 100644 --- a/main/gradebook/lib/flatview_data_generator.class.php +++ b/main/gradebook/lib/flatview_data_generator.class.php @@ -23,18 +23,18 @@ class FlatViewDataGenerator private $evals; private $links; private $evals_links; + public $params; public $category = array(); /** * Constructor */ - public function FlatViewDataGenerator ($users= array (), $evals= array (), $links= array ()) { + public function FlatViewDataGenerator ($users = array(), $evals = array(), $links = array(), $params = array()) { $this->users = (isset($users) ? $users : array()); $this->evals = (isset($evals) ? $evals : array()); $this->links = (isset($links) ? $links : array()); $this->evals_links = array_merge($this->evals, $this->links); - - + $this->params = $params; } /** @@ -89,17 +89,16 @@ class FlatViewDataGenerator foreach ($allcat as $sub_cat) { $headers[] = Display::url($sub_cat->get_name(), api_get_self().'?selectcat='.$sub_cat->get_id()).' '.$sub_cat->get_weight().' % '; } - } else { - for ($count=0; ($count < $items_count ) && ($items_start + $count < count($this->evals_links)); $count++) { - $item = $this->evals_links[$count + $items_start]; + } else { + if (!isset($this->params['only_total_category'])) { + for ($count=0; ($count < $items_count ) && ($items_start + $count < count($this->evals_links)); $count++) { + $item = $this->evals_links[$count + $items_start]; - //$headers[] = $item->get_name().'
    '.get_lang('Max').' '.$this->get_max_result_by_link($count + $items_start).' '; - $sub_cat_percentage = $sum_categories_weight_array[$item->get_category_id()]; + //$headers[] = $item->get_name().'
    '.get_lang('Max').' '.$this->get_max_result_by_link($count + $items_start).' '; + $sub_cat_percentage = $sum_categories_weight_array[$item->get_category_id()]; - $weight = round($item->get_weight()/($sub_cat_percentage) * $sub_cat_percentage/$this->category->get_weight() *100, 2); - $headers[] = $item->get_name().' '.$weight.' % '; - if ($show_detail) { - //$headers[] = $item->get_name().' ('.get_lang('Detail').')'; + $weight = round($item->get_weight()/($sub_cat_percentage) * $sub_cat_percentage/$this->category->get_weight() *100, 2); + $headers[] = $item->get_name().' '.$weight.' % '; } } } @@ -107,17 +106,11 @@ class FlatViewDataGenerator return $headers; } - function get_max_result_by_link($id) { - $usertable = array(); - $items_count = count ($this->evals) + count ($this->links); - $item_value = 0; - $item_total = 0; + function get_max_result_by_link($id) { $max = 0; foreach ($this->users as $user) { $item = $this->evals_links [$id]; $score = $item->calc_score($user[0]); - $divide=( ($score[1])==0 ) ? 1 : $score[1]; - //$item_value = round($score[0]/$divide*$item->get_weight(),2); if ($score[0] > $max) { $max = $score[0]; } @@ -160,7 +153,7 @@ class FlatViewDataGenerator } if ($users_count < 0) { $users_count = 0; - } + } if (!isset($items_count)) { $items_count = count ($this->evals) + count ($this->links) - $items_start; } @@ -186,8 +179,8 @@ class FlatViewDataGenerator // select the requested users $selected_users = array_slice($usertable, $users_start, $users_count); + // generate actual data array - $scoredisplay = ScoreDisplay :: instance(); $data = array (); @@ -222,7 +215,7 @@ class FlatViewDataGenerator if (empty($grade_model_id) || $grade_model_id == -1) { $use_grade_model = false; } - + foreach ($selected_users as $user) { $row = array (); $row[] = $user_id = $user[0]; //user id @@ -258,12 +251,13 @@ class FlatViewDataGenerator } $temp_score = $scoredisplay->display_score($score, SCORE_DIV_PERCENT, SCORE_ONLY_SCORE); - - if (!$show_all) { - $row[] = $temp_score.' '; - } else { - $row[] = $temp_score; - } + if (!isset($this->params['only_total_category'])) { + if (!$show_all) { + $row[] = $temp_score.' '; + } else { + $row[] = $temp_score; + } + } $item_value_total +=$item_value; } if ($convert_using_the_global_weight) { @@ -271,13 +265,10 @@ class FlatViewDataGenerator } } else { for ($count=0; ($count < $items_count ) && ($items_start + $count < count($this->evals_links)); $count++) { - $item = $this->evals_links[$count + $items_start]; + $item = $this->evals_links[$count + $items_start]; $score = $item->calc_score($user_id); - $debug = false; - if ($user_id == 11) { - $debug = true; - } - $divide = ( ($score[1])==0 ) ? 1 : $score[1]; + $divide = ( ($score[1])==0 ) ? 1 : $score[1]; + //sub cat weight $sub_cat_percentage = $sum_categories_weight_array[$item->get_category_id()]; @@ -287,10 +278,7 @@ class FlatViewDataGenerator if ($this->category->get_parent_id() == 0 ) { $item_value = $item_value; $item_value =round($score[0]/$divide*$item->get_weight(),2); - } else { - // if ($debug) var_dump($item_value); - //$percentage = round($item->get_weight()/($sub_cat_percentage) * $sub_cat_percentage/$this->category->get_weight(), 2); - //if ($debug) var_dump($item->get_weight().' '.$item_value .' -'.$sub_cat_percentage); + } else { $item_value = $item_value*$item->get_weight(); $item_value = $main_weight*$item_value/$item->get_weight(); } @@ -299,28 +287,28 @@ class FlatViewDataGenerator $temp_score = $scoredisplay->display_score($score, SCORE_DIV_PERCENT, SCORE_ONLY_SCORE); - //if ($debug) var_dump($temp_score); - - if (!$show_all) { - //$row[] = $scoredisplay->display_score($score,SCORE_DIV_PERCENT); - if (in_array($item->get_type() , array(LINK_EXERCISE, LINK_DROPBOX, LINK_STUDENTPUBLICATION, - LINK_LEARNPATH, LINK_FORUM_THREAD, LINK_ATTENDANCE,LINK_SURVEY))) { - if (!empty($score[0])) { - $row[] = $temp_score.' '; + if (!isset($this->params['only_total_category'])) { + if (!$show_all) { + //$row[] = $scoredisplay->display_score($score,SCORE_DIV_PERCENT); + if (in_array($item->get_type() , array(LINK_EXERCISE, LINK_DROPBOX, LINK_STUDENTPUBLICATION, + LINK_LEARNPATH, LINK_FORUM_THREAD, LINK_ATTENDANCE,LINK_SURVEY))) { + if (!empty($score[0])) { + $row[] = $temp_score.' '; + } else { + $row[] = ''; + } + //$row[] = $scoredisplay->display_score($score,SCORE_DIV_PERCENT, SCORE_ONLY_SCORE); } else { - $row[] = ''; - } - //$row[] = $scoredisplay->display_score($score,SCORE_DIV_PERCENT, SCORE_ONLY_SCORE); + //$row[] = $scoredisplay->display_score($score,SCORE_DIV_PERCENT); + //$row[] = $score[0]; + $row[] = $temp_score.' '; + } } else { - //$row[] = $scoredisplay->display_score($score,SCORE_DIV_PERCENT); - //$row[] = $score[0]; - $row[] = $temp_score.' '; - } - } else { - //$row[] = $scoredisplay->display_score($score, SCORE_DECIMAL); - $row[] = $temp_score; - //$row[] = $scoredisplay->display_score($score, SCORE_DIV_PERCENT); - } + //$row[] = $scoredisplay->display_score($score, SCORE_DECIMAL); + $row[] = $temp_score; + //$row[] = $scoredisplay->display_score($score, SCORE_DIV_PERCENT); + } + } $item_value_total +=$item_value; } $item_total = $main_weight; diff --git a/main/gradebook/lib/gradebook_functions.inc.php b/main/gradebook/lib/gradebook_functions.inc.php index 735be883a3..57e41339c1 100644 --- a/main/gradebook/lib/gradebook_functions.inc.php +++ b/main/gradebook/lib/gradebook_functions.inc.php @@ -179,7 +179,7 @@ function build_edit_icons_cat($cat, $selectcat) { if (api_get_setting('gradebook_locking_enabled') == 'true') { if ($cat->is_locked()) { if (api_is_platform_admin()) { - $modify_icons .= ' '.Display::return_icon('unlock.png', get_lang('Unlock'),'',ICON_SIZE_SMALL).''; + $modify_icons .= ' '.Display::return_icon('unlock.png', get_lang('Unlock'),'',ICON_SIZE_SMALL).''; } else { $modify_icons .= ' '.Display::return_icon('unlock_na.png', get_lang('GradebookLockedAlert'),'',ICON_SIZE_SMALL).''; } @@ -189,7 +189,7 @@ function build_edit_icons_cat($cat, $selectcat) { } //PDF - $modify_icons .= ' '.Display::return_icon('pdf.png', get_lang('ExportToPDF'),'',ICON_SIZE_SMALL).''; + $modify_icons .= ' '.Display::return_icon('pdf.png', get_lang('ExportToPDF'),'',ICON_SIZE_SMALL).''; if (empty($grade_model_id) || $grade_model_id == -1) { if ($cat->is_locked() && !api_is_platform_admin()) { @@ -416,8 +416,9 @@ function get_table_type_course($type) { return Database::get_course_table($table_evaluated[$type][0]); } -function get_printable_data($cat, $users, $alleval, $alllinks) { - $datagen = new FlatViewDataGenerator ($users, $alleval, $alllinks); +function get_printable_data($cat, $users, $alleval, $alllinks, $params) { + $datagen = new FlatViewDataGenerator ($users, $alleval, $alllinks, $params); + $offset = isset($_GET['offset']) ? $_GET['offset'] : '0'; $offset = intval($offset); @@ -426,7 +427,7 @@ function get_printable_data($cat, $users, $alleval, $alllinks) { $count = (($offset + 10) > $datagen->get_total_items_count()) ? ($datagen->get_total_items_count() - $offset) : LIMIT; $header_names = $datagen->get_header_names($offset, $count, true); - $data_array = $datagen->get_data(FlatViewDataGenerator :: FVDG_SORT_LASTNAME, 0, null, $offset, $count, true,true); + $data_array = $datagen->get_data(FlatViewDataGenerator :: FVDG_SORT_LASTNAME, 0, null, $offset, $count, true, true); $newarray = array(); foreach ($data_array as $data) { @@ -693,7 +694,7 @@ function load_gradebook_select_in_tool($form) { function export_pdf_flatview($cat, $users, $alleval, $alllinks, $params = array()) { // Beginning of PDF report creation - $printable_data = get_printable_data($cat[0], $users, $alleval, $alllinks); + $printable_data = get_printable_data($cat[0], $users, $alleval, $alllinks, $params); // Reading report's CSS $css_file = api_get_path(SYS_CODE_PATH).'gradebook/print.css'; @@ -731,7 +732,19 @@ function export_pdf_flatview($cat, $users, $alleval, $alllinks, $params = array( } } - $html .= '

    '.get_lang('FlatView').'

    '; + $grade_model_id = $cat[0]->get_grade_model_id(); + $use_grade_model = true; + if (empty($grade_model_id) || $grade_model_id == -1) { + $use_grade_model = false; + } + + //var_dump($use_grade_model);exit; + + if ($use_grade_model) { + $html .= '

    '.get_lang('FlatView').'

    '; + } else { + $html .= '

    '.get_lang('FlatView').'

    '; + } $html .= '
    '; $name = "fckdiv".$questionId; $marksname = "marksName".$questionId; @@ -536,6 +528,7 @@ foreach ($questionList as $questionId) { $feedback_form->setDefaults(${user.$questionId}); $feedback_form->display(); echo ''; + } else { $comnt = get_comments($id,$questionId); echo '

    '; @@ -616,7 +609,7 @@ if (is_array($arrid) && is_array($arrmarks)) { $marksid = implode(",",$arrmarks); } -if ($is_allowedToEdit) { +if ($is_allowedToEdit && $locked == false) { if (in_array($origin, array('tracking_course','user_course','correct_exercise_in_lp'))) { echo ' '; //echo ' '; diff --git a/main/exercice/question.class.php b/main/exercice/question.class.php index 3a2fa0adc2..c6241ea088 100644 --- a/main/exercice/question.class.php +++ b/main/exercice/question.class.php @@ -1278,8 +1278,8 @@ abstract class Question foreach ($question_type_custom_list as $i=>$a_type) { // include the class of the type require_once($a_type[0]); - // get the picture of the type and the langvar which describes it - $img = $explanation = ''; + // get the picture of the type and the langvar which describes it + $img = $explanation = ''; eval('$img = '.$a_type[1].'::$typePicture;'); eval('$explanation = get_lang('.$a_type[1].'::$explanationLangVar);'); echo '
  • '; diff --git a/main/forum/editpost.php b/main/forum/editpost.php index 6e5aed978a..f212f6b2f4 100644 --- a/main/forum/editpost.php +++ b/main/forum/editpost.php @@ -25,7 +25,7 @@ /* INIT SECTION */ // Language files that need to be included. -$language_file = array ('forum', 'group'); +$language_file = array ('forum', 'group', 'gradebook'); // Including the global initialization file. require_once '../inc/global.inc.php'; @@ -81,6 +81,8 @@ $current_forum = get_forum_information($_GET['forum']); // Note: This h $current_forum_category = get_forumcategory_information($current_forum['forum_category']); $current_post = get_post_information($_GET['post']); +block_course_item_locked_by_gradebook($_GET['thread']); + /* Header and Breadcrumbs */ if (isset($_SESSION['gradebook'])) { @@ -211,9 +213,10 @@ if (!empty($values) and isset($_POST['SubmitPost'])) { $weight_calification = $values['weight_calification']; $description = ''; $session_id = api_get_session_id(); - $link_id = is_resource_in_course_gradebook(api_get_course_id(), 5, $id, $session_id); - if (!$link_id) { - add_resource_to_course_gradebook(api_get_course_id(), 5, $id, $title_gradebook, $weight_calification, $value_calification, $description, time(), 1, api_get_session_id()); + $link_info = is_resource_in_course_gradebook(api_get_course_id(), 5, $id, $session_id); + $link_id = $link_info['id']; + if (!$link_info) { + add_resource_to_course_gradebook($values['category_id'], api_get_course_id(), 5, $id, $title_gradebook, $weight_calification, $value_calification, $description, 1, api_get_session_id()); } else { Database::query('UPDATE '.$table_link.' SET weight='.$weight_calification.' WHERE id='.$link_id.''); } diff --git a/main/forum/forumfunction.inc.php b/main/forum/forumfunction.inc.php index 9aa7076f08..a5a089ea70 100644 --- a/main/forum/forumfunction.inc.php +++ b/main/forum/forumfunction.inc.php @@ -84,9 +84,9 @@ function handle_forum_and_forumcategories($lp_id = null) { for ($i = 0; $i < count($list_threads); $i++) { delete_forum_forumcategory_thread('thread', $list_threads[$i]['thread_id']); require_once api_get_path(SYS_CODE_PATH).'gradebook/lib/gradebook_functions.inc.php'; - $link_id = is_resource_in_course_gradebook(api_get_course_id(), 5 , intval($list_threads[$i]['thread_id']), api_get_session_id()); - if ($link_id !== false) { - remove_resource_from_course_gradebook($link_id); + $link_info = is_resource_in_course_gradebook(api_get_course_id(), 5 , intval($list_threads[$i]['thread_id']), api_get_session_id()); + if ($link_info !== false) { + remove_resource_from_course_gradebook($link_info['id']); } } $return_message = delete_forum_forumcategory_thread($_GET['content'], $_GET['id']); @@ -1905,9 +1905,7 @@ function store_thread($values) { $maxqualify = $values['numeric_calification']; $weigthqualify = $values['weight_calification']; $resourcedescription = ''; - $date = time(); - //is_resource_in_course_gradebook($course_code, $resource_type, $resource_id); - add_resource_to_course_gradebook($coursecode, $resourcetype, $resourceid, $resourcename, $weigthqualify, $maxqualify, $resourcedescription, $date, 0, api_get_session_id()); + add_resource_to_course_gradebook($values['category_id'], $coursecode, $resourcetype, $resourceid, $resourcename, $weigthqualify, $maxqualify, $resourcedescription, 0, api_get_session_id()); } api_item_property_update($_course, TOOL_FORUM_THREAD, $last_thread_id, 'ForumThreadAdded', api_get_user_id()); @@ -2006,8 +2004,7 @@ function show_add_post_form($action = '', $id = '', $form_values = '') { global $forum_setting; global $current_forum; global $_user; - global $origin; - global $charset; + global $origin; $gradebook = Security::remove_XSS($_GET['gradebook']); // Setting the class and text of the form title and submit button. @@ -2065,6 +2062,9 @@ function show_add_post_form($action = '', $id = '', $form_values = '') { if( (api_is_course_admin() || api_is_course_coach() || api_is_course_tutor()) && !($my_thread) ) { + //Loading gradebook select + load_gradebook_select_in_tool($form); + // Thread qualify $form->applyFilter('numeric_calification', 'html_filter'); $form->addElement('checkbox', 'thread_qualify_gradebook', '', get_lang('QualifyThreadGradebook'), 'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"'); @@ -2097,10 +2097,7 @@ function show_add_post_form($action = '', $id = '', $form_values = '') { $form->addElement('textarea', 'file_comment', get_lang('FileComment'), array ('rows' => 4, 'cols' => 34)); $form->applyFilter('file_comment', 'html_filter'); $form->addElement('html', ''); - $userid = api_get_user_id(); - $info = api_get_user_info($userid); - $courseid = api_get_course_id(); - + $form->addElement('style_submit_button', 'SubmitPost', $text, 'class="'.$class.'"'); $form->add_real_progress_bar('DocumentUpload', 'user_upload'); @@ -2496,17 +2493,26 @@ function show_edit_post_form($current_post, $current_thread, $current_forum, $fo $form->addElement('static', 'Group', ''.get_lang('AlterQualifyThread').''); $form->applyFilter('numeric_calification', 'html_filter'); $form->addElement('checkbox', 'thread_qualify_gradebook', '', get_lang('QualifyThreadGradebook'), 'onclick="javascript: if(this.checked){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"'); - $defaults['thread_qualify_gradebook'] = is_resource_in_course_gradebook(api_get_course_id(), 5, $_GET['thread'], api_get_session_id()); + $link_info = is_resource_in_course_gradebook(api_get_course_id(), 5, $_GET['thread'], api_get_session_id()); + + if (!empty($link_info)) { + $defaults['thread_qualify_gradebook'] = true; + $defaults['category_id'] = $link_info['category_id']; + } if (!empty($defaults['thread_qualify_gradebook'])) { $form -> addElement('html', '
    '); } else { $form -> addElement('html', ''); } @@ -2529,11 +2535,10 @@ function show_edit_post_form($current_post, $current_thread, $current_forum, $fo $form->addElement('checkbox', 'remove_attach', null, get_lang('DeleteAttachmentFile')); } // User upload - $form->addElement('html', '
    '.$message.'


    '); + $form->addElement('label', $message); $form->addElement('file', 'user_upload', get_lang('FileName'), ''); $form->addElement('textarea', 'file_comment', get_lang('FileComment'), array ('rows' => 4, 'cols' => 34)); - $form->applyFilter('file_comment', 'html_filter'); - $form->addElement('html', '


    '); + $form->applyFilter('file_comment', 'html_filter'); if ($current_forum['allow_attachments'] == '1' || api_is_allowed_to_edit(null, true)) { if (empty($form_values) && !isset($_POST['SubmitPost'])) { //edit_added_resources('forum_post', $current_post['post_id']); @@ -2550,9 +2555,7 @@ function show_edit_post_form($current_post, $current_thread, $current_forum, $fo $defaults['post_notification'] = true; } - if (!empty($form_values)) { - //$defaults['post_title']=Security::remove_XSS($form_values['post_title']); - //$defaults['post_text']=Security::remove_XSS($form_values['post_text']); + if (!empty($form_values)) { $defaults['post_notification'] = Security::remove_XSS($form_values['post_notification']); $defaults['thread_sticky'] = Security::remove_XSS($form_values['thread_sticky']); } @@ -2631,18 +2634,20 @@ function store_edit_post($values) { if (api_is_course_admin() == true) { $ccode = api_get_course_id(); $sid = api_get_session_id(); - $link_id = is_resource_in_course_gradebook($ccode, 5, $values['thread_id'], $sid); + + + $link_info = is_resource_in_course_gradebook($ccode, 5, $values['thread_id'], $sid); + $link_id = $link_info['id']; + $thread_qualify_gradebook = isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : null; if ($thread_qualify_gradebook != 1) { - if ($link_id !== false) { + if ($link_info !== false) { remove_resource_from_course_gradebook($link_id); } } else { - if ($link_id === false && !$_GET['thread']) { - //$date_in_gradebook = date('Y-m-d H:i:s'); - $date_in_gradebook = null; + if ($link_info === false && !$_GET['thread']) { $weigthqualify = $values['weight_calification']; - add_resource_to_course_gradebook($ccode, 5, $values['thread_id'], Database::escape_string(stripslashes($values['calification_notebook_title'])), $weigthqualify, $values['numeric_calification'], null, $date_in_gradebook, 0, $sid); + add_resource_to_course_gradebook($values['category_id'], $ccode, 5, $values['thread_id'], Database::escape_string(stripslashes($values['calification_notebook_title'])), $weigthqualify, $values['numeric_calification'], null, 0, $sid); } } } @@ -3359,9 +3364,9 @@ function prepare4display($input) { if (!isset($search)) { if (isset($_POST['search_term'])) { - $search = html_filter($_POST['search_term']); // No html at all. + $search = $_POST['search_term']; // No html at all. } elseif (isset($_GET['search'])) { - $search = html_filter($_GET['search']); + $search = $_GET['search']; } else { $search = ''; } diff --git a/main/forum/newthread.php b/main/forum/newthread.php index 5baab78265..afb74e752e 100644 --- a/main/forum/newthread.php +++ b/main/forum/newthread.php @@ -89,7 +89,6 @@ if (!empty($_GET['gidReq'])) { api_session_register('toolgroup'); } - /* Is the user allowed here? */ // The user is not allowed here if: @@ -121,7 +120,6 @@ if ($current_forum['forum_of_group'] != 0) { api_not_allowed(); } } - $session_toolgroup = 0; if ($origin == 'group') { $session_toolgroup = intval($_SESSION['toolgroup']); @@ -146,8 +144,6 @@ if (isset($_POST['add_resources']) AND $_POST['add_resources'] == get_lang('Reso header('Location: ../resourcelinker/resourcelinker.php'); } - - /* Header */ if ($origin == 'learnpath') { @@ -163,36 +159,9 @@ handle_forum_and_forumcategories(); // Action links echo ''; -/* Display Forum Category and the Forum information */ -/* -echo "\n"; - -if ($origin != 'learnpath') { - echo "\n\n"; - echo "\n"; -} -echo '
    "; - - echo ''.prepare4display($current_forum['forum_title']).''; - - if (!empty($current_forum['forum_comment'])) { - echo '
    '.prepare4display($current_forum['forum_comment']).''; - } - - if (!empty($current_forum_category['cat_title'])) { - echo '
    '.prepare4display($current_forum_category['cat_title'])."
    "; - } - echo "
    '; -*/ $values = show_add_post_form('newthread', '', isset($_SESSION['formelements']) ? $_SESSION['formelements'] : null); if (!empty($values) && isset($values['SubmitPost'])) { diff --git a/main/forum/viewforum.php b/main/forum/viewforum.php index f9c98478fd..4db9b4701d 100644 --- a/main/forum/viewforum.php +++ b/main/forum/viewforum.php @@ -141,12 +141,17 @@ if (($my_action == 'lock' OR $my_action == 'unlock') AND isset($_GET['content']) } // Deleting. if ($my_action == 'delete' AND isset($_GET['content']) AND isset($_GET['id']) AND api_is_allowed_to_edit(false, true) && api_is_allowed_to_session_edit(false, true)) { - $message = delete_forum_forumcategory_thread($_GET['content'], $_GET['id']); // Note: This has to be cleaned first. - // Delete link - require_once api_get_path(SYS_CODE_PATH).'gradebook/lib/gradebook_functions.inc.php'; - $link_id = is_resource_in_course_gradebook(api_get_course_id(), 5 , intval($_GET['id']), api_get_session_id()); - if ($link_id !== false) { - remove_resource_from_course_gradebook($link_id); + + $locked = api_resource_is_locked_by_gradebook($_GET['id']); + if ($locked == false) { + $message = delete_forum_forumcategory_thread($_GET['content'], $_GET['id']); // Note: This has to be cleaned first. + // Delete link + require_once api_get_path(SYS_CODE_PATH).'gradebook/lib/gradebook_functions.inc.php'; + $link_info = is_resource_in_course_gradebook(api_get_course_id(), 5 , intval($_GET['id']), api_get_session_id()); + $link_id = $link_info['id']; + if ($link_info !== false) { + remove_resource_from_course_gradebook($link_id); + } } } // Moving. @@ -357,12 +362,6 @@ if (is_array($threads)) { } else { echo '
  • '.Display::tag('span', api_get_person_name($row['firstname'], $row['lastname']), array("title"=>api_htmlentities($poster_username, ENT_QUOTES))).'
    '; $html .= '';