Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependency/dependant tracking #426

Merged
merged 10 commits into from Apr 8, 2021
Merged
5 changes: 5 additions & 0 deletions phpstan.neon
Expand Up @@ -8,6 +8,11 @@ parameters:
count: 1
path: src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php

-
message: "#^Variable method call on Composer\\\\Package\\\\PackageInterface\\.$#"
count: 1
path: src/Service/PackageSynchronizer/ComposerPackageSynchronizer.php

-
message: "#^Variable property access on DateInterval\\.$#"
count: 1
Expand Down
19 changes: 19 additions & 0 deletions src/Controller/OrganizationController.php
Expand Up @@ -110,13 +110,32 @@ public function packageDetails(Organization $organization, PackageDetails $packa
{
$filter = Filter::fromRequest($request);

$packageLinks = $this->packageQuery->getLinks($package->id(), $organization->id());

/** @var string $packageName */
$packageName = $package->name();

$dependantCount = $this->packageQuery->getDependantCount($packageName, $organization->id());

$groupedPackageLinks = [];

foreach ($packageLinks as $packageLink) {
if (!isset($groupedPackageLinks[$packageLink->type()])) {
$groupedPackageLinks[$packageLink->type()] = [];
}

$groupedPackageLinks[$packageLink->type()][] = $packageLink;
}

return $this->render('organization/package/details.html.twig', [
'organization' => $organization,
'package' => $package,
'filter' => $filter,
'count' => $this->packageQuery->versionCount($package->id()),
'versions' => $this->packageQuery->getVersions($package->id(), $filter),
'installs' => $this->packageQuery->getInstalls($package->id(), 0),
'packageLinks' => $groupedPackageLinks,
'dependantCount' => $dependantCount,
]);
}

Expand Down
31 changes: 30 additions & 1 deletion src/Entity/Organization/Package.php
Expand Up @@ -5,6 +5,7 @@
namespace Buddy\Repman\Entity\Organization;

use Buddy\Repman\Entity\Organization;
use Buddy\Repman\Entity\Organization\Package\Link;
use Buddy\Repman\Entity\Organization\Package\Version;
use Buddy\Repman\Entity\User\OAuthToken;
use Doctrine\Common\Collections\ArrayCollection;
Expand Down Expand Up @@ -120,6 +121,12 @@ class Package
*/
private Collection $versions;

/**
* @var Collection<int,Link>|Link[]
* @ORM\OneToMany(targetEntity="Buddy\Repman\Entity\Organization\Package\Link", mappedBy="package", cascade={"persist"}, orphanRemoval=true)
*/
private Collection $links;

/**
* @ORM\Column(type="integer")
*/
Expand All @@ -136,6 +143,7 @@ public function __construct(UuidInterface $id, string $type, string $url, array
$this->metadata = $metadata;
$this->keepLastReleases = $keepLastReleases;
$this->versions = new ArrayCollection();
$this->links = new ArrayCollection();
}

public function id(): UuidInterface
Expand Down Expand Up @@ -163,8 +171,9 @@ public function repositoryUrl(): string

/**
* @param string[] $encounteredVersions
* @param string[] $encounteredLinks
*/
public function syncSuccess(string $name, string $description, string $latestReleasedVersion, array $encounteredVersions, \DateTimeImmutable $latestReleaseDate): void
public function syncSuccess(string $name, string $description, string $latestReleasedVersion, array $encounteredVersions, array $encounteredLinks, \DateTimeImmutable $latestReleaseDate): void
{
$this->setName($name);
$this->description = $description;
Expand All @@ -175,6 +184,11 @@ public function syncSuccess(string $name, string $description, string $latestRel
$this->versions->removeElement($version);
}
}
foreach ($this->links as $link) {
if (!in_array($link->type().'-'.$link->target(), $encounteredLinks, true)) {
$this->links->removeElement($link);
}
}
$this->lastSyncAt = new \DateTimeImmutable();
$this->lastSyncError = null;
}
Expand Down Expand Up @@ -320,6 +334,21 @@ public function addOrUpdateVersion(Version $version): void
$this->versions->add($version);
}

/**
* @return Collection<int,Link>|Link[]
*/
public function links(): Collection
{
return $this->links;
}

public function addLink(Link $link): void
{
$link->setPackage($this);
$link->setOrganization($this->organization);
$this->links->add($link);
}

