Gets the EntityRepository for an entity.
public getRepository ( string $entityName, $entityManagerName = null ) : Doctrine\ORM\EntityRepository | ||
$entityName | string | The name of the entity. |
return | Doctrine\ORM\EntityRepository |
/** * @inheritdoc */ public function finishView(FormView $view, FormInterface $form, array $options) { /** @var ChoiceView $choice */ foreach ($view->vars['choices'] as $choice) { if ($options['select2_template_result']) { $object = $choice->value; if ($this->doctrine && $options['class']) { $object = $this->doctrine->getRepository($options['class'])->find($object); } if (is_string($options['select2_template_result'])) { $choice->attr['data-template-result'] = $this->templating->render($options['select2_template_result'], ['choice' => $choice, 'object' => $object]); } else { $choice->attr['data-template-result'] = call_user_func_array($options['select2_template_result'], [$choice, $object]); } } if ($options['select2_template_selection']) { $object = $choice->value; if ($this->doctrine && $options['class']) { $object = $this->doctrine->getRepository($options['class'])->find($object); } if (is_string($options['select2_template_selection'])) { $choice->attr['data-template-selection'] = $this->templating->render($options['select2_template_selection'], ['choice' => $choice, 'object' => $object]); } else { $choice->attr['data-template-selection'] = call_user_func_array($options['select2_template_selection'], [$choice, $object]); } } } if ($options['select2'] === true) { $options['select2_options'] = array_merge($this->select2DefaultOptions, $options['select2_options']); $view->vars['select2_options'] = json_encode($options['select2_options']); } }
/** * @param array $context * * @return Integration * @throws \LogicException */ public function getIntegrationFromContext(array $context) { if (!isset($context['channel'])) { throw new \LogicException('Context should contain reference to channel'); } return $this->registry->getRepository('OroIntegrationBundle:Channel')->getOrLoadById($context['channel']); }
/** * Returns a JSON response containing options * * @param Request $request * * @return JsonResponse */ public function listAction(Request $request) { $query = $request->query; $search = $query->get('search'); $referenceDataName = $query->get('referenceDataName'); $class = $query->get('class'); if (null !== $referenceDataName) { $class = $this->registry->get($referenceDataName)->getClass(); } $repository = $this->doctrine->getRepository($class); if ($repository instanceof OptionRepositoryInterface) { $choices = $repository->getOptions($query->get('dataLocale'), $query->get('collectionId'), $search, $query->get('options', [])); } elseif ($repository instanceof ReferenceDataRepositoryInterface) { $choices['results'] = $repository->findBySearch($search, $query->get('options', [])); } elseif ($repository instanceof SearchableRepositoryInterface) { $choices['results'] = $repository->findBySearch($search, $query->get('options', [])); } elseif (method_exists($repository, 'getOptions')) { $choices = $repository->getOptions($query->get('dataLocale'), $query->get('collectionId'), $search, $query->get('options', [])); } else { throw new \LogicException(sprintf('The repository of the class "%s" can not retrieve options via Ajax.', $query->get('class'))); } if ($query->get('isCreatable') && 0 === count($choices['results'])) { $choices['results'] = [['id' => $search, 'text' => $search]]; } return new JsonResponse($choices); }
public function packageExistsTest($package) { if (!preg_match('/^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/', $package)) { return false; } return $this->doctrine->getRepository('PackagistWebBundle:Package')->packageExists($package); }
protected function findPattern(FormBuilderInterface $builder) { $pattern = $this->registry->getRepository('ClasticAliasBundle:AliasPattern')->findOneBy(array('moduleIdentifier' => $builder->getData()->getNode()->getType())); if ($pattern) { return $pattern->getPattern(); } return '{title}'; }
/** * @param array $dateRange * @param string $entity * @param string $field * * @return \DateTime[] */ public function getPeriod($dateRange, $entity, $field) { $start = $dateRange['start']; $end = $dateRange['end']; if ($dateRange['type'] === AbstractDateFilterType::TYPE_LESS_THAN) { $qb = $this->doctrine->getRepository($entity)->createQueryBuilder('e')->select(sprintf('MIN(e.%s) as val', $field)); $start = $this->aclHelper->apply($qb)->getSingleScalarResult(); $start = new \DateTime($start, new \DateTimeZone('UTC')); } return [$start, $end]; }
protected function trainContainer() { $this->request->getSession()->willReturn($this->session); $this->request->getLocale()->willReturn('fr_FR'); $this->doctrine->getManager()->willReturn($this->manager); $this->doctrine->getManager()->willReturn($this->manager); $this->doctrine->getRepository('DonateCoreBundle:Intent')->willReturn($this->intentRepository); $this->container->has('doctrine')->willReturn(true); $this->container->get('doctrine')->willReturn($this->doctrine); $this->container->get('request')->willReturn($this->request); $this->container->get('donate_core.payment_method_discovery')->willReturn($this->discovery); $this->container->get('event_dispatcher')->willReturn($this->dispatcher); $this->container->get('logger')->willReturn($this->logger); }
/** * Rotates imported feeds * * @param Feed $feed The feed to rotate imports for * @param integer $max The number of imports to keep */ public function rotate(Feed $feed, $max = 4) { /** @var ImportRepository $repo */ $repo = $this->doctrine->getRepository('FMIoBundle:Import'); $imports = $repo->findCompletedByFeed($feed); if (sizeof($imports) <= $max) { return; } $manager = $this->doctrine->getManager(); foreach (array_slice($imports, $max) as $import) { $this->eventDispatcher->dispatch(IoEvents::IMPORT_ROTATE, new ImportEvent($import)); $manager->remove($import); $manager->flush(); } }
/** * Sets the attributes and identifierAttributes properties * * @param array $columnsInfo * * @return array|null */ public function getAttributes($columnsInfo) { if (!count($columnsInfo)) { return array(); } $codes = array_unique(array_map(function ($columnInfo) { return $columnInfo->getName(); }, $columnsInfo)); $attributes = $this->doctrine->getRepository($this->attributeClass)->findBy(array('code' => $codes)); $attributeMap = array(); foreach ($attributes as $attribute) { $attributeMap[$attribute->getCode()] = $attribute; } return $attributeMap; }
/** * Returns a JSON response containing options * * @param Request $request * * @return JsonResponse */ public function listAction(Request $request) { $query = $request->query; $repository = $this->doctrine->getRepository($query->get('class')); if ($repository instanceof OptionRepositoryInterface) { $choices = $repository->getOptions($query->get('dataLocale'), $query->get('collectionId'), $query->get('search'), $query->get('options', [])); } elseif ($repository instanceof ReferenceDataRepositoryInterface) { $choices['results'] = $repository->findBySearch($query->get('search'), $query->get('options', [])); } elseif (method_exists($repository, 'getOptions')) { $choices = $repository->getOptions($query->get('dataLocale'), $query->get('collectionId'), $query->get('search'), $query->get('options', [])); } else { throw new \LogicException(sprintf('The repository of the class "%s" can not retrieve options via Ajax.', $query->get('class'))); } return new JsonResponse($choices); }
/** * Returns true of the implementation manages this type of object. * * @param mixed $object * * @return bool */ public function isManaged($object) { if (!is_object($object)) { return false; } $className = get_class($object); if (isset($this->resolvedCache[$className])) { return $this->resolvedCache[$className]; } try { $this->registry->getRepository($className); } catch (MappingException $e) { return $this->resolvedCache[$className] = false; } return $this->resolvedCache[$className] = true; }
/** * @param TokenInterface $token */ protected function getOrCreateAccessToken(TokenInterface $token) { $user = $token->getUser(); $tokenManager = new TokenManager($this->doctrine->getEntityManager(), 'Acme\\SPA\\ApiBundle\\Entity\\OAuth\\AccessToken'); $oauthToken = $tokenManager->findTokenBy(array('user' => $token->getUser())); if (!$oauthToken instanceof AccessToken) { // id 1 is our chaplin client $chaplinClient = $this->doctrine->getRepository('AcmeSPAApiBundle:Oauth\\Client')->find(1); $oauthToken = $tokenManager->createToken(); // TODO: create a more sophisticated access token $oauthToken->setToken(uniqid()); $oauthToken->setClient($chaplinClient); $oauthToken->setUser($user); $oauthToken->updateToken($token); } return $oauthToken; }
/** * @param LifecycleEventArgs */ public function prePersist(LifecycleEventArgs $args) { $build = $args->getEntity(); if (!$build instanceof Build || $build->isPullRequest()) { return; } $em = $this->doctrine->getManager(); $branch = $this->doctrine->getRepository('Model:Branch')->findOneByProjectAndName($build->getProject(), $build->getRef()); if (!$branch) { $this->logger->info('creating non-existing branch', ['project' => $build->getProject()->getId(), 'branch' => $build->getRef()]); $branch = new Branch(); $branch->setName($build->getRef()); $branch->setProject($build->getProject()); $em->persist($branch); } $build->setBranch($branch); }
/** * @param LifecycleEventArgs */ public function prePersist(LifecycleEventArgs $args) { $build = $args->getEntity(); if (!$this->supports($build)) { return; } $em = $this->doctrine->getManager(); $pr = $this->doctrine->getRepository('Model:PullRequest')->findOneBy(['project' => $build->getProject()->getId(), 'ref' => $build->getRef()]); if (!$pr) { $this->logger->info('creating non-existing pr', ['project' => $build->getProject()->getId(), 'ref' => $build->getRef()]); $project = $build->getProject(); if (null === $project) { $this->logger->info('could not find a project for build', ['build_id' => $build->getId()]); } $provider = $this->providerFactory->getProvider($project); $pr = $provider->createPullRequestFromPayload($project, $build->getRawPayload()); $em->persist($pr); } $build->setPullRequest($pr); }
/** * @param array $dateRange * @return int */ public function getCustomerConversionValues($dateRange) { $result = 0; list($start, $end) = $this->dateHelper->getPeriod($dateRange, 'OroCRMMagentoBundle:Customer', 'createdAt'); $customers = $this->doctrine->getRepository('OroCRMMagentoBundle:Customer')->getNewCustomersNumberWhoMadeOrderByPeriod($start, $end, $this->aclHelper); $visits = $this->doctrine->getRepository('OroCRMChannelBundle:Channel')->getVisitsCountByPeriodForChannelType($start, $end, $this->aclHelper, ChannelType::TYPE); if ($visits !== 0) { $result = $customers / $visits; } return $result; }
/** * {@inheritdoc} * * @throws \RuntimeException */ public function finishView(FormView $view, FormInterface $form, array $options) { /** @var ChoiceView $choice */ foreach ($view->vars['choices'] as $choice) { if ($options['select2_template_result']) { $object = $choice->value; if ($this->doctrine && $options['class']) { $object = $this->doctrine->getRepository($options['class'])->find($object); } if (is_string($options['select2_template_result'])) { $choice->attr['data-template-result'] = $this->templating->render($options['select2_template_result'], ['choice' => $choice, 'object' => $object]); } else { $choice->attr['data-template-result'] = call_user_func_array($options['select2_template_result'], [$choice, $object]); } } if ($options['select2_template_selection']) { $object = $choice->value; if ($this->doctrine && $options['class']) { $object = $this->doctrine->getRepository($options['class'])->find($object); } if (is_string($options['select2_template_selection'])) { $choice->attr['data-template-selection'] = $this->templating->render($options['select2_template_selection'], ['choice' => $choice, 'object' => $object]); } else { $choice->attr['data-template-selection'] = call_user_func_array($options['select2_template_selection'], [$choice, $object]); } } } if ($options['select2'] === true) { if ($options['autocomplete']) { $options['select2_options']['minimumResultsForSearch'] = 0; if (!isset($options['select2_options']['minimumInputLength'])) { $options['select2_options']['minimumInputLength'] = $options['autocomplete_min_length']; } } $this->select2DefaultOptions['theme'] = array_key_value($this->formConfig, 'select2.theme', $this->select2DefaultOptions['theme']); $options['select2_options'] = array_merge($this->select2DefaultOptions, $options['select2_options']); $view->vars['attr']['select2'] = null; $view->vars['attr']['select2-options'] = json_encode($options['select2_options']); } }
public function __construct($defaultLocale, RegistryInterface $doctrine) { $locales = $doctrine->getRepository('Orkestro\\Bundle\\LocaleBundle\\Model\\Locale')->findBy(array('isEnabled' => true), array('isFallback' => 'DESC')); /** @var Locale $locale */ foreach ($locales as $locale) { if ($locale->getIsFallback()) { $this->defaultLocaleCode = $locale->getCode(); } $this->availableLocales[] = $locale->getCode(); } if (empty($this->defaultLocaleCode)) { $this->defaultLocaleCode = $defaultLocale; } }
/** * @param string $connector * @param string $jobName * @param array $configuration * @param Integration $integration * @param boolean $saveStatus * * @return boolean */ protected function processImport($connector, $jobName, $configuration, Integration $integration, $saveStatus) { $jobResult = $this->jobExecutor->executeJob(ProcessorRegistry::TYPE_IMPORT, $jobName, $configuration); /** @var ContextInterface $contexts */ $context = $jobResult->getContext(); $counts = []; if ($context) { $counts['process'] = $counts['warnings'] = 0; $counts['read'] = $context->getReadCount(); $counts['process'] += $counts['add'] = $context->getAddCount(); $counts['process'] += $counts['update'] = $context->getUpdateCount(); $counts['process'] += $counts['delete'] = $context->getDeleteCount(); } $exceptions = $jobResult->getFailureExceptions(); $isSuccess = $jobResult->isSuccessful() && empty($exceptions); $connectorData = $context->getValue(ConnectorInterface::CONTEXT_CONNECTOR_DATA_KEY); $status = new Status(); $status->setConnector($connector); if (is_array($connectorData)) { $status->setData($connectorData); } if (!$isSuccess) { $this->logger->error('Errors were occurred:'); $exceptions = implode(PHP_EOL, $exceptions); $this->logger->error($exceptions, ['exceptions' => $jobResult->getFailureExceptions()]); $status->setCode(Status::STATUS_FAILED)->setMessage($exceptions); } else { $message = ''; if ($context->getErrors()) { $message = 'Some entities were skipped due to warnings:'; foreach ($context->getErrors() as $error) { $message .= $error . PHP_EOL; } $this->logger->warning($message); } $message .= sprintf("Stats: read [%d], process [%d], updated [%d], added [%d], delete [%d], invalid entities: [%d]", $counts['read'], $counts['process'], $counts['update'], $counts['add'], $counts['delete'], $context->getErrorEntriesCount()); $this->logger->info($message); $status->setCode(Status::STATUS_COMPLETED)->setMessage($message); } if ($saveStatus) { $this->doctrineRegistry->getRepository('OroIntegrationBundle:Channel')->addStatus($integration, $status); if ($integration->getEditMode() < Integration::EDIT_MODE_RESTRICTED) { $integration->setEditMode(Integration::EDIT_MODE_RESTRICTED); } } return $isSuccess; }
/** * @param WidgetOptionBag $widgetOptions * * @return array */ protected function getOwnerIds(WidgetOptionBag $widgetOptions) { $owners = $widgetOptions->get('owners'); $owners = is_array($owners) ? $owners : [$owners]; $ownerIds = []; foreach ($owners as $owner) { if (is_object($owner)) { $ownerIds[] = $owner->getId(); } } $businessUnitIds = $this->getBusinessUnitsIds($widgetOptions); if (!empty($businessUnitIds)) { //need to load from repository, because it returns unserialized object without users from widget options $businessUnits = $this->doctrine->getRepository('OroOrganizationBundle:BusinessUnit')->findById($businessUnitIds); foreach ($businessUnits as $businessUnit) { $users = $businessUnit->getUsers(); foreach ($users as $user) { $ownerIds[] = $user->getId(); } } $ownerIds = array_unique($ownerIds); } return $ownerIds; }
/** * @return array */ protected function getMenu() : array { $menu = $this->doctrine->getRepository("AppBundle:Menu")->getPages(); return $menu; }
/** * Creates a transformer for the given options * * @param array $options * * @return \Symfony\Component\Form\DataTransformerInterface */ public function create(array $options) { $repository = $this->doctrine->getRepository($options['class']); return new $this->class($repository, $this->renderer, $options); }
/** * Get the attribute repository * @return AttributeRepositoryInterface */ protected function getAttributeRepository() { return $this->doctrine->getRepository($this->attributeClass); }
private function updateInformation(Package $package, PackageInterface $data, $flags) { $em = $this->doctrine->getManager(); $version = new Version(); $normVersion = $data->getVersion(); $existingVersion = $package->getVersion($normVersion); if ($existingVersion) { $source = $existingVersion->getSource(); // update if the right flag is set, or the source reference has changed (re-tag or new commit on branch) if ($source['reference'] !== $data->getSourceReference() || $flags & self::UPDATE_EQUAL_REFS) { $version = $existingVersion; } else { // mark it updated to avoid it being pruned $existingVersion->setUpdatedAt(new \DateTime()); return false; } } $version->setName($package->getName()); $version->setVersion($data->getPrettyVersion()); $version->setNormalizedVersion($normVersion); $version->setDevelopment($data->isDev()); $em->persist($version); $descr = $this->sanitize($data->getDescription()); $version->setDescription($descr); $package->setDescription($descr); $version->setHomepage($data->getHomepage()); $version->setLicense($data->getLicense() ?: array()); $version->setPackage($package); $version->setUpdatedAt(new \DateTime()); $version->setReleasedAt($data->getReleaseDate()); if ($data->getSourceType()) { $source['type'] = $data->getSourceType(); $source['url'] = $data->getSourceUrl(); $source['reference'] = $data->getSourceReference(); $version->setSource($source); } else { $version->setSource(null); } if ($data->getDistType()) { $dist['type'] = $data->getDistType(); $dist['url'] = $data->getDistUrl(); $dist['reference'] = $data->getDistReference(); $dist['shasum'] = $data->getDistSha1Checksum(); $version->setDist($dist); } else { $version->setDist(null); } if ($data->getType()) { $type = $this->sanitize($data->getType()); $version->setType($type); if ($type !== $package->getType()) { $package->setType($type); } } $version->setTargetDir($data->getTargetDir()); $version->setAutoload($data->getAutoload()); $version->setExtra($data->getExtra()); $version->setBinaries($data->getBinaries()); $version->setIncludePaths($data->getIncludePaths()); $version->setSupport($data->getSupport()); if ($data->getKeywords()) { $keywords = array(); foreach ($data->getKeywords() as $keyword) { $keywords[mb_strtolower($keyword, 'UTF-8')] = $keyword; } $existingTags = []; foreach ($version->getTags() as $tag) { $existingTags[mb_strtolower($tag->getName(), 'UTF-8')] = $tag; } foreach ($keywords as $tagKey => $keyword) { if (isset($existingTags[$tagKey])) { unset($existingTags[$tagKey]); continue; } $tag = Tag::getByName($em, $keyword, true); if (!$version->getTags()->contains($tag)) { $version->addTag($tag); } } foreach ($existingTags as $tag) { $version->getTags()->removeElement($tag); } } elseif (count($version->getTags())) { $version->getTags()->clear(); } $authorRepository = $this->doctrine->getRepository('PackagistWebBundle:Author'); $version->getAuthors()->clear(); if ($data->getAuthors()) { foreach ($data->getAuthors() as $authorData) { $author = null; foreach (array('email', 'name', 'homepage', 'role') as $field) { if (isset($authorData[$field])) { $authorData[$field] = trim($authorData[$field]); if ('' === $authorData[$field]) { $authorData[$field] = null; } } else { $authorData[$field] = null; } } // skip authors with no information if (!isset($authorData['email']) && !isset($authorData['name'])) { continue; } $author = $authorRepository->findOneBy(array('email' => $authorData['email'], 'name' => $authorData['name'], 'homepage' => $authorData['homepage'], 'role' => $authorData['role'])); if (!$author) { $author = new Author(); $em->persist($author); } foreach (array('email', 'name', 'homepage', 'role') as $field) { if (isset($authorData[$field])) { $author->{'set' . $field}($authorData[$field]); } } // only update the author timestamp once a month at most as the value is kinda unused if ($author->getUpdatedAt() === null || $author->getUpdatedAt()->getTimestamp() < time() - 86400 * 30) { $author->setUpdatedAt(new \DateTime()); } if (!$version->getAuthors()->contains($author)) { $version->addAuthor($author); } if (!$author->getVersions()->contains($version)) { $author->addVersion($version); } } } // handle links foreach ($this->supportedLinkTypes as $linkType => $opts) { $links = array(); foreach ($data->{$opts['method']}() as $link) { $constraint = $link->getPrettyConstraint(); if (false !== strpos($constraint, ',') && false !== strpos($constraint, '@')) { $constraint = preg_replace_callback('{([><]=?\\s*[^@]+?)@([a-z]+)}i', function ($matches) { if ($matches[2] === 'stable') { return $matches[1]; } return $matches[1] . '-' . $matches[2]; }, $constraint); } $links[$link->getTarget()] = $constraint; } foreach ($version->{'get' . $linkType}() as $link) { // clear links that have changed/disappeared (for updates) if (!isset($links[$link->getPackageName()]) || $links[$link->getPackageName()] !== $link->getPackageVersion()) { $version->{'get' . $linkType}()->removeElement($link); $em->remove($link); } else { // clear those that are already set unset($links[$link->getPackageName()]); } } foreach ($links as $linkPackageName => $linkPackageVersion) { $class = 'Packagist\\WebBundle\\Entity\\' . $opts['entity']; $link = new $class(); $link->setPackageName($linkPackageName); $link->setPackageVersion($linkPackageVersion); $version->{'add' . $linkType . 'Link'}($link); $link->setVersion($version); $em->persist($link); } } // handle suggests if ($suggests = $data->getSuggests()) { foreach ($version->getSuggest() as $link) { // clear links that have changed/disappeared (for updates) if (!isset($suggests[$link->getPackageName()]) || $suggests[$link->getPackageName()] !== $link->getPackageVersion()) { $version->getSuggest()->removeElement($link); $em->remove($link); } else { // clear those that are already set unset($suggests[$link->getPackageName()]); } } foreach ($suggests as $linkPackageName => $linkPackageVersion) { $link = new SuggestLink(); $link->setPackageName($linkPackageName); $link->setPackageVersion($linkPackageVersion); $version->addSuggestLink($link); $link->setVersion($version); $em->persist($link); } } elseif (count($version->getSuggest())) { // clear existing suggests if present foreach ($version->getSuggest() as $link) { $em->remove($link); } $version->getSuggest()->clear(); } if (!$package->getVersions()->contains($version)) { $package->addVersions($version); } return true; }
/** * @return CronJobRepository */ protected function getJobRepo() { return $this->registry->getRepository('CronCronBundle:CronJob'); }
/** * Dump a set of packages to the web root * * @param array $packageIds * @param Boolean $force * @param Boolean $verbose */ public function dump(array $packageIds, $force = false, $verbose = false) { $cleanUpOldFiles = date('i') == 0; // prepare build dir $webDir = $this->webDir; $buildDir = $this->buildDir; $retries = 5; do { if (!$this->cfs->removeDirectory($buildDir)) { usleep(200); } clearstatcache(); } while (is_dir($buildDir) && $retries--); if (is_dir($buildDir)) { echo 'Could not remove the build dir entirely, aborting'; return false; } $this->fs->mkdir($buildDir); $this->fs->mkdir($webDir . '/p/'); if (!$force) { if ($verbose) { echo 'Copying existing files' . PHP_EOL; } exec('cp -rpf ' . escapeshellarg($webDir . '/p') . ' ' . escapeshellarg($buildDir . '/p'), $output, $exit); if (0 !== $exit) { $this->fs->mirror($webDir . '/p/', $buildDir . '/p/', null, array('override' => true)); } } $modifiedIndividualFiles = array(); $total = count($packageIds); $current = 0; $step = 50; while ($packageIds) { $dumpTime = new \DateTime(); $packages = $this->doctrine->getRepository('PackagistWebBundle:Package')->getPackagesWithVersions(array_splice($packageIds, 0, $step)); if ($verbose) { echo '[' . sprintf('%' . strlen($total) . 'd', $current) . '/' . $total . '] Processing ' . $step . ' packages' . PHP_EOL; } $current += $step; // prepare packages in memory foreach ($packages as $package) { $affectedFiles = array(); $name = strtolower($package->getName()); // clean up versions in individual files if (file_exists($buildDir . '/p/' . $name . '.files')) { $files = json_decode(file_get_contents($buildDir . '/p/' . $name . '.files')); foreach ($files as $file) { $key = $this->getIndividualFileKey($buildDir . '/' . $file); $this->loadIndividualFile($buildDir . '/' . $file, $key); if (isset($this->individualFiles[$key]['packages'][$name])) { unset($this->individualFiles[$key]['packages'][$name]); $modifiedIndividualFiles[$key] = true; } } } // (re)write versions in individual files foreach ($package->getVersions() as $version) { foreach (array_slice($version->getNames(), 0, 150) as $versionName) { if (!preg_match('{^[A-Za-z0-9_-][A-Za-z0-9_.-]*/[A-Za-z0-9_-][A-Za-z0-9_.-]*$}', $versionName) || strpos($versionName, '..')) { continue; } $file = $buildDir . '/p/' . $versionName . '.json'; $key = $this->getIndividualFileKey($file); $this->dumpVersionToIndividualFile($version, $file, $key); $modifiedIndividualFiles[$key] = true; $affectedFiles[$key] = true; } } // store affected files to clean up properly in the next update $this->fs->mkdir(dirname($buildDir . '/p/' . $name)); file_put_contents($buildDir . '/p/' . $name . '.files', json_encode(array_keys($affectedFiles))); $modifiedIndividualFiles['p/' . $name . '.files'] = true; $package->setDumpedAt($dumpTime); } // update dump dates $this->doctrine->getManager()->flush(); $this->doctrine->getManager()->clear(); unset($packages); if ($current % 250 === 0 || !$packageIds) { if ($verbose) { echo 'Dumping individual files' . PHP_EOL; } // dump individual files to build dir foreach ($this->individualFiles as $file => $dummy) { $this->dumpIndividualFile($buildDir . '/' . $file, $file); // write the hashed provider file $hash = hash_file('sha256', $buildDir . '/' . $file); $hashedFile = substr($buildDir . '/' . $file, 0, -5) . '$' . $hash . '.json'; copy($buildDir . '/' . $file, $hashedFile); } $this->individualFiles = array(); } } // prepare individual files listings if ($verbose) { echo 'Preparing individual files listings' . PHP_EOL; } $safeFiles = array(); $individualHashedListings = array(); $finder = Finder::create()->files()->ignoreVCS(true)->name('*.json')->in($buildDir . '/p/')->depth('1'); foreach ($finder as $file) { // skipped hashed files if (strpos($file, '$')) { continue; } $key = $this->getIndividualFileKey(strtr($file, '\\', '/')); if ($force && !isset($modifiedIndividualFiles[$key])) { continue; } // add hashed provider to listing $listing = 'p/' . $this->getTargetListing($file); $key = substr($key, 2, -5); $hash = hash_file('sha256', $file); $safeFiles[] = 'p/' . $key . '$' . $hash . '.json'; $this->listings[$listing]['providers'][$key] = array('sha256' => $hash); $individualHashedListings[$listing] = true; } // prepare root file $rootFile = $buildDir . '/p/packages.json'; $this->rootFile = array('packages' => array()); $url = $this->router->generate('track_download', array('name' => 'VND/PKG')); $this->rootFile['notify'] = str_replace('VND/PKG', '%package%', $url); $this->rootFile['notify-batch'] = $this->router->generate('track_download_batch'); $this->rootFile['providers-url'] = $this->router->generate('home') . 'p/%package%$%hash%.json'; $this->rootFile['search'] = $this->router->generate('search', array('_format' => 'json')) . '?q=%query%'; if ($verbose) { echo 'Dumping individual listings' . PHP_EOL; } // dump listings to build dir foreach ($individualHashedListings as $listing => $dummy) { $this->dumpListing($buildDir . '/' . $listing); $hash = hash_file('sha256', $buildDir . '/' . $listing); $hashedListing = substr($listing, 0, -5) . '$' . $hash . '.json'; rename($buildDir . '/' . $listing, $buildDir . '/' . $hashedListing); $this->rootFile['provider-includes'][str_replace($hash, '%hash%', $hashedListing)] = array('sha256' => $hash); $safeFiles[] = $hashedListing; } if ($verbose) { echo 'Dumping root' . PHP_EOL; } // sort & dump root file ksort($this->rootFile['packages']); ksort($this->rootFile['provider-includes']); $this->dumpRootFile($rootFile); if ($verbose) { echo 'Putting new files in production' . PHP_EOL; } // put the new files in production exec(sprintf('mv %s %s && mv %s %1$s', escapeshellarg($webDir . '/p'), escapeshellarg($webDir . '/p-old'), escapeshellarg($buildDir . '/p')), $out, $exit); if (0 !== $exit) { throw new \RuntimeException("Rename failed:\n\n" . implode("\n", $out)); } if (defined('PHP_WINDOWS_VERSION_BUILD')) { rename($webDir . '/p/packages.json', $webDir . '/packages.json'); } else { $packagesJsonPath = $webDir . '/packages.json'; if (!is_link($packagesJsonPath)) { if (file_exists($packagesJsonPath)) { unlink($packagesJsonPath); } symlink($webDir . '/p/packages.json', $webDir . '/packages.json'); } } // clean up old dir $retries = 5; do { if (!$this->cfs->removeDirectory($webDir . '/p-old')) { usleep(200); } clearstatcache(); } while (is_dir($webDir . '/p-old') && $retries--); // run only once an hour if ($cleanUpOldFiles) { if ($verbose) { echo 'Cleaning up old files' . PHP_EOL; } // clean up old files $finder = Finder::create()->directories()->ignoreVCS(true)->in($webDir . '/p/'); foreach ($finder as $vendorDir) { $vendorFiles = Finder::create()->files()->ignoreVCS(true)->name('/\\$[a-f0-9]+\\.json$/')->date('until 10minutes ago')->in((string) $vendorDir); $hashedFiles = iterator_to_array($vendorFiles->getIterator()); foreach ($hashedFiles as $file) { $key = preg_replace('{(?:.*/|^)(p/[^/]+/[^/$]+\\$[a-f0-9]+\\.json)$}', '$1', strtr($file, '\\', '/')); if (!in_array($key, $safeFiles, true)) { unlink((string) $file); } } } // clean up old provider listings $finder = Finder::create()->depth(0)->files()->name('provider-*.json')->ignoreVCS(true)->in($webDir . '/p/')->date('until 10minutes ago'); $providerFiles = array(); foreach ($finder as $provider) { $key = preg_replace('{(?:.*/|^)(p/[^/$]+\\$[a-f0-9]+\\.json)$}', '$1', strtr($provider, '\\', '/')); if (!in_array($key, $safeFiles, true)) { unlink((string) $provider); } } } return true; }
/** * Returns the repository * * @return \Doctrine\ORM\EntityRepository */ protected function getRepository() { return $this->doctrine->getRepository($this->getFullEntityName()); }
/** * {@inheritdoc} */ public function resolve($referenceDataType) { $referenceDataConf = $this->configurationRegistry->get($referenceDataType); $referenceDataClass = $referenceDataConf->getClass(); return $this->doctrineRegistry->getRepository($referenceDataClass); }
private function updateInformation(OutputInterface $output, RegistryInterface $doctrine, $package, PackageInterface $data) { $em = $doctrine->getEntityManager(); $version = new Version(); $version->setName($package->getName()); $version->setNormalizedVersion(preg_replace('{-dev$}i', '', $data->getVersion())); // check if we have that version yet foreach ($package->getVersions() as $existingVersion) { if ($existingVersion->equals($version)) { // avoid updating newer versions, in case two branches have the same version in their composer.json if ($existingVersion->getReleasedAt() > $data->getReleaseDate()) { return; } if ($existingVersion->getDevelopment()) { $version = $existingVersion; break; } return; } } $version->setVersion($data->getPrettyVersion()); $version->setDevelopment(substr($data->getVersion(), -4) === '-dev'); $em->persist($version); $version->setDescription($data->getDescription()); $package->setDescription($data->getDescription()); $version->setHomepage($data->getHomepage()); $version->setLicense($data->getLicense() ?: array()); $version->setPackage($package); $version->setUpdatedAt(new \DateTime()); $version->setReleasedAt($data->getReleaseDate()); if ($data->getSourceType()) { $source['type'] = $data->getSourceType(); $source['url'] = $data->getSourceUrl(); $source['reference'] = $data->getSourceReference(); $version->setSource($source); } if ($data->getDistType()) { $dist['type'] = $data->getDistType(); $dist['url'] = $data->getDistUrl(); $dist['reference'] = $data->getDistReference(); $dist['shasum'] = $data->getDistSha1Checksum(); $version->setDist($dist); } if ($data->getType()) { $version->setType($data->getType()); if ($data->getType() && $data->getType() !== $package->getType()) { $package->setType($data->getType()); } } $version->setTargetDir($data->getTargetDir()); $version->setAutoload($data->getAutoload()); $version->setExtra($data->getExtra()); $version->setBinaries($data->getBinaries()); $version->getTags()->clear(); if ($data->getKeywords()) { foreach ($data->getKeywords() as $keyword) { $version->addTag(Tag::getByName($em, $keyword, true)); } } $version->getAuthors()->clear(); if ($data->getAuthors()) { foreach ($data->getAuthors() as $authorData) { $author = null; // skip authors with no information if (empty($authorData['email']) && empty($authorData['name'])) { continue; } if (!empty($authorData['email'])) { $author = $doctrine->getRepository('PackagistWebBundle:Author')->findOneByEmail($authorData['email']); } if (!$author && !empty($authorData['homepage'])) { $author = $doctrine->getRepository('PackagistWebBundle:Author')->findOneBy(array('name' => $authorData['name'], 'homepage' => $authorData['homepage'])); } if (!$author && !empty($authorData['name'])) { $author = $doctrine->getRepository('PackagistWebBundle:Author')->findOneByNameAndPackage($authorData['name'], $package); } if (!$author) { $author = new Author(); $em->persist($author); } foreach (array('email', 'name', 'homepage') as $field) { if (isset($authorData[$field])) { $author->{'set' . $field}($authorData[$field]); } } $author->setUpdatedAt(new \DateTime()); if (!$version->getAuthors()->contains($author)) { $version->addAuthor($author); } if (!$author->getVersions()->contains($version)) { $author->addVersion($version); } } } foreach ($this->supportedLinkTypes as $linkType => $linkEntity) { $links = array(); foreach ($data->{'get' . $linkType . 's'}() as $link) { $links[$link->getTarget()] = $link->getPrettyConstraint(); } foreach ($version->{'get' . $linkType}() as $link) { // clear links that have changed/disappeared (for updates) if (!isset($links[$link->getPackageName()]) || $links[$link->getPackageName()] !== $link->getPackageVersion()) { $version->{'get' . $linkType}()->removeElement($link); $em->remove($link); } else { // clear those that are already set unset($links[$link->getPackageName()]); } } foreach ($links as $linkPackageName => $linkPackageVersion) { $class = 'Packagist\\WebBundle\\Entity\\' . $linkEntity; $link = new $class(); $link->setPackageName($linkPackageName); $link->setPackageVersion($linkPackageVersion); $version->{'add' . $linkType . 'Link'}($link); $link->setVersion($version); $em->persist($link); } } if (!$package->getVersions()->contains($version)) { $package->addVersions($version); } }
/** * Dump a set of packages to the web root * * @param array $packageIds * @param Boolean $force * @param Boolean $verbose */ public function dump(array $packageIds, $force = false, $verbose = false) { $cleanUpOldFiles = date('i') == 0; // prepare build dir $webDir = $this->webDir; $buildDirA = $this->buildDir . '/a'; $buildDirB = $this->buildDir . '/b'; // initialize $initialRun = false; if (!is_dir($buildDirA) || !is_dir($buildDirB)) { $initialRun = true; if (!$this->removeDirectory($buildDirA) || !$this->removeDirectory($buildDirB)) { throw new \RuntimeException('Failed to delete ' . $buildDirA . ' or ' . $buildDirB); } $this->fs->mkdir($buildDirA); $this->fs->mkdir($buildDirB); } // set build dir to the not-active one if (realpath($webDir . '/p') === realpath($buildDirA)) { $buildDir = realpath($buildDirB); $oldBuildDir = realpath($buildDirA); } else { $buildDir = realpath($buildDirA); $oldBuildDir = realpath($buildDirB); } // copy existing stuff for smooth BC transition if ($initialRun && !$force) { if (!file_exists($webDir . '/p') || is_link($webDir . '/p')) { @rmdir($buildDir); @rmdir($oldBuildDir); throw new \RuntimeException('Run this again with --force the first time around to make sure it dumps all packages'); } if ($verbose) { echo 'Copying existing files' . PHP_EOL; } foreach (array($buildDir, $oldBuildDir) as $dir) { $this->cloneDir($webDir . '/p', $dir); } } if ($verbose) { echo 'Web dir is ' . $webDir . '/p (' . realpath($webDir . '/p') . ')' . PHP_EOL; echo 'Build dir is ' . $buildDir . PHP_EOL; } // clean the build dir to start over if we are re-dumping everything if ($force) { // disable the write log since we copy everything at the end in forced mode $this->writeLog = false; if ($verbose) { echo 'Cleaning up existing files' . PHP_EOL; } if (!$this->clearDirectory($buildDir)) { return false; } } $dumpTimeUpdates = []; try { $modifiedIndividualFiles = array(); $total = count($packageIds); $current = 0; $step = 50; while ($packageIds) { $dumpTime = new \DateTime(); $packages = $this->doctrine->getRepository('PackagistWebBundle:Package')->getPackagesWithVersions(array_splice($packageIds, 0, $step)); if ($verbose) { echo '[' . sprintf('%' . strlen($total) . 'd', $current) . '/' . $total . '] Processing ' . $step . ' packages' . PHP_EOL; } $current += $step; // prepare packages in memory foreach ($packages as $package) { $affectedFiles = array(); $name = strtolower($package->getName()); // clean up versions in individual files if (file_exists($buildDir . '/' . $name . '.files')) { $files = json_decode(file_get_contents($buildDir . '/' . $name . '.files')); foreach ($files as $file) { if (substr_count($file, '/') > 1) { // handle old .files with p/*/*.json paths $file = preg_replace('{^p/}', '', $file); } $this->loadIndividualFile($buildDir . '/' . $file, $file); if (isset($this->individualFiles[$file]['packages'][$name])) { unset($this->individualFiles[$file]['packages'][$name]); $modifiedIndividualFiles[$file] = true; } } } // (re)write versions in individual files foreach ($package->getVersions() as $version) { foreach (array_slice($version->getNames(), 0, 150) as $versionName) { if (!preg_match('{^[A-Za-z0-9_-][A-Za-z0-9_.-]*/[A-Za-z0-9_-][A-Za-z0-9_.-]*$}', $versionName) || strpos($versionName, '..')) { continue; } $file = $buildDir . '/' . $versionName . '.json'; $key = $versionName . '.json'; $this->dumpVersionToIndividualFile($version, $file, $key); $modifiedIndividualFiles[$key] = true; $affectedFiles[$key] = true; } } // store affected files to clean up properly in the next update $this->fs->mkdir(dirname($buildDir . '/' . $name)); $this->writeFile($buildDir . '/' . $name . '.files', json_encode(array_keys($affectedFiles))); $dumpTimeUpdates[$dumpTime->format('Y-m-d H:i:s')][] = $package->getId(); } unset($packages, $package, $version); $this->doctrine->getManager()->clear(); if ($current % 250 === 0 || !$packageIds) { if ($verbose) { echo 'Dumping individual files' . PHP_EOL; } $this->dumpIndividualFiles($buildDir); } } // prepare individual files listings if ($verbose) { echo 'Preparing individual files listings' . PHP_EOL; } $safeFiles = array(); $individualHashedListings = array(); $finder = Finder::create()->files()->ignoreVCS(true)->name('*.json')->in($buildDir)->depth('1'); foreach ($finder as $file) { // skip hashed files if (strpos($file, '$')) { continue; } $key = basename(dirname($file)) . '/' . basename($file); if ($force && !isset($modifiedIndividualFiles[$key])) { continue; } // add hashed provider to listing $listing = $this->getTargetListing($file); $hash = hash_file('sha256', $file); $key = substr($key, 0, -5); $safeFiles[] = $key . '$' . $hash . '.json'; $this->listings[$listing]['providers'][$key] = array('sha256' => $hash); $individualHashedListings[$listing] = true; } // prepare root file $rootFile = $buildDir . '/packages.json'; $this->rootFile = array('packages' => array()); $url = $this->router->generate('track_download', array('name' => 'VND/PKG')); $this->rootFile['notify'] = str_replace('VND/PKG', '%package%', $url); $this->rootFile['notify-batch'] = $this->router->generate('track_download_batch'); $this->rootFile['providers-url'] = $this->router->generate('home') . 'p/%package%$%hash%.json'; $this->rootFile['search'] = $this->router->generate('search', array('_format' => 'json')) . '?q=%query%'; if ($verbose) { echo 'Dumping individual listings' . PHP_EOL; } // dump listings to build dir foreach ($individualHashedListings as $listing => $dummy) { list($listingPath, $hash) = $this->dumpListing($buildDir . '/' . $listing); $hashedListing = basename($listingPath); $this->rootFile['provider-includes']['p/' . str_replace($hash, '%hash%', $hashedListing)] = array('sha256' => $hash); $safeFiles[] = $hashedListing; } if ($verbose) { echo 'Dumping root' . PHP_EOL; } $this->dumpRootFile($rootFile); } catch (\Exception $e) { // restore files as they were before we started $this->cloneDir($oldBuildDir, $buildDir); throw $e; } try { if ($verbose) { echo 'Putting new files in production' . PHP_EOL; } // move away old files for BC update if ($initialRun && file_exists($webDir . '/p') && !is_link($webDir . '/p')) { rename($webDir . '/p', $webDir . '/p-old'); } $this->switchActiveWebDir($webDir, $buildDir); } catch (\Exception $e) { @symlink($oldBuildDir, $webDir . '/p'); throw $e; } try { if ($initialRun || !is_link($webDir . '/packages.json') || $force) { if ($verbose) { echo 'Writing/linking the packages.json' . PHP_EOL; } if (file_exists($webDir . '/packages.json')) { unlink($webDir . '/packages.json'); } if (file_exists($webDir . '/packages.json.gz')) { unlink($webDir . '/packages.json.gz'); } if (defined('PHP_WINDOWS_VERSION_BUILD')) { $sourcePath = $buildDir . '/packages.json'; if (!copy($sourcePath, $webDir . '/packages.json')) { throw new \RuntimeException('Could not copy the packages.json file'); } } else { $sourcePath = 'p/packages.json'; if (!symlink($sourcePath, $webDir . '/packages.json')) { throw new \RuntimeException('Could not symlink the packages.json file'); } if ($this->compress && !symlink($sourcePath . '.gz', $webDir . '/packages.json.gz')) { throw new \RuntimeException('Could not symlink the packages.json.gz file'); } } } } catch (\Exception $e) { $this->switchActiveWebDir($webDir, $oldBuildDir); throw $e; } // clean up old dir if present on BC update if ($initialRun) { $this->removeDirectory($webDir . '/p-old'); } // clean the old build dir if we re-dumped everything if ($force) { if ($verbose) { echo 'Cleaning up old build dir' . PHP_EOL; } if (!$this->clearDirectory($oldBuildDir)) { throw new \RuntimeException('Unrecoverable inconsistent state (old build dir could not be cleared), run with --force again to retry'); } } // copy state to old active dir if ($force) { if ($verbose) { echo 'Copying new contents to old build dir to sync up' . PHP_EOL; } $this->cloneDir($buildDir, $oldBuildDir); } else { if ($verbose) { echo 'Replaying write log in old build dir' . PHP_EOL; } $this->copyWriteLog($buildDir, $oldBuildDir); } // clean up old files once an hour if (!$force && $cleanUpOldFiles) { if ($verbose) { echo 'Cleaning up old files' . PHP_EOL; } $this->cleanOldFiles($buildDir, $oldBuildDir, $safeFiles); } if ($verbose) { echo 'Updating package dump times' . PHP_EOL; } foreach ($dumpTimeUpdates as $dt => $ids) { $retries = 5; // retry loop in case of a lock timeout while ($retries--) { try { $this->doctrine->getManager()->getConnection()->executeQuery('UPDATE package SET dumpedAt=:dumped WHERE id IN (:ids)', ['ids' => $ids, 'dumped' => $dt], ['ids' => Connection::PARAM_INT_ARRAY]); } catch (\Exception $e) { if (!$retries) { throw $e; } sleep(2); } } } // TODO when a package is deleted, it should be removed from provider files, or marked for removal at least return true; }
private function updateInformation(Package $package, PackageInterface $data, $flags) { $em = $this->doctrine->getEntityManager(); $version = new Version(); $version->setNormalizedVersion($data->getVersion()); // check if we have that version yet foreach ($package->getVersions() as $existingVersion) { if ($existingVersion->getNormalizedVersion() === $version->getNormalizedVersion()) { if ($existingVersion->getDevelopment() || $flags & self::UPDATE_TAGS) { $version = $existingVersion; break; } // mark it updated to avoid it being pruned $existingVersion->setUpdatedAt(new \DateTime()); return; } } $version->setName($package->getName()); $version->setVersion($data->getPrettyVersion()); $version->setDevelopment($data->isDev()); $em->persist($version); $version->setDescription($data->getDescription()); $package->setDescription($data->getDescription()); $version->setHomepage($data->getHomepage()); $version->setLicense($data->getLicense() ?: array()); $version->setPackage($package); $version->setUpdatedAt(new \DateTime()); $version->setReleasedAt($data->getReleaseDate()); if ($data->getSourceType()) { $source['type'] = $data->getSourceType(); $source['url'] = $data->getSourceUrl(); $source['reference'] = $data->getSourceReference(); $version->setSource($source); } if ($data->getDistType()) { $dist['type'] = $data->getDistType(); $dist['url'] = $data->getDistUrl(); $dist['reference'] = $data->getDistReference(); $dist['shasum'] = $data->getDistSha1Checksum(); $version->setDist($dist); } if ($data->getType()) { $version->setType($data->getType()); if ($data->getType() && $data->getType() !== $package->getType()) { $package->setType($data->getType()); } } $version->setTargetDir($data->getTargetDir()); $version->setAutoload($data->getAutoload()); $version->setExtra($data->getExtra()); $version->setBinaries($data->getBinaries()); $version->setIncludePaths($data->getIncludePaths()); $version->setSupport($data->getSupport()); $version->getTags()->clear(); if ($data->getKeywords()) { foreach ($data->getKeywords() as $keyword) { $tag = Tag::getByName($em, $keyword, true); if (!$version->getTags()->contains($tag)) { $version->addTag($tag); } } } $authorRepository = $this->doctrine->getRepository('PackagistWebBundle:Author'); $version->getAuthors()->clear(); if ($data->getAuthors()) { foreach ($data->getAuthors() as $authorData) { $author = null; // skip authors with no information if (empty($authorData['email']) && empty($authorData['name'])) { continue; } if (!empty($authorData['email'])) { $author = $authorRepository->findOneByEmail($authorData['email']); } if (!$author && !empty($authorData['homepage'])) { $author = $authorRepository->findOneBy(array('name' => $authorData['name'], 'homepage' => $authorData['homepage'])); } if (!$author && !empty($authorData['name'])) { $author = $authorRepository->findOneByNameAndPackage($authorData['name'], $package); } if (!$author) { $author = new Author(); $em->persist($author); } foreach (array('email', 'name', 'homepage', 'role') as $field) { if (isset($authorData[$field])) { $author->{'set' . $field}($authorData[$field]); } } $author->setUpdatedAt(new \DateTime()); if (!$version->getAuthors()->contains($author)) { $version->addAuthor($author); } if (!$author->getVersions()->contains($version)) { $author->addVersion($version); } } } // handle links foreach ($this->supportedLinkTypes as $linkType => $opts) { $links = array(); foreach ($data->{$opts['method']}() as $link) { $constraint = $link->getPrettyConstraint(); if (false !== strpos($constraint, '~')) { $constraint = str_replace(array('[', ']'), '', $link->getConstraint()); $constraint = preg_replace('{(\\d\\.\\d)(\\.0)+(?=$|,|-)}', '$1', $constraint); $constraint = preg_replace('{([><=,]) }', '$1', $constraint); $constraint = preg_replace('{(<[0-9.]+)-dev}', '$1', $constraint); } if (false !== strpos($constraint, ',') && false !== strpos($constraint, '@')) { $constraint = preg_replace_callback('{([><]=?\\s*[^@]+?)@([a-z]+)}i', function ($matches) { if ($matches[2] === 'stable') { return $matches[1]; } return $matches[1] . '-' . $matches[2]; }, $constraint); } $links[$link->getTarget()] = $constraint; } foreach ($version->{'get' . $linkType}() as $link) { // clear links that have changed/disappeared (for updates) if (!isset($links[$link->getPackageName()]) || $links[$link->getPackageName()] !== $link->getPackageVersion()) { $version->{'get' . $linkType}()->removeElement($link); $em->remove($link); } else { // clear those that are already set unset($links[$link->getPackageName()]); } } foreach ($links as $linkPackageName => $linkPackageVersion) { $class = 'Packagist\\WebBundle\\Entity\\' . $opts['entity']; $link = new $class(); $link->setPackageName($linkPackageName); $link->setPackageVersion($linkPackageVersion); $version->{'add' . $linkType . 'Link'}($link); $link->setVersion($version); $em->persist($link); } } // handle suggests if ($suggests = $data->getSuggests()) { foreach ($version->getSuggest() as $link) { // clear links that have changed/disappeared (for updates) if (!isset($suggests[$link->getPackageName()]) || $suggests[$link->getPackageName()] !== $link->getPackageVersion()) { $version->getSuggest()->removeElement($link); $em->remove($link); } else { // clear those that are already set unset($suggests[$link->getPackageName()]); } } foreach ($suggests as $linkPackageName => $linkPackageVersion) { $link = new SuggestLink(); $link->setPackageName($linkPackageName); $link->setPackageVersion($linkPackageVersion); $version->addSuggestLink($link); $link->setVersion($version); $em->persist($link); } } if (!$package->getVersions()->contains($version)) { $package->addVersions($version); } }