Browse Source

Fix heavy readmes causing issues with joins

Jordi Boggiano 7 years ago
parent
commit
1b33922314

+ 3 - 3
src/Packagist/WebBundle/Controller/PackageController.php

@@ -310,7 +310,7 @@ class PackageController extends Controller
 
         try {
             /** @var Package $package */
-            $package = $repo->findOneByName($name);
+            $package = $repo->getPartialPackageByNameWithVersions($name);
         } catch (NoResultException $e) {
             if ('json' === $req->getRequestFormat()) {
                 return new JsonResponse(array('status' => 'error', 'message' => 'Package not found'), 404);
@@ -423,7 +423,7 @@ class PackageController extends Controller
 
         try {
             /** @var $package Package */
-            $package = $repo->findOneByName($name);
+            $package = $repo->getPartialPackageByNameWithVersions($name);
         } catch (NoResultException $e) {
             if ('json' === $req->getRequestFormat()) {
                 return new JsonResponse(array('status' => 'error', 'message' => 'Package not found'), 404);
@@ -612,7 +612,7 @@ class PackageController extends Controller
             /** @var Package $package */
             $package = $doctrine
                 ->getRepository('PackagistWebBundle:Package')
-                ->findOneByName($name);
+                ->getPartialPackageByNameWithVersions($name);
         } catch (NoResultException $e) {
             throw new NotFoundHttpException('The requested package, '.$name.', was not found.');
         }

+ 31 - 17
src/Packagist/WebBundle/Entity/PackageRepository.php

@@ -155,12 +155,40 @@ class PackageRepository extends EntityRepository
         return $conn->fetchAll('SELECT p.id FROM package p WHERE p.dumpedAt IS NULL OR p.dumpedAt <= p.crawledAt  ORDER BY p.id ASC');
     }
 
-    public function findOneByName($name)
+    public function getPartialPackageByNameWithVersions($name)
     {
-        $qb = $this->getBaseQueryBuilder()
+        // first fetch a partial package including joined versions/maintainers, that way
+        // the join is cheap and heavy data (description, readme) is not duplicated for each joined row
+        $qb = $this->getEntityManager()->createQueryBuilder();
+        $qb->select('partial p.{id}', 'v', 't', 'm')
+            ->from('Packagist\WebBundle\Entity\Package', 'p')
+            ->leftJoin('p.versions', 'v')
+            ->leftJoin('p.maintainers', 'm')
+            ->leftJoin('v.tags', 't')
+            ->orderBy('v.development', 'DESC')
+            ->addOrderBy('v.releasedAt', 'DESC')
             ->where('p.name = ?0')
             ->setParameters(array($name));
-        return $qb->getQuery()->getSingleResult();
+
+        $pkg = $qb->getQuery()->getSingleResult();
+
+        if ($pkg) {
+            // then refresh the package to complete its data and inject the previously fetched versions/maintainers to
+            // get a complete package
+            $versions = $pkg->getVersions();
+            $maintainers = $pkg->getMaintainers();
+            $this->getEntityManager()->refresh($pkg);
+
+            $prop = new \ReflectionProperty($pkg, 'versions');
+            $prop->setAccessible(true);
+            $prop->setValue($pkg, $versions);
+
+            $prop = new \ReflectionProperty($pkg, 'maintainers');
+            $prop->setAccessible(true);
+            $prop->setValue($pkg, $maintainers);
+        }
+
+        return $pkg;
     }
 
     public function getPackageByName($name)
@@ -358,20 +386,6 @@ class PackageRepository extends EntityRepository
         }
     }
 
-    public function getBaseQueryBuilder()
-    {
-        $qb = $this->getEntityManager()->createQueryBuilder();
-        $qb->select('p', 'v', 't', 'm')
-            ->from('Packagist\WebBundle\Entity\Package', 'p')
-            ->leftJoin('p.versions', 'v')
-            ->leftJoin('p.maintainers', 'm')
-            ->leftJoin('v.tags', 't')
-            ->orderBy('v.development', 'DESC')
-            ->addOrderBy('v.releasedAt', 'DESC');
-
-        return $qb;
-    }
-
     /**
      * Gets the most recent packages created
      *