diff --git a/src/Oro/Bundle/CacheBundle/Tests/Unit/Provider/FileCacheTest.php b/src/Oro/Bundle/CacheBundle/Tests/Unit/Provider/FileCacheTest.php index 348831ae91e..06f1031de73 100644 --- a/src/Oro/Bundle/CacheBundle/Tests/Unit/Provider/FileCacheTest.php +++ b/src/Oro/Bundle/CacheBundle/Tests/Unit/Provider/FileCacheTest.php @@ -2,34 +2,54 @@ namespace Oro\Bundle\CacheBundle\Tests\Unit\Provider; +use Symfony\Component\Filesystem\Filesystem; + +use Oro\Bundle\CacheBundle\Provider\SyncCacheInterface; + class FileCacheTest extends \PHPUnit_Framework_TestCase { /** + * @param string $cacheClass + * @param string $id + * @param string $namespace + * @param string $expectedFileName + * * @dataProvider getFilenameProvider */ - public function testGetFilename($cacheClass, $id, $expectedFileName) + public function testGetFilename($cacheClass, $id, $namespace, $expectedFileName) { + $fs = new Filesystem(); + $directory = 'dir' . uniqid(); + $cache = $this->getMockBuilder($cacheClass) - ->disableOriginalConstructor() - ->setMethods(['fetch']) + ->setConstructorArgs([$directory, '.ext']) + ->setMethods(['fetch', 'getNamespace']) ->getMock(); - self::setProtectedProperty($cache, 'directory', 'dir'); - self::setProtectedProperty($cache, 'extension', '.ext'); + $cache->expects($this->any()) + ->method('getNamespace') + ->will($this->returnValue($namespace)); + $result = self::callProtectedMethod($cache, 'getFilename', [$id]); $this->assertEquals( - $expectedFileName, - self::callProtectedMethod($cache, 'getFilename', array($id)) + $directory . DIRECTORY_SEPARATOR . $expectedFileName, + str_replace(realpath($directory), $directory, $result) ); + + $this->assertTrue($fs->exists($directory)); + $fs->remove($directory); } /** + * @param string $cacheClass + * * @dataProvider syncProvider */ public function testSync($cacheClass) { $namespace = '123'; + /** @var \PHPUnit_Framework_MockObject_MockObject|SyncCacheInterface $cache */ $cache = $this->getMockBuilder($cacheClass) ->disableOriginalConstructor() ->setMethods(['setNamespace', 'getNamespace']) @@ -45,32 +65,54 @@ public function testSync($cacheClass) $cache->sync(); } + /** + * @return array + */ public static function getFilenameProvider() { return [ [ 'Oro\Bundle\CacheBundle\Provider\FilesystemCache', 'test', - 'dir' . DIRECTORY_SEPARATOR . 'test.ext', + null, + 'test.ext', + ], + [ + 'Oro\Bundle\CacheBundle\Provider\FilesystemCache', + 'test', + 'namespace', + 'namespace' . DIRECTORY_SEPARATOR . 'test.ext', ], [ 'Oro\Bundle\CacheBundle\Provider\FilesystemCache', 'test\\\\//::""**??<<>>||file', - 'dir' . DIRECTORY_SEPARATOR . 'testfile.ext' + 'namespace\\\\//::""**??<<>>||', + 'namespace' . DIRECTORY_SEPARATOR . 'testfile.ext', ], [ 'Oro\Bundle\CacheBundle\Provider\PhpFileCache', 'test', - 'dir' . DIRECTORY_SEPARATOR . 'test.ext', + null, + 'test.ext', + ], + [ + 'Oro\Bundle\CacheBundle\Provider\PhpFileCache', + 'test', + 'namespace', + 'namespace' . DIRECTORY_SEPARATOR . 'test.ext', ], [ 'Oro\Bundle\CacheBundle\Provider\PhpFileCache', 'test\\\\//::""**??<<>>||file', - 'dir' . DIRECTORY_SEPARATOR . 'testfile.ext' + 'namespace\\\\//::""**??<<>>||', + 'namespace' . DIRECTORY_SEPARATOR . 'testfile.ext', ], ]; } + /** + * @return array + */ public static function syncProvider() { return [ @@ -79,20 +121,6 @@ public static function syncProvider() ]; } - /** - * @param mixed $obj - * @param string $propName - * @param mixed $val - */ - public static function setProtectedProperty($obj, $propName, $val) - { - $class = new \ReflectionClass($obj); - $prop = $class->getProperty($propName); - $prop->setAccessible(true); - - $prop->setValue($obj, $val); - } - /** * @param mixed $obj * @param string $methodName diff --git a/src/Oro/Bundle/IntegrationBundle/Entity/Channel.php b/src/Oro/Bundle/IntegrationBundle/Entity/Channel.php index efcbef8a2ce..2b1235f125d 100644 --- a/src/Oro/Bundle/IntegrationBundle/Entity/Channel.php +++ b/src/Oro/Bundle/IntegrationBundle/Entity/Channel.php @@ -335,8 +335,10 @@ public function getStatuses() } /** - * @param string $connector - * @param int|int $codeFilter + * @deprecated Deprecated since 1.7.0 in favor of getLastStatusForConnector because of performance impact. + * @see Oro\Bundle\IntegrationBundle\Entity\Repository\ChannelRepository::getLastStatusForConnector + * @param string $connector + * @param int|null $codeFilter * * @return ArrayCollection */ diff --git a/src/Oro/Bundle/IntegrationBundle/Entity/Repository/ChannelRepository.php b/src/Oro/Bundle/IntegrationBundle/Entity/Repository/ChannelRepository.php index 409f67e5f85..4cc018d40ff 100644 --- a/src/Oro/Bundle/IntegrationBundle/Entity/Repository/ChannelRepository.php +++ b/src/Oro/Bundle/IntegrationBundle/Entity/Repository/ChannelRepository.php @@ -9,6 +9,36 @@ class ChannelRepository extends EntityRepository { + /** + * Returns latest status for integration's connector and code if it exists. + * + * @param Integration $integration + * @param string $connector + * @param int|null $code + * @return Status|null + */ + public function getLastStatusForConnector(Integration $integration, $connector, $code = null) + { + $queryBuilder = $this->getEntityManager()->createQueryBuilder() + ->select('status') + ->from('OroIntegrationBundle:Status', 'status') + ->where('status.channel = :integration') + ->andWhere('status.connector = :connector') + ->setParameters(['integration' => $integration, 'connector' => (string)$connector]) + ->orderBy('status.date', 'DESC') + ->setFirstResult(0) + ->setMaxResults(1); + + if ($code) { + $queryBuilder->andWhere('status.code = :code') + ->setParameter('code', (string)$code); + }; + + $statuses = $queryBuilder->getQuery()->execute(); + + return $statuses ? reset($statuses) : null; + } + /** * Returns channels that have configured transports * Assume that they are ready for sync diff --git a/src/Oro/Bundle/IntegrationBundle/Resources/doc/reference/additional-capabilities.md b/src/Oro/Bundle/IntegrationBundle/Resources/doc/reference/additional-capabilities.md index f64b0d51b8c..b0e971a2536 100644 --- a/src/Oro/Bundle/IntegrationBundle/Resources/doc/reference/additional-capabilities.md +++ b/src/Oro/Bundle/IntegrationBundle/Resources/doc/reference/additional-capabilities.md @@ -34,7 +34,8 @@ and then methods `addStatusData` and `getStatusData` will be available. // retrieve data from status - $status = $this->channel->getStatusesForConnector($this->getType(), Status::STATUS_COMPLETED)->first(); + $status = $this->container->get('doctrine')->getRepository('OroIntegrationBundle:Channel') + ->getLastStatusForConnector($channel, $this->getType(), Status::STATUS_COMPLETED); /** @var array **/ $data = $status->getData(); $lastItemUpdatedAt = $data['lastItemUpdatedAt']; diff --git a/src/Oro/Bundle/IntegrationBundle/Tests/Functional/DataFixtures/LoadChannelData.php b/src/Oro/Bundle/IntegrationBundle/Tests/Functional/DataFixtures/LoadChannelData.php new file mode 100644 index 00000000000..ec23f57281c --- /dev/null +++ b/src/Oro/Bundle/IntegrationBundle/Tests/Functional/DataFixtures/LoadChannelData.php @@ -0,0 +1,71 @@ + 'Foo Integration', + 'type' => 'foo', + 'enabled' => true, + 'reference' => 'oro_integration:foo_integration' + ], + [ + 'name' => 'Bar Integration', + 'type' => 'bar', + 'enabled' => true, + 'reference' => 'oro_integration:bar_integration' + ] + ]; + + /** + * {@inheritdoc} + */ + public function setContainer(ContainerInterface $container = null) + { + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function load(ObjectManager $manager) + { + $userManager = $this->container->get('oro_user.manager'); + $admin = $userManager->findUserByEmail(LoadAdminUserData::DEFAULT_ADMIN_EMAIL); + + foreach ($this->data as $data) { + $integration = new Integration(); + + $integration->setName($data['name']); + $integration->setType($data['type']); + $integration->setEnabled($data['enabled']); + $integration->setDefaultUserOwner($admin); + $integration->setOrganization($admin->getOrganization()); + + $this->setReference($data['reference'], $integration); + + $manager->persist($integration); + } + + $manager->flush(); + } +} diff --git a/src/Oro/Bundle/IntegrationBundle/Tests/Functional/DataFixtures/LoadStatusData.php b/src/Oro/Bundle/IntegrationBundle/Tests/Functional/DataFixtures/LoadStatusData.php new file mode 100644 index 00000000000..561a4aeb506 --- /dev/null +++ b/src/Oro/Bundle/IntegrationBundle/Tests/Functional/DataFixtures/LoadStatusData.php @@ -0,0 +1,105 @@ + 'oro_integration:foo_integration', + 'status' => Status::STATUS_COMPLETED, + 'connector' => 'first_connector', + 'date' => '2015-02-01 00:00:00', + 'message' => '', + 'reference' => 'oro_integration:foo_first_connector_first_status_completed' + ], + [ + 'channel' => 'oro_integration:foo_integration', + 'status' => Status::STATUS_COMPLETED, + 'connector' => 'first_connector', + 'date' => '2015-02-01 00:05:00', + 'message' => '', + 'reference' => 'oro_integration:foo_first_connector_second_status_completed' + ], + [ + 'channel' => 'oro_integration:foo_integration', + 'status' => Status::STATUS_FAILED, + 'connector' => 'first_connector', + 'date' => '2015-02-01 00:10:00', + 'message' => '', + 'reference' => 'oro_integration:foo_first_connector_third_status_failed' + ], + [ + 'channel' => 'oro_integration:foo_integration', + 'status' => Status::STATUS_COMPLETED, + 'connector' => 'second_connector', + 'date' => '2015-02-01 00:15:00', + 'message' => '', + 'reference' => 'oro_integration:foo_second_connector_first_status_completed' + ], + [ + 'channel' => 'oro_integration:bar_integration', + 'status' => Status::STATUS_COMPLETED, + 'connector' => 'first_connector', + 'date' => '2015-02-01 00:20:00', + 'message' => '', + 'reference' => 'oro_integration:bar_first_connector_first_status_completed' + ], + ]; + + /** + * {@inheritdoc} + */ + public function setContainer(ContainerInterface $container = null) + { + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function load(ObjectManager $manager) + { + foreach ($this->data as $data) { + $status = new Status(); + $status->setChannel($this->getReference($data['channel'])); + $status->setCode($data['status']); + $status->setConnector($data['connector']); + $status->setDate(new \DateTime($data['date'], new \DateTimeZone('UTC'))); + $status->setMessage($data['message']); + + $this->setReference($data['reference'], $status); + + $manager->persist($status); + } + + $manager->flush(); + } + + /** + * {@inheritdoc} + */ + public function getDependencies() + { + return [ + 'Oro\Bundle\IntegrationBundle\Tests\Functional\DataFixtures\LoadChannelData' + ]; + } +} diff --git a/src/Oro/Bundle/IntegrationBundle/Tests/Functional/Entity/Repository/ChannelRepositoryTest.php b/src/Oro/Bundle/IntegrationBundle/Tests/Functional/Entity/Repository/ChannelRepositoryTest.php new file mode 100644 index 00000000000..f24864dc171 --- /dev/null +++ b/src/Oro/Bundle/IntegrationBundle/Tests/Functional/Entity/Repository/ChannelRepositoryTest.php @@ -0,0 +1,50 @@ +initClient(); + $this->loadFixtures(['Oro\Bundle\IntegrationBundle\Tests\Functional\DataFixtures\LoadStatusData']); + $this->repository = $this->getContainer()->get('doctrine')->getRepository('OroIntegrationBundle:Channel'); + } + + public function testRepositoryIsRegistered() + { + $this->assertInstanceOf('Oro\Bundle\IntegrationBundle\Entity\Repository\ChannelRepository', $this->repository); + } + + public function testGetLastStatusForConnectorWorks() + { + $fooIntegration = $this->getReference('oro_integration:foo_integration'); + + $this->assertSame( + $this->getReference('oro_integration:foo_first_connector_second_status_completed'), + $this->repository->getLastStatusForConnector($fooIntegration, 'first_connector', Status::STATUS_COMPLETED) + ); + + $this->assertSame( + $this->getReference('oro_integration:foo_first_connector_third_status_failed'), + $this->repository->getLastStatusForConnector($fooIntegration, 'first_connector', Status::STATUS_FAILED) + ); + + $barIntegration = $this->getReference('oro_integration:bar_integration'); + + $this->assertSame( + $this->getReference('oro_integration:bar_first_connector_first_status_completed'), + $this->repository->getLastStatusForConnector($barIntegration, 'first_connector', Status::STATUS_COMPLETED) + ); + } +} diff --git a/src/Oro/Bundle/SearchBundle/Engine/Orm.php b/src/Oro/Bundle/SearchBundle/Engine/Orm.php index 9c7f9b609f6..e6710cc39d8 100644 --- a/src/Oro/Bundle/SearchBundle/Engine/Orm.php +++ b/src/Oro/Bundle/SearchBundle/Engine/Orm.php @@ -199,15 +199,24 @@ protected function doSearch(Query $query) if (is_array($item)) { $item = $item['item']; } - /** @var $item Item */ - $results[] = new ResultItem( - $this->registry->getManagerForClass($item->getEntity()), - $item->getEntity(), - $item->getRecordId(), - $item->getTitle(), + + /** + * Search result can contains duplicates and we can not use HYDRATE_OBJECT because of performance issue. + * @todo: update after fix BAP-7166. Remove check for existing result. + */ + $id = $item['id']; + if (isset($results[$id])) { + continue; + } + + $results[$id] = new ResultItem( + $this->registry->getManagerForClass($item['entity']), + $item['entity'], + $item['recordId'], + $item['title'], + null, null, - $item->getRecordText(), - $this->mapper->getEntityConfig($item->getEntity()) + $this->mapper->getEntityConfig($item['entity']) ); } } diff --git a/src/Oro/Bundle/SearchBundle/Engine/Orm/BaseDriver.php b/src/Oro/Bundle/SearchBundle/Engine/Orm/BaseDriver.php index 3031279c2f7..33b2250b259 100644 --- a/src/Oro/Bundle/SearchBundle/Engine/Orm/BaseDriver.php +++ b/src/Oro/Bundle/SearchBundle/Engine/Orm/BaseDriver.php @@ -48,6 +48,7 @@ public function createQueryBuilder($alias) /** * Search query by Query builder object + * Can contains duplicates and we can not use HYDRATE_OBJECT because of performance issue. Will be fixed in BAP-7166 * * @param \Oro\Bundle\SearchBundle\Query\Query $query * @@ -70,7 +71,7 @@ public function search(Query $query) return $qb ->getQuery() - ->getResult(); + ->getArrayResult(); } /** diff --git a/src/Oro/Bundle/SearchBundle/Query/Result/Item.php b/src/Oro/Bundle/SearchBundle/Query/Result/Item.php index 0d57a6c5669..af76820eba0 100644 --- a/src/Oro/Bundle/SearchBundle/Query/Result/Item.php +++ b/src/Oro/Bundle/SearchBundle/Query/Result/Item.php @@ -53,6 +53,15 @@ class Item */ protected $em; + /** + * @param ObjectManager $em + * @param string|null $entityName + * @param string|null $recordId + * @param string|null $recordTitle + * @param string|null $recordUrl + * @param string $recordText + * @param array $entityConfig + */ public function __construct( ObjectManager $em, $entityName = null,