duplicate projects with all settings (#1465)
This commit is contained in:
@@ -25,6 +25,7 @@ use App\Form\ProjectRateForm;
|
||||
use App\Form\ProjectTeamPermissionForm;
|
||||
use App\Form\Toolbar\ProjectToolbarForm;
|
||||
use App\Form\Type\ProjectType;
|
||||
use App\Project\ProjectDuplicationService;
|
||||
use App\Repository\ActivityRepository;
|
||||
use App\Repository\ProjectRateRepository;
|
||||
use App\Repository\ProjectRepository;
|
||||
@@ -374,6 +375,17 @@ final class ProjectController extends AbstractController
|
||||
return $this->renderProjectForm($project, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(path="/{id}/duplicate", name="admin_project_duplicate", methods={"GET", "POST"})
|
||||
* @Security("is_granted('edit', project)")
|
||||
*/
|
||||
public function duplicateAction(Project $project, Request $request, ProjectDuplicationService $projectDuplicationService)
|
||||
{
|
||||
$newProject = $projectDuplicationService->duplicate($project, $project->getName() . ' [COPY]');
|
||||
|
||||
return $this->redirectToRoute('project_details', ['id' => $newProject->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(path="/{id}/delete", name="admin_project_delete", methods={"GET", "POST"})
|
||||
* @Security("is_granted('delete', project)")
|
||||
|
||||
@@ -31,7 +31,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
class Activity implements EntityWithMetaFields
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
* @var int|null
|
||||
*
|
||||
* @ORM\Column(name="id", type="integer")
|
||||
* @ORM\Id
|
||||
@@ -211,4 +211,12 @@ class Activity implements EntityWithMetaFields
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->id) {
|
||||
$this->id = null;
|
||||
$this->meta = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
trait MetaTableTypeTrait
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
* @var int|null
|
||||
*
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
@@ -234,4 +234,11 @@ trait MetaTableTypeTrait
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->id) {
|
||||
$this->id = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
class Project implements EntityWithMetaFields
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
* @var int|null
|
||||
*
|
||||
* @ORM\Column(name="id", type="integer")
|
||||
* @ORM\Id
|
||||
@@ -382,4 +382,13 @@ class Project implements EntityWithMetaFields
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->id) {
|
||||
$this->id = null;
|
||||
$this->teams = new ArrayCollection();
|
||||
$this->meta = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
trait Rate
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
* @var int|null
|
||||
*
|
||||
* @ORM\Column(name="id", type="integer")
|
||||
* @ORM\Id
|
||||
@@ -89,4 +89,11 @@ trait Rate
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->id) {
|
||||
$this->id = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
102
src/Project/ProjectDuplicationService.php
Normal file
102
src/Project/ProjectDuplicationService.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Project;
|
||||
|
||||
use App\Entity\ActivityRate;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\ProjectRate;
|
||||
use App\Repository\ActivityRateRepository;
|
||||
use App\Repository\ActivityRepository;
|
||||
use App\Repository\ProjectRateRepository;
|
||||
use App\Repository\ProjectRepository;
|
||||
|
||||
final class ProjectDuplicationService
|
||||
{
|
||||
/**
|
||||
* @var ProjectRepository
|
||||
*/
|
||||
private $projectRepository;
|
||||
/**
|
||||
* @var ActivityRepository
|
||||
*/
|
||||
private $activityRepository;
|
||||
/**
|
||||
* @var ProjectRateRepository
|
||||
*/
|
||||
private $projectRateRepository;
|
||||
/**
|
||||
* @var ActivityRateRepository
|
||||
*/
|
||||
private $activityRateRepository;
|
||||
|
||||
public function __construct(
|
||||
ProjectRepository $projectRepository,
|
||||
ActivityRepository $activityRepository,
|
||||
ProjectRateRepository $projectRateRepository,
|
||||
ActivityRateRepository $activityRateRepository
|
||||
) {
|
||||
$this->projectRepository = $projectRepository;
|
||||
$this->activityRepository = $activityRepository;
|
||||
$this->projectRateRepository = $projectRateRepository;
|
||||
$this->activityRateRepository = $activityRateRepository;
|
||||
}
|
||||
|
||||
public function duplicate(Project $project, string $newName): Project
|
||||
{
|
||||
$newProject = clone $project;
|
||||
$newProject->setName($newName);
|
||||
|
||||
foreach ($project->getTeams() as $team) {
|
||||
$newProject->addTeam($team);
|
||||
}
|
||||
|
||||
foreach ($project->getMetaFields() as $metaField) {
|
||||
$newMetaField = clone $metaField;
|
||||
$newMetaField->setEntity($newProject);
|
||||
$newProject->setMetaField($newMetaField);
|
||||
}
|
||||
|
||||
if (null !== $project->getEnd()) {
|
||||
$newProject->setStart(clone $project->getEnd());
|
||||
$newProject->setEnd(null);
|
||||
}
|
||||
|
||||
$this->projectRepository->saveProject($newProject);
|
||||
|
||||
foreach ($this->projectRateRepository->getRatesForProject($project) as $rate) {
|
||||
/** @var ProjectRate $newRate */
|
||||
$newRate = clone $rate;
|
||||
$newRate->setProject($newProject);
|
||||
$this->projectRateRepository->saveRate($newRate);
|
||||
}
|
||||
|
||||
$allActivities = $this->activityRepository->findByProject($project);
|
||||
foreach ($allActivities as $activity) {
|
||||
$newActivity = clone $activity;
|
||||
$newActivity->setProject($newProject);
|
||||
foreach ($activity->getMetaFields() as $metaField) {
|
||||
$newMetaField = clone $metaField;
|
||||
$newMetaField->setEntity($newActivity);
|
||||
$newActivity->setMetaField($newMetaField);
|
||||
}
|
||||
|
||||
$this->activityRepository->saveActivity($newActivity);
|
||||
|
||||
foreach ($this->activityRateRepository->getRatesForActivity($activity) as $rate) {
|
||||
/** @var ActivityRate $newRate */
|
||||
$newRate = clone $rate;
|
||||
$newRate->setActivity($newActivity);
|
||||
$this->activityRateRepository->saveRate($newRate);
|
||||
}
|
||||
}
|
||||
|
||||
return $newProject;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Model\ActivityStatistic;
|
||||
@@ -46,6 +47,15 @@ class ActivityRepository extends EntityRepository
|
||||
return $activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Project $project
|
||||
* @return Activity[]
|
||||
*/
|
||||
public function findByProject(Project $project)
|
||||
{
|
||||
return $this->findBy(['project' => $project]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Activity $activity
|
||||
* @throws ORMException
|
||||
|
||||
Reference in New Issue
Block a user