public function removeVersion(Version $version): void
{
$this->versions->removeElement($version);
Expand Down
111 changes: 111 additions & 0 deletions src/Entity/Organization/Package/Link.php
@@ -0,0 +1,111 @@
<?php

declare(strict_types=1);

namespace Buddy\Repman\Entity\Organization\Package;

use Buddy\Repman\Entity\Organization;
use Buddy\Repman\Entity\Organization\Package;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\UuidInterface;

/**
* @ORM\Entity
* @ORM\Table(
* name="organization_package_link",
* indexes={
* @ORM\Index(name="link_package_id_idx", columns={"package_id"}),
* @ORM\Index(name="link_target_idx", columns={"target"}),
* }
* )
*/
class Link
{
/**
* @ORM\Id()
* @ORM\Column(type="uuid")
*/
private UuidInterface $id;

/**
* @ORM\ManyToOne(targetEntity="Buddy\Repman\Entity\Organization")
* @ORM\JoinColumn(nullable=false)
*/
private Organization $organization;

/**
* @ORM\ManyToOne(targetEntity="Buddy\Repman\Entity\Organization\Package", inversedBy="links")
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
*/
private Package $package;

/**
* @ORM\Column(type="string")
*/
private string $type;

/**
* @ORM\Column(type="string")
*/
private string $target;

/**
* @ORM\Column(name="`constraint`",type="string")
*/
private string $constraint;

private ?string $packageId;
private ?string $targetPackageId;

public function __construct(
UuidInterface $id,
string $type,
string $target,
string $constraint,
?string $packageId = null,
?string $targetPackageId = null
) {
$this->id = $id;
$this->type = $type;
$this->target = $target;
$this->constraint = $constraint;
$this->packageId = $packageId;
$this->targetPackageId = $targetPackageId;
}

public function type(): string
{
return $this->type;
}

public function target(): string
{
return $this->target;
}

public function constraint(): string
{
return $this->constraint;
}

public function targetPackageId(): ?string
{
return $this->targetPackageId;
}

public function setOrganization(Organization $organization): void
{
if (isset($this->organization)) {
throw new \RuntimeException('You can not change link organization');
}
$this->organization = $organization;
}

public function setPackage(Package $package): void
{
if (isset($this->package)) {
throw new \RuntimeException('You can not change link package');
}
$this->package = $package;
}
}
41 changes: 41 additions & 0 deletions src/Migrations/Version20210309201702.php
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Buddy\Repman\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210309201702 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add package links';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs

$this->addSql('CREATE TABLE organization_package_link (id UUID NOT NULL, organization_id UUID NOT NULL, package_id UUID NOT NULL, target VARCHAR(255) NOT NULL, "constraint" VARCHAR(255) NOT NULL, type VARCHAR (255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX link_package_id_idx ON organization_package_link (package_id)');
$this->addSql('CREATE INDEX IDX_4A06082932C8A3DE ON organization_package_link (organization_id)');
$this->addSql('CREATE INDEX link_target_idx ON organization_package_link (target)');
$this->addSql('COMMENT ON COLUMN organization_package_link.id IS \'(DC2Type:uuid)\'');
$this->addSql('COMMENT ON COLUMN organization_package_link.package_id IS \'(DC2Type:uuid)\'');
$this->addSql('COMMENT ON COLUMN organization_package_link.organization_id IS \'(DC2Type:uuid)\'');
$this->addSql('ALTER TABLE organization_package_link ADD CONSTRAINT FK_CAKE4LIFE FOREIGN KEY (package_id) REFERENCES organization_package (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE organization_package_link ADD CONSTRAINT FK_4A06082932C8A3DE FOREIGN KEY (organization_id) REFERENCES organization (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs

$this->addSql('DROP TABLE organization_package_link');
}
}
8 changes: 8 additions & 0 deletions src/Query/User/PackageQuery.php
Expand Up @@ -4,6 +4,7 @@

namespace Buddy\Repman\Query\User;

use Buddy\Repman\Entity\Organization\Package\Link;
use Buddy\Repman\Query\Filter;
use Buddy\Repman\Query\User\Model\Installs;
use Buddy\Repman\Query\User\Model\Package;
Expand Down Expand Up @@ -46,6 +47,13 @@ public function versionCount(string $packageId): int;
*/
public function getVersions(string $packageId, Filter $filter): array;

/**
* @return Link[]
*/
public function getLinks(string $packageId, string $organizationId): array;

public function getDependantCount(string $packageName, string $organizationId): int;

public function getInstalls(string $packageId, int $lastDays = 30, ?string $version = null): Installs;

/**
Expand Down