From 40c0c52465bd9e8fed49edaad1de954d6547be08 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Wed, 29 Jun 2016 12:21:41 +0200 Subject: [PATCH 1/6] [DoctrineBridge] fixed default parameter value in UniqueEntityValidator --- .../Tests/Fixtures/AssociationEntity2.php | 45 +++++++++++++++++++ .../Constraints/UniqueEntityValidatorTest.php | 40 +++++++++++++++++ .../Constraints/UniqueEntityValidator.php | 4 ++ 3 files changed, 89 insertions(+) create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Fixtures/AssociationEntity2.php diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/AssociationEntity2.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/AssociationEntity2.php new file mode 100644 index 0000000000..a0a7612458 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/AssociationEntity2.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Fixtures; + +use Doctrine\ORM\Mapping as ORM; + +/** + * @ORM\Entity + */ +class AssociationEntity2 +{ + /** + * @var int + * @ORM\Id @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + private $id; + + /** + * @ORM\ManyToOne(targetEntity="SingleIntIdNoToStringEntity") + * + * @var \Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity + */ + public $single; + + /** + * @ORM\ManyToOne(targetEntity="CompositeIntIdEntity") + * @ORM\JoinColumns({ + * @ORM\JoinColumn(name="composite_id1", referencedColumnName="id1"), + * @ORM\JoinColumn(name="composite_id2", referencedColumnName="id2") + * }) + * + * @var \Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity + */ + public $composite; +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index 70aef68b22..d9ed107bda 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -19,6 +19,8 @@ use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity; +use Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity2; +use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator; use Symfony\Component\Validator\Tests\Constraints\AbstractConstraintValidatorTest; @@ -125,9 +127,11 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest $schemaTool = new SchemaTool($em); $schemaTool->createSchema(array( $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity'), + $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity'), $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity'), $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity'), $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity'), + $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity2'), )); } @@ -406,6 +410,42 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest ->assertRaised(); } + public function testValidateUniquenessNotToStringEntityWithAssociatedEntity() + { + $constraint = new UniqueEntity(array( + 'message' => 'myMessage', + 'fields' => array('single'), + 'em' => self::EM_NAME, + )); + + $entity1 = new SingleIntIdNoToStringEntity(1, 'foo'); + $associated = new AssociationEntity2(); + $associated->single = $entity1; + $associated2 = new AssociationEntity2(); + $associated2->single = $entity1; + + $this->em->persist($entity1); + $this->em->persist($associated); + $this->em->flush(); + + $this->validator->validate($associated, $constraint); + + $this->assertNoViolation(); + + $this->em->persist($associated2); + $this->em->flush(); + + $this->validator->validate($associated2, $constraint); + + $expectedValue = 'Object of class "Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity2" identified by "2"'; + + $this->buildViolation('myMessage') + ->atPath('property.path.single') + ->setParameter('{{ value }}', $expectedValue) + ->setInvalidValue($expectedValue) + ->assertRaised(); + } + public function testAssociatedEntityWithNull() { $constraint = new UniqueEntity(array( diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index 1b16f5237e..c85c344b94 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -127,6 +127,10 @@ class UniqueEntityValidator extends ConstraintValidator $errorPath = null !== $constraint->errorPath ? $constraint->errorPath : $fields[0]; $invalidValue = isset($criteria[$errorPath]) ? $criteria[$errorPath] : $criteria[$fields[0]]; + if (is_object($invalidValue) && !method_exists($invalidValue, '__toString')) { + $invalidValue = sprintf('Object of class "%s" identified by "%s"', get_class($entity), implode(', ', $class->getIdentifierValues($entity))); + } + $this->context->buildViolation($constraint->message) ->atPath($errorPath) ->setParameter('{{ value }}', $invalidValue) From 082f1b5b1c4606e2519743813fff8ca787ad4040 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 1 Jun 2016 17:22:18 +0200 Subject: [PATCH 2/6] Fixed some issues of the AccessDecisionManager profiler --- .../Resources/config/collectors.xml | 2 +- .../Resources/config/security_debug.xml | 4 ++-- .../Bundle/SecurityBundle/composer.json | 2 +- .../DebugAccessDecisionManager.php | 20 ++++++++++++------- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml index 738455358b..de157d5182 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml @@ -10,7 +10,7 @@ - + diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.xml index 4312d74741..eb22cbddf5 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.xml @@ -1,8 +1,8 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 6e22dc9192..a67980b643 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=5.5.9", - "symfony/security": "~3.1", + "symfony/security": "~3.1,>=3.1.2", "symfony/http-kernel": "~2.8|~3.0", "symfony/polyfill-php70": "~1.0" }, diff --git a/src/Symfony/Component/Security/Core/Authorization/DebugAccessDecisionManager.php b/src/Symfony/Component/Security/Core/Authorization/DebugAccessDecisionManager.php index 540d998206..1a04bc1f60 100644 --- a/src/Symfony/Component/Security/Core/Authorization/DebugAccessDecisionManager.php +++ b/src/Symfony/Component/Security/Core/Authorization/DebugAccessDecisionManager.php @@ -26,17 +26,19 @@ class DebugAccessDecisionManager implements AccessDecisionManagerInterface { private $manager; private $strategy; - private $voters; + private $voters = array(); private $decisionLog = array(); - public function __construct(AccessDecisionManager $manager) + public function __construct(AccessDecisionManagerInterface $manager) { $this->manager = $manager; - // The strategy is stored in a private property of the decorated service - $reflection = new \ReflectionProperty($manager, 'strategy'); - $reflection->setAccessible(true); - $this->strategy = $reflection->getValue($manager); + if ($this->manager instanceof AccessDecisionManager) { + // The strategy is stored in a private property of the decorated service + $reflection = new \ReflectionProperty(AccessDecisionManager::class, 'strategy'); + $reflection->setAccessible(true); + $this->strategy = $reflection->getValue($manager); + } } /** @@ -60,6 +62,10 @@ class DebugAccessDecisionManager implements AccessDecisionManagerInterface */ public function setVoters(array $voters) { + if (!$this->manager instanceof AccessDecisionManager) { + return; + } + $this->voters = $voters; $this->manager->setVoters($voters); } @@ -72,7 +78,7 @@ class DebugAccessDecisionManager implements AccessDecisionManagerInterface // The $strategy property is misleading because it stores the name of its // method (e.g. 'decideAffirmative') instead of the original strategy name // (e.g. 'affirmative') - return strtolower(substr($this->strategy, 6)); + return null === $this->strategy ? '-' : strtolower(substr($this->strategy, 6)); } /** From 5ec92e8af35d36facf52db9cfecd3fde7a1d06fa Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 30 Jun 2016 08:29:00 +0200 Subject: [PATCH 3/6] [travis] Fix deps=low/high patching --- .travis.php => .github/travis.php | 10 +++++++--- .travis.yml | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) rename .travis.php => .github/travis.php (83%) diff --git a/.travis.php b/.github/travis.php similarity index 83% rename from .travis.php rename to .github/travis.php index 7618c272e8..9470836ef5 100644 --- a/.travis.php +++ b/.github/travis.php @@ -1,19 +1,23 @@ $_SERVER['argc']) { - echo "Usage: branch dir1 dir2 ... dirN\n"; + echo "Usage: branch version dir1 dir2 ... dirN\n"; exit(1); } $dirs = $_SERVER['argv']; array_shift($dirs); $branch = array_shift($dirs); +$version = array_shift($dirs); $packages = array(); $flags = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE : 0; foreach ($dirs as $dir) { - if (!`git diff --name-only $branch...HEAD -- $dir`) { + if (!system("git diff --name-only $branch...HEAD -- $dir", $exitStatus)) { + if ($exitStatus) { + exit($exitStatus); + } continue; } echo "$dir\n"; @@ -32,7 +36,7 @@ foreach ($dirs as $dir) { file_put_contents($dir.'/composer.json', $json); passthru("cd $dir && tar -cf package.tar --exclude='package.tar' *"); - $package->version = $branch.'.x-dev'; + $package->version = $version.'.x-dev'; $package->dist['type'] = 'tar'; $package->dist['url'] = 'file://'.__DIR__."/$dir/package.tar"; diff --git a/.travis.yml b/.travis.yml index b5a28f71fb..76e38fcb1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,7 +64,7 @@ before_install: install: - if [[ ! $skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components - - if [[ ! $skip && $deps ]]; then php .travis.php $TRAVIS_BRANCH $COMPONENTS; fi + - if [[ ! $skip && $deps ]]; then git fetch origin $TRAVIS_BRANCH && php .github/travis.php FETCH_HEAD $TRAVIS_BRANCH $COMPONENTS; fi # For the master branch when deps=high, the version before master is checked out and tested with the locally patched components - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//); else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*'); fi - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); ./phpunit install; fi From 1f00b553735f47f7614d98968cfdf2eb2f9c0b48 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 29 Jun 2016 19:50:09 +0200 Subject: [PATCH 4/6] [HttpKernel] Move conflicting origin IPs handling to catch block --- .../Component/HttpKernel/HttpKernel.php | 10 +++------- .../HttpKernel/Tests/HttpKernelTest.php | 20 +++++++------------ 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 2b8146127e..4e628a1409 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -63,6 +63,9 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface try { return $this->handleRaw($request, $type); } catch (\Exception $e) { + if ($e instanceof ConflictingHeadersException) { + $e = new BadRequestHttpException('The request headers contain conflicting information regarding the origin of this request.', $e); + } if (false === $catch) { $this->finishRequest($request, $type); @@ -115,13 +118,6 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface */ private function handleRaw(Request $request, $type = self::MASTER_REQUEST) { - if (self::MASTER_REQUEST === $type && $request::getTrustedProxies()) { - try { - $request->getClientIps(); - } catch (ConflictingHeadersException $e) { - throw new BadRequestHttpException('The request headers contain conflicting information regarding the origin of this request.', $e); - } - } $this->requestStack->push($request); // request diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php index 59c1d33425..372c2a3c1b 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php @@ -276,7 +276,13 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase */ public function testInconsistentClientIpsOnMasterRequests() { - $kernel = new HttpKernel(new EventDispatcher(), $this->getResolver()); + $dispatcher = new EventDispatcher(); + $dispatcher->addListener(KernelEvents::REQUEST, function ($event) { + $event->getRequest()->getClientIp(); + }); + + $kernel = new HttpKernel($dispatcher, $this->getResolver()); + $request = new Request(); $request->setTrustedProxies(array('1.1.1.1')); $request->server->set('REMOTE_ADDR', '1.1.1.1'); @@ -286,18 +292,6 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase $kernel->handle($request, $kernel::MASTER_REQUEST, false); } - public function testInconsistentClientIpsOnSubRequests() - { - $kernel = new HttpKernel(new EventDispatcher(), $this->getResolver()); - $request = new Request(); - $request->setTrustedProxies(array('1.1.1.1')); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('FORWARDED', '2.2.2.2'); - $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); - - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $kernel->handle($request, $kernel::SUB_REQUEST, false)); - } - protected function getResolver($controller = null) { if (null === $controller) { From db841018dce300566c15a959bd6add7aaab7b831 Mon Sep 17 00:00:00 2001 From: Magnus Nordlander Date: Mon, 2 May 2016 14:34:55 +0200 Subject: [PATCH 5/6] [HttpKernel] Add listener that checks when request has both Forwarded and X-Forwarded-For --- .../FrameworkBundle/Resources/config/web.xml | 4 ++ .../Bundle/FrameworkBundle/composer.json | 4 +- .../EventListener/ValidateRequestListener.php | 55 +++++++++++++++++++ .../ValidateRequestListenerTest.php | 42 ++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/HttpKernel/EventListener/ValidateRequestListener.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml index 9b2f3cb3a4..c1f73e5610 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml @@ -46,5 +46,9 @@ + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index bcfce7b707..9f62cb42e7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -22,8 +22,8 @@ "symfony/config": "~2.4", "symfony/event-dispatcher": "~2.5", "symfony/finder": "~2.0,>=2.0.5", - "symfony/http-foundation": "~2.4.9|~2.5,>=2.5.4", - "symfony/http-kernel": "~2.7", + "symfony/http-foundation": "~2.7", + "symfony/http-kernel": "~2.7.15|~2.8.8", "symfony/filesystem": "~2.3", "symfony/routing": "~2.6,>2.6.4", "symfony/security-core": "~2.6.13|~2.7.9|~2.8", diff --git a/src/Symfony/Component/HttpKernel/EventListener/ValidateRequestListener.php b/src/Symfony/Component/HttpKernel/EventListener/ValidateRequestListener.php new file mode 100644 index 0000000000..00096ccf9e --- /dev/null +++ b/src/Symfony/Component/HttpKernel/EventListener/ValidateRequestListener.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; + +/** + * Validates that the headers and other information indicating the + * client IP address of a request are consistent. + * + * @author Magnus Nordlander + */ +class ValidateRequestListener implements EventSubscriberInterface +{ + /** + * Performs the validation. + * + * @param GetResponseEvent $event + */ + public function onKernelRequest(GetResponseEvent $event) + { + if (!$event->isMasterRequest()) { + return; + } + $request = $event->getRequest(); + + if ($request::getTrustedProxies()) { + // This will throw an exception if the headers are inconsistent. + $request->getClientIps(); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array( + KernelEvents::REQUEST => array( + array('onKernelRequest', 256), + ), + ); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php new file mode 100644 index 0000000000..842a3869cb --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\EventListener; + +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\EventListener\ValidateRequestListener; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\KernelEvents; + +class ValidateRequestListenerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @expectedException Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException + */ + public function testListenerThrowsWhenMasterRequestHasInconsistentClientIps() + { + $dispatcher = new EventDispatcher(); + $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); + + $request = new Request(); + $request->setTrustedProxies(array('1.1.1.1')); + $request->server->set('REMOTE_ADDR', '1.1.1.1'); + $request->headers->set('FORWARDED', '2.2.2.2'); + $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); + + $dispatcher->addListener(KernelEvents::REQUEST, array(new ValidateRequestListener(), 'onKernelRequest')); + $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + + $dispatcher->dispatch(KernelEvents::REQUEST, $event); + } +} From fbeb299273f045500e0b6fe290e546101e1a6c80 Mon Sep 17 00:00:00 2001 From: Rootie Date: Thu, 30 Jun 2016 09:10:11 +0200 Subject: [PATCH 6/6] Fixed BC Layer in DoctrineChoiceLoader in the case when the BC Layer is used $idReader is not set to the right value. --- .../Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php index 3026850627..72f961a501 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php @@ -75,6 +75,7 @@ class DoctrineChoiceLoader implements ChoiceLoaderInterface // form first to last argument as of 3.1 $manager = $class; $class = $idReader; + $idReader = $objectLoader; $objectLoader = $factory; }