2 Commits

Author SHA1 Message Date
  raphael 38508a71dd BGC-192 @fixed patch 3 years ago
  raphael 6f8ca9a10e @fixed clonnage des parcours 3 years ago

+ 0
- 1
config/services.yaml View File

@@ -106,7 +106,6 @@ services:
106 106
   # Service de gestion des uploads
107 107
   Logipro\Phoenix\Service\FileUploader:
108 108
     public: true
109
-    arguments: ['@service_container']
110 109
 
111 110
   Logipro\Phoenix\Component\VichUploader\UniqidNamer:
112 111
     public: true

+ 12
- 12
src/Phoenix/Controller/NewBackOffice/Admin/Session/Create/SessionController.php View File

@@ -38,6 +38,7 @@ use Logipro\Phoenix\Service\Session\SessionExportHandler;
38 38
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
39 39
 use Logipro\Phoenix\Form\Session\SessionIntraCreateAndUpdateSocietyType;
40 40
 use Logipro\Phoenix\Controller\NewBackOffice\Admin\BackOfficeAdminController;
41
+use Logipro\Phoenix\Service\EntityDuplicator;
41 42
 
42 43
 class SessionController extends BackOfficeAdminController
43 44
 {
@@ -524,7 +525,7 @@ class SessionController extends BackOfficeAdminController
524 525
 	 * @param int $sessionId
525 526
 	 * @return \Symfony\Component\HttpFoundation\Response
526 527
 	 */
527
-	public function manageImportPath(Request $request, $sessionId)
528
+	public function manageImportPath(Request $request, $sessionId,EntityDuplicator $entityDuplicator)
528 529
 	{
529 530
 		$this->denyAccessUnlessGranted('ROLE_MANAGE_SESSION');
530 531
 
@@ -549,7 +550,7 @@ class SessionController extends BackOfficeAdminController
549 550
 
550 551
 			try {
551 552
 				// Importer le parcours
552
-				$this->importSessionPath($session, $templatePath);
553
+				$this->importSessionPath($session, $templatePath, $entityDuplicator);
553 554
 				$this->addFlash('success', $this->get('translator')->trans('success_learning_path_import'));
554 555
 			} catch (PhoenixException $e) {
555 556
 				$this->addFlash('error', $this->get('translator')->trans('error_import_failed', array('%message%' => $e->getMessage())));
@@ -576,30 +577,29 @@ class SessionController extends BackOfficeAdminController
576 577
 	/**
577 578
 	 *
578 579
 	 * @param Session $session
579
-	 * @param LearningPath $templatePath
580
+	 * @param LearningPath $templateLearningPath
580 581
 	 */
581
-	protected function importSessionPath(Session $session, LearningPath $templatePath)
582
+	protected function importSessionPath(Session $session, LearningPath $templateLearningPath,EntityDuplicator $entityDuplicator): void
582 583
 	{
583
-		$manager = $this->getDoctrine()->getManager();
584
-
585 584
 		if ($session->getLearningPath()) {
586 585
 			//FIXME ???
587 586
 			throw new PhoenixException($this->get('translator')->trans('exception_session_already_learning_path'));
588 587
 		}
589 588
 
590 589
 		// Clonage du gabarit
591
-		$entityDuplicator = $this->get('Logipro\Phoenix\Service\EntityDuplicator');
592
-		$newLearningPath = $entityDuplicator->duplicateLearningPath($templatePath, $session, false);
590
+		$entityDuplicator->duplicateLearningPath($templateLearningPath, $session);
593 591
 
594 592
 		// Durée
593
+		// raph: cet algo n'est pas au niveau de l'event
594
+		// raph: ce ne serait pas une comparaison par rapport à '00:00:00' ??
595 595
 		if ($session->getDuration()->format('%h:%i:%s') == '0:0:0') {
596
-			$session->setDuration($templatePath->getTotalDuration());
596
+			$session->setDuration($templateLearningPath->getTotalDuration());
597
+
598
+			$manager = $this->getDoctrine()->getManager();
599
+			$manager->flush();
597 600
 		}
598
-		$manager->persist($newLearningPath);
599
-		$manager->flush();
600 601
 	}
601 602
 
602
-
603 603
 	/**
604 604
 	 *
605 605
 	 * @param Request $request

+ 70
- 0
src/Phoenix/DoctrineMigrations/Version20191203165250.php View File

@@ -0,0 +1,70 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+namespace Logipro\Phoenix\DoctrineMigrations;
6
+
7
+use Doctrine\DBAL\Schema\Schema;
8
+use Doctrine\Migrations\AbstractMigration;
9
+use Symfony\Component\Filesystem\Filesystem;
10
+use Logipro\Phoenix\Service\FileUploader;
11
+use Logipro\Phoenix\Service\FileUploaderInterface;
12
+use Logipro\Phoenix\Entity\Sequence;
13
+use Symfony\Component\DependencyInjection\ContainerAwareInterface;
14
+use Symfony\Component\DependencyInjection\ContainerInterface;
15
+
16
+final class Version20191203165250 extends AbstractMigration
17
+implements ContainerAwareInterface
18
+{
19
+    private $fileUploader;
20
+
21
+    public function setContainer(ContainerInterface $container = null)
22
+    {
23
+        $this->fileUploader = $container->get(FileUploader::class);
24
+    }
25
+    public function up(Schema $schema): void
26
+    {
27
+        $fileUploader = $this->fileUploader;
28
+        $filesystem = new Filesystem();
29
+        $sequence = new Sequence();
30
+        $propertyName = 'image';
31
+
32
+        // extrait les images des sequences et regarde les sequences qui utilisent plusieurs fois la même image
33
+        $query = "SELECT COUNT(*) as `number`,`image` FROM `phx_sequence` WHERE `image` != '' GROUP BY `image` HAVING `number` > 1";
34
+        foreach ($this->connection->fetchAll($query) as $result) {
35
+            $imageName = $result['image'];
36
+
37
+            // recherche les identifiants des sequences de l'image
38
+            $query = 'SELECT `sequence_id` FROM `phx_sequence` WHERE `image`=\'' . $imageName . '\'';
39
+            $results = $this->connection->fetchAll($query);
40
+
41
+            // supprime le premier
42
+            array_shift($results);
43
+
44
+            // parcours les identifiants pour la copie
45
+            $queries = array();
46
+            foreach ($results as $result) {
47
+                $newFileName = $fileUploader->generateNewName($imageName);
48
+                try {
49
+                    $filesystem->copy(
50
+                        $fileUploader->buildUploadPublicPath($imageName, $sequence, $propertyName),
51
+                        $fileUploader->buildUploadPublicPath($newFileName, $sequence, $propertyName)
52
+                    );
53
+
54
+                    // après la copie, on met a jour l'objet
55
+                    $queries[] = 'UPDATE `phx_sequence` SET `image`=\'' . $newFileName . '\' WHERE `sequence_id`=' . $result['sequence_id'];
56
+                } catch (\Exception $exp) {
57
+                    dump($exp->getMessage());
58
+                }
59
+            }
60
+
61
+            foreach ($queries as $query)
62
+            {
63
+                $this->connection->executeQuery($query);
64
+            }
65
+        }
66
+    }
67
+
68
+    public function down(Schema $schema): void
69
+    { }
70
+}

+ 23
- 14
src/Phoenix/Entity/Assertion/Assertion.php View File

@@ -1,4 +1,5 @@
1 1
 <?php
2
+
2 3
 namespace Logipro\Phoenix\Entity\Assertion;
3 4
 
4 5
 use Logipro\Phoenix\Entity\Common\AbstractEntity;
@@ -44,19 +45,20 @@ class Assertion extends AbstractEntity
44 45
 	protected $testedSequenceItem;
45 46
 
46 47
 	/**
47
-	 *
48
+	 * @deprecated use LearningPathHandler:duplicateTemplate instead
48 49
 	 */
49 50
 	public function __clone()
50 51
 	{
51 52
 		$this->assertionId = null;
52
-		$this->name = $this->name.' clone';
53
-	}	
53
+		$this->name = $this->name . ' clone';
54
+	}
54 55
 
55 56
 	/**
56 57
 	 *
57 58
 	 * @return int
58 59
 	 */
59
-	public function getAssertionId() {
60
+	public function getAssertionId()
61
+	{
60 62
 		return $this->assertionId;
61 63
 	}
62 64
 
@@ -64,7 +66,8 @@ class Assertion extends AbstractEntity
64 66
 	 * Nom de l'affirmation
65 67
 	 * @return string
66 68
 	 */
67
-	public function getName() {
69
+	public function getName()
70
+	{
68 71
 		return $this->name;
69 72
 	}
70 73
 
@@ -72,7 +75,8 @@ class Assertion extends AbstractEntity
72 75
 	 * Ajoute un nom à l'affirmation
73 76
 	 * @param string $name
74 77
 	 */
75
-	public function setName($name) {
78
+	public function setName($name)
79
+	{
76 80
 		$this->name = $name;
77 81
 	}
78 82
 
@@ -81,7 +85,8 @@ class Assertion extends AbstractEntity
81 85
 	 *
82 86
 	 * @return boolean
83 87
 	 */
84
-	public function isChecked() {
88
+	public function isChecked()
89
+	{
85 90
 		return $this->isChecked;
86 91
 	}
87 92
 
@@ -89,7 +94,8 @@ class Assertion extends AbstractEntity
89 94
 	 *
90 95
 	 * @param $isChecked
91 96
 	 */
92
-	public function setIsChecked($isChecked) {
97
+	public function setIsChecked($isChecked)
98
+	{
93 99
 		$this->isChecked = $isChecked;
94 100
 	}
95 101
 
@@ -97,7 +103,8 @@ class Assertion extends AbstractEntity
97 103
 	 *
98 104
 	 * @return ConditionPursuit
99 105
 	 */
100
-	public function getConditionPursuit(): ConditionPursuit {
106
+	public function getConditionPursuit(): ConditionPursuit
107
+	{
101 108
 		return $this->conditionPursuit;
102 109
 	}
103 110
 
@@ -105,7 +112,8 @@ class Assertion extends AbstractEntity
105 112
 	 *
106 113
 	 * @param ConditionPursuit|NULL $conditionPursuit
107 114
 	 */
108
-	public function setConditionPursuit($conditionPursuit) {
115
+	public function setConditionPursuit($conditionPursuit)
116
+	{
109 117
 		$this->conditionPursuit = $conditionPursuit;
110 118
 	}
111 119
 
@@ -114,7 +122,8 @@ class Assertion extends AbstractEntity
114 122
 	 *
115 123
 	 * @return SequenceItem|NULL
116 124
 	 */
117
-	public function getTestedSequenceItem() {
125
+	public function getTestedSequenceItem()
126
+	{
118 127
 		return $this->testedSequenceItem;
119 128
 	}
120 129
 
@@ -122,7 +131,8 @@ class Assertion extends AbstractEntity
122 131
 	 *
123 132
 	 * @return SequenceItem|NULL $testedSequenceItem
124 133
 	 */
125
-	public function setTestedSequenceItem($testedSequenceItem) {
134
+	public function setTestedSequenceItem($testedSequenceItem)
135
+	{
126 136
 		$this->testedSequenceItem = $testedSequenceItem;
127 137
 	}
128 138
 
@@ -131,8 +141,7 @@ class Assertion extends AbstractEntity
131 141
 	 */
132 142
 	public function preRemove()
133 143
 	{
134
-		if (!$this->isDeletable())
135
-		{
144
+		if (!$this->isDeletable()) {
136 145
 			$message = $this->getLastExcuseMessage(EntityExcuse::TYPE_IS_DELETABLE);
137 146
 			throw new PhoenixException($message);
138 147
 		}

+ 1
- 1
src/Phoenix/Entity/Condition/Condition.php View File

@@ -48,7 +48,7 @@ abstract class Condition extends AbstractEntity
48 48
 	}
49 49
 
50 50
 	/**
51
-	 *
51
+	 * @deprecated use LearningPathHandler:duplicateTemplate instead
52 52
 	 */
53 53
 	public function __clone()
54 54
 	{

+ 2
- 0
src/Phoenix/Entity/File/File.php View File

@@ -127,6 +127,8 @@ class File extends AbstractUploadableEntity
127 127
 		return $this;
128 128
 	}
129 129
 
130
+	/**
131
+	 */
130 132
 	public function __clone()
131 133
 	{
132 134
 		$this->fileId = null;

+ 294
- 349
src/Phoenix/Entity/LearningPath.php View File

@@ -1,4 +1,5 @@
1 1
 <?php
2
+
2 3
 namespace Logipro\Phoenix\Entity;
3 4
 
4 5
 use Logipro\Phoenix\Entity\Common\AbstractEntity;
@@ -19,147 +20,92 @@ use Logipro\Phoenix\Entity\ProgramInterface;
19 20
  */
20 21
 class LearningPath extends AbstractEntity implements ProgramInterface
21 22
 {
22
-	/**
23
-	 * ID du parcours.
24
-	 * @var int
25
-	 */
26
-	protected $learningPathId;
27
-
28
-	/**
29
-	 *
30
-	 * @var \DateTime
31
-	 */
32
-	protected $creationDate;
33
-
34
-	/**
35
-	 *
36
-	 * @var \DateTime
37
-	 */
38
-	protected $updateDate;
39
-
40
-	/**
41
-	 * @var string
42
-	 */
43
-	protected $title;
44
-
45
-	/**
46
-	 * @var string
47
-	 */
48
-	protected $description;
49
-
50
-	/**
51
-	 * Si ce parcours est un gabarit.
52
-	 * @var bool
53
-	 */
54
-	protected $isTemplate = false;
55
-
56
-	/**
57
-	 * Si ce parcours est accessible à tout les auteurs.
58
-	 * @var bool
59
-	 */
60
-	protected $isAccessAtAllAuthor = true;
61
-
62
-	/**
63
-	 * Session parente du parcours.
64
-	 * @var SessionFixedFixed
65
-	 */
66
-	protected $session;
67
-
68
-	/**
69
-	 * Gabarit de parcours qui a servi à la création.
70
-	 * @var LearningPath
71
-	 */
72
-	protected $template;
73
-
74
-	/**
75
-	 * Auteur créateur du parcours.
76
-	 * @var User
77
-	 */
78
-	protected $creatingUser;
79
-
80
-	/**
81
-	 * Dernier colaborateur à avoir modifier le parcours.
82
-	 * @var User
83
-	 */
84
-	protected $updatingUser;
85
-
86
-	/**
87
-	 *
88
-	 * @var ArrayCollection
89
-	 */
90
-	protected $sequences;
91
-	
92
-
93
-    /**
94
-	 * Program items
95
-	 * @var ArrayCollection
96
-	 */
97
-	protected $programItems;
98
-	
99
-	protected $isClone = false;
100
-	
101
-	/**
102
-	 * Constructeur de parcours.
103
-	 */
104
-	public function __construct()
105
-	{
106
-		$this->sequences = new ArrayCollection();
107
-		$this->programItems = new ArrayCollection();
108
-	}
109
-
110
-    /**
111
-     * Clonage protégé.
112
-     * Utiliser cloneThisTemplate.
113
-     */
114
-    protected function __clone()
115
-    {
116
-        $this->isClone = true;
117
-        
118
-        $this->learningPathId = null;
23
+    /**
24
+     * ID du parcours.
25
+     * @var int
26
+     */
27
+    protected $learningPathId;
119 28
 
120
-        // Copie les séquences
121
-        $sequences = new ArrayCollection();
122
-        foreach ($this->sequences as $sequence) {
123
-            $newSequence = clone $sequence;
124
-            $newSequence->setLearningPath($this);
29
+    /**
30
+     *
31
+     * @var \DateTime
32
+     */
33
+    protected $creationDate;
125 34
 
126
-            $sequences->add($newSequence);
127
-        }
35
+    /**
36
+     *
37
+     * @var \DateTime
38
+     */
39
+    protected $updateDate;
128 40
 
129
-        $this->sequences = $sequences;
41
+    /**
42
+     * @var string
43
+     */
44
+    protected $title;
130 45
 
131
-        // Copie les éléments de parcours
132
-        $programItems = new ArrayCollection();
133
-        foreach ($this->programItems as $programItem) {
134
-            $newProgramItem = clone $programItem;
135
-            $newProgramItem->setLearningPath($this);
46
+    /**
47
+     * @var string
48
+     */
49
+    protected $description;
136 50
 
137
-            $programItems->add($newProgramItem);
138
-        }
51
+    /**
52
+     * Si ce parcours est un gabarit.
53
+     * @var bool
54
+     */
55
+    protected $isTemplate = false;
139 56
 
140
-        $this->programItems = $programItems;
141
-    }
57
+    /**
58
+     * Si ce parcours est accessible à tout les auteurs.
59
+     * @var bool
60
+     */
61
+    protected $isAccessAtAllAuthor = true;
62
+
63
+    /**
64
+     * Session parente du parcours.
65
+     * @var SessionFixedFixed
66
+     */
67
+    protected $session;
68
+
69
+    /**
70
+     * Gabarit de parcours qui a servi à la création.
71
+     * @var LearningPath
72
+     */
73
+    protected $template;
74
+
75
+    /**
76
+     * Auteur créateur du parcours.
77
+     * @var User
78
+     */
79
+    protected $creatingUser;
80
+
81
+    /**
82
+     * Dernier colaborateur à avoir modifier le parcours.
83
+     * @var User
84
+     */
85
+    protected $updatingUser;
142 86
 
143 87
     /**
144
-     * Retourne une copie du parcours.
145 88
      *
146
-     * @param boolean Le parcours est il un gabarit ?
147
-     * @throws PhoenixException
148
-     * @return \Logipro\Phoenix\Entity\LearningPath
89
+     * @var ArrayCollection
149 90
      */
150
-    public function cloneThisTemplate($isTemplate = false)
151
-    {
152
-        //FIXME Peut-on copier un parcours qui n'est pas un gabarit ?
153
-        if (!$this->isTemplate()) {
154
-            throw new PhoenixException('Ce parcours n\'est pas un gabarit');
155
-        }
91
+    protected $sequences;
92
+
93
+
94
+    /**
95
+     * Program items
96
+     * @var ArrayCollection
97
+     */
98
+    protected $programItems;
156 99
 
157
-        // Clonage du parcours (et de ses éléments enfants en cascade)
158
-        $pathCopy = clone $this;
159
-        $pathCopy->setTemplate($this);
160
-        $pathCopy->setIsTemplate($isTemplate);
100
+    protected $isClone = false;
161 101
 
162
-        return $pathCopy;
102
+    /**
103
+     * Constructeur de parcours.
104
+     */
105
+    public function __construct()
106
+    {
107
+        $this->sequences = new ArrayCollection();
108
+        $this->programItems = new ArrayCollection();
163 109
     }
164 110
 
165 111
     /**
@@ -181,6 +127,12 @@ class LearningPath extends AbstractEntity implements ProgramInterface
181 127
         $this->updateDate = new \DateTime('now');
182 128
     }
183 129
 
130
+    public function __clone()
131
+    {
132
+        $this->learningPathId = null;
133
+        $this->isClone = true;
134
+    }
135
+
184 136
     /**
185 137
      *
186 138
      * @return int
@@ -271,9 +223,10 @@ class LearningPath extends AbstractEntity implements ProgramInterface
271 223
         return $this->session;
272 224
     }
273 225
 
274
-	public function setSession($session) {
275
-		$this->session = $session;
276
-	}
226
+    public function setSession($session)
227
+    {
228
+        $this->session = $session;
229
+    }
277 230
 
278 231
     /**
279 232
      *
@@ -311,21 +264,23 @@ class LearningPath extends AbstractEntity implements ProgramInterface
311 264
         $this->updatingUser = $updatingUser;
312 265
     }
313 266
 
314
-	/**
315
-	 *
316
-	 * @return User|NULL
317
-	 */
318
-	public function getCreatingUser() {
319
-		return $this->creatingUser;
320
-	}
267
+    /**
268
+     *
269
+     * @return User|NULL
270
+     */
271
+    public function getCreatingUser()
272
+    {
273
+        return $this->creatingUser;
274
+    }
321 275
 
322
-	/**
323
-	 *
324
-	 * @param User|NULL $creatingUser
325
-	 */
326
-	public function setCreatingUser($creatingUser) {
327
-		$this->creatingUser = $creatingUser;
328
-	}
276
+    /**
277
+     *
278
+     * @param User|NULL $creatingUser
279
+     */
280
+    public function setCreatingUser($creatingUser)
281
+    {
282
+        $this->creatingUser = $creatingUser;
283
+    }
329 284
 
330 285
     /**
331 286
      *
@@ -371,6 +326,12 @@ class LearningPath extends AbstractEntity implements ProgramInterface
371 326
         $this->sequences->removeElement($sequence);
372 327
     }
373 328
 
329
+    public function setSequences($sequences)
330
+    {
331
+        $this->sequences = $sequences;
332
+    }
333
+
334
+
374 335
     /**
375 336
      * Retourne le dossier d'un parcours
376 337
      * @return string
@@ -478,7 +439,7 @@ class LearningPath extends AbstractEntity implements ProgramInterface
478 439
         }
479 440
         return $events;
480 441
     }
481
-    
442
+
482 443
     public function getEventClassrooms()
483 444
     {
484 445
         $events = array();
@@ -506,7 +467,7 @@ class LearningPath extends AbstractEntity implements ProgramInterface
506 467
 
507 468
         return $this;
508 469
     }
509
-    
470
+
510 471
     /**
511 472
      * Get program items
512 473
      *
@@ -531,205 +492,189 @@ class LearningPath extends AbstractEntity implements ProgramInterface
531 492
     public function removeProgramItem(ProgramItem $programItem)
532 493
     {
533 494
         $this->programItems->removeElement($programItem);
534
-	}
535
-
536
-	/**
537
-	 * Retourne si le programme est vide ou non
538
-	 *
539
-	 * @return boolean
540
-	 */
541
-	public function programIsEmpty()
542
-	{
543
-		// test si le programme de l'offre a des elements
544
-		if (!empty($this->programItems))
545
-		{
546
-			// test si le programme est complété
547
-			foreach ($this->programItems as $programItem)
548
-			{
549
-				if (!$programItem->isEmpty()) {
550
-					return false;
551
-				}
552
-			}
553
-		}
554
-
555
-		return true;
556
-	}
557
-
558
-	/**
559
-	 * Retourne si le programme, 
560
-	 * à travers les types d'éléments renseignés en param à tester, 
561
-	 * est vide ou non
562
-	 *
563
-	 * @param array $programTypes
564
-	 *
565
-	 * @return boolean
566
-	 */
567
-	public function programIsEmptyFilterByTypes($programTypes)
568
-	{
569
-		// test si le programme de l'offre a des elements
570
-		if (!empty($this->programItems))
571
-		{
572
-			// S'il y a une liste de type d'élément de program a tester
573
-			if (is_array($programTypes))
574
-			{
575
-				// test si le programme est complété
576
-				foreach ($this->programItems as $programItem)
577
-				{
578
-					$programTypeItem = $programItem->getProgramTypeItem();
579
-					// Si le type d'élément est présent dans la liste des types d'élément à tester
580
-					if ($programTypeItem && in_array($programTypeItem->getName(), $programTypes)) {
581
-						if (!$programItem->isEmpty()) {
582
-							return false;
583
-						}
584
-					}
585
-				}
586
-			}
587
-			else
588
-			{
589
-				$this->programIsEmpty();
590
-			}
591
-		}
592
-
593
-		return true;
594
-	}
595
-	
596
-	/**
597
-	 * Retourne le cumul des durées des sequences du parcours
598
-	 *
599
-	 * @return DateInterval
600
-	 */
601
-	public function getTotalDuration()
602
-	{
603
-		$duration = 0;
604
-
605
-		$totalSeconds = 0;
606
-		
607
-		foreach ($this->sequences as $sequence)
608
-		{
609
-			foreach ($sequence->getSequenceItems() as $sequenceItem)
610
-			{
611
-				if ($sequenceItem->getSequenceItemId())
612
-				{
613
-					$sequenceItemDuration = $sequenceItem->getDuration();
614
-					if ($sequenceItemDuration)
615
-					{
616
-						$totalSeconds += $sequenceItemDuration->h * 3600;
617
-						$totalSeconds += $sequenceItemDuration->i * 60;
618
-						$totalSeconds += $sequenceItemDuration->s;
619
-					}
620
-				}
621
-			}
622
-		}
623
-
624
-		$dateIntervalReturn = new \DateInterval('PT'.$totalSeconds.'S');
625
-		
626
-		return $dateIntervalReturn;
627
-	}
628
-
629
-	
630
-	
631
-	/**
632
-	 * Definit si une sequence est verouillée (en fonction du sequence item conditionable qui la précède)
633
-	 */
634
-	public function getLastSequenceItemStartedByLearner($learner)
635
-	{
636
-		// Recuperation du sequenceItem portant la condition sur celle là
637
-		$repository = $this->entityManager->getRepository(SequenceItem::class);
638
-		$sequenceItem = $repository->findLastSequenceItemStartedOfLearningPathByLearner($learner, $this);
639
-		
640
-		return $sequenceItem;
641
-	}
642
-
643
-	/**
644
-	 * Retourne les sequences items du parcours
645
-	 *
646
-	 * @return SequenceItem[]
647
-	 */
648
-	public function getSequenceItems()
649
-	{
650
-		$items = array();
651
-		foreach ($this->sequences as $sequence)
652
-		{
653
-			$sequenceItems = $sequence->getSequenceItems();
654
-			foreach ($sequenceItems as $sequenceItem)
655
-			{
656
-				$items[] = $sequenceItem;
657
-			}
658
-		}
659
-		return $items;
660
-	}
661
-
662
-	/**
663
-	 * retourne le mode du parcours
664
-	 * 
665
-	 * @return string
666
-	 */
667
-	public function getMode()
668
-	{
669
-		$items = $this->getSequenceItems();
670
-
671
-		$type = null;
672
-		foreach ($items as $item)
673
-		{
674
-			switch (get_class($item))
675
-			{
676
-				// présentiel
677
-				case EventClassroom::class:
678
-				case EventVirtualClassroom::class:
679
-					if (is_null($type))
680
-					{
681
-						$type = EnumSessionModeType::SESSION_MODE_FACE_TO_FACE;
682
-					}
683
-					elseif ($type == EnumSessionModeType::SESSION_MODE_E_LEARNING)
684
-					{
685
-						$type = EnumSessionModeType::SESSION_MODE_BLENDED;
686
-					}
687
-					break;
688
-
689
-				// virtuel
690
-				case ActivityPage::class:
691
-				case ActivityPackage::class:
692
-				//case EventVirtualClassroom::class:
693
-					if (is_null($type))
694
-					{
695
-						$type = EnumSessionModeType::SESSION_MODE_E_LEARNING;
696
-					}
697
-					elseif ($type == EnumSessionModeType::SESSION_MODE_FACE_TO_FACE)
698
-					{
699
-						$type = EnumSessionModeType::SESSION_MODE_BLENDED;
700
-					}
701
-					break;
702
-			}
703
-		}
704
-		return $type;
705
-	}
706
-
707
-	public function getIsClone()
708
-	{
709
-		return $this->isClone;
710
-	}
711
-	
712
-	/**
713
-	 * Get si ce parcours est accessible à tout les auteurs.
714
-	 *
715
-	 * @return  bool
716
-	 */ 
717
-	public function getIsAccessAtAllAuthor()
718
-	{
719
-		return $this->isAccessAtAllAuthor;
720
-	}
721
-
722
-	/**
723
-	 * Set si ce parcours est accessible à tout les auteurs.
724
-	 *
725
-	 * @param  bool  $isAccessAtAllAuthor  Si ce parcours est accessible à tout les auteurs.
726
-	 *
727
-	 * @return  self
728
-	 */ 
729
-	public function setIsAccessAtAllAuthor(bool $isAccessAtAllAuthor)
730
-	{
731
-		$this->isAccessAtAllAuthor = $isAccessAtAllAuthor;
732
-
733
-		return $this;
734
-	}
495
+    }
496
+
497
+    public function setProgramItems($programItems)
498
+    {
499
+        $this->programItems = $programItems;
500
+    }
501
+
502
+    /**
503
+     * Retourne si le programme est vide ou non
504
+     *
505
+     * @return boolean
506
+     */
507
+    public function programIsEmpty()
508
+    {
509
+        // test si le programme de l'offre a des elements
510
+        if (!empty($this->programItems)) {
511
+            // test si le programme est complété
512
+            foreach ($this->programItems as $programItem) {
513
+                if (!$programItem->isEmpty()) {
514
+                    return false;
515
+                }
516
+            }
517
+        }
518
+
519
+        return true;
520
+    }
521
+
522
+    /**
523
+     * Retourne si le programme, 
524
+     * à travers les types d'éléments renseignés en param à tester, 
525
+     * est vide ou non
526
+     *
527
+     * @param array $programTypes
528
+     *
529
+     * @return boolean
530
+     */
531
+    public function programIsEmptyFilterByTypes($programTypes)
532
+    {
533
+        // test si le programme de l'offre a des elements
534
+        if (!empty($this->programItems)) {
535
+            // S'il y a une liste de type d'élément de program a tester
536
+            if (is_array($programTypes)) {
537
+                // test si le programme est complété
538
+                foreach ($this->programItems as $programItem) {
539
+                    $programTypeItem = $programItem->getProgramTypeItem();
540
+                    // Si le type d'élément est présent dans la liste des types d'élément à tester
541
+                    if ($programTypeItem && in_array($programTypeItem->getName(), $programTypes)) {
542
+                        if (!$programItem->isEmpty()) {
543
+                            return false;
544
+                        }
545
+                    }
546
+                }
547
+            } else {
548
+                $this->programIsEmpty();
549
+            }
550
+        }
551
+
552
+        return true;
553
+    }
554
+
555
+    /**
556
+     * Retourne le cumul des durées des sequences du parcours
557
+     *
558
+     * @return DateInterval
559
+     */
560
+    public function getTotalDuration()
561
+    {
562
+        $duration = 0;
563
+
564
+        $totalSeconds = 0;
565
+
566
+        foreach ($this->sequences as $sequence) {
567
+            foreach ($sequence->getSequenceItems() as $sequenceItem) {
568
+                if ($sequenceItem->getSequenceItemId()) {
569
+                    $sequenceItemDuration = $sequenceItem->getDuration();
570
+                    if ($sequenceItemDuration) {
571
+                        $totalSeconds += $sequenceItemDuration->h * 3600;
572
+                        $totalSeconds += $sequenceItemDuration->i * 60;
573
+                        $totalSeconds += $sequenceItemDuration->s;
574
+                    }
575
+                }
576
+            }
577
+        }
578
+
579
+        $dateIntervalReturn = new \DateInterval('PT' . $totalSeconds . 'S');
580
+
581
+        return $dateIntervalReturn;
582
+    }
583
+
584
+
585
+
586
+    /**
587
+     * Definit si une sequence est verouillée (en fonction du sequence item conditionable qui la précède)
588
+     */
589
+    public function getLastSequenceItemStartedByLearner($learner)
590
+    {
591
+        // Recuperation du sequenceItem portant la condition sur celle là
592
+        $repository = $this->entityManager->getRepository(SequenceItem::class);
593
+        $sequenceItem = $repository->findLastSequenceItemStartedOfLearningPathByLearner($learner, $this);
594
+
595
+        return $sequenceItem;
596
+    }
597
+
598
+    /**
599
+     * Retourne les sequences items du parcours
600
+     *
601
+     * @return SequenceItem[]
602
+     */
603
+    public function getSequenceItems()
604
+    {
605
+        $items = array();
606
+        foreach ($this->sequences as $sequence) {
607
+            $sequenceItems = $sequence->getSequenceItems();
608
+            foreach ($sequenceItems as $sequenceItem) {
609
+                $items[] = $sequenceItem;
610
+            }
611
+        }
612
+        return $items;
613
+    }
614
+
615
+    /**
616
+     * retourne le mode du parcours
617
+     * 
618
+     * @return string
619
+     */
620
+    public function getMode()
621
+    {
622
+        $items = $this->getSequenceItems();
623
+
624
+        $type = null;
625
+        foreach ($items as $item) {
626
+            switch (get_class($item)) {
627
+                    // présentiel
628
+                case EventClassroom::class:
629
+                case EventVirtualClassroom::class:
630
+                    if (is_null($type)) {
631
+                        $type = EnumSessionModeType::SESSION_MODE_FACE_TO_FACE;
632
+                    } elseif ($type == EnumSessionModeType::SESSION_MODE_E_LEARNING) {
633
+                        $type = EnumSessionModeType::SESSION_MODE_BLENDED;
634
+                    }
635
+                    break;
636
+
637
+                    // virtuel
638
+                case ActivityPage::class:
639
+                case ActivityPackage::class:
640
+                    //case EventVirtualClassroom::class:
641
+                    if (is_null($type)) {
642
+                        $type = EnumSessionModeType::SESSION_MODE_E_LEARNING;
643
+                    } elseif ($type == EnumSessionModeType::SESSION_MODE_FACE_TO_FACE) {
644
+                        $type = EnumSessionModeType::SESSION_MODE_BLENDED;
645
+                    }
646
+                    break;
647
+            }
648
+        }
649
+        return $type;
650
+    }
651
+
652
+    public function getIsClone()
653
+    {
654
+        return $this->isClone;
655
+    }
656
+
657
+    /**
658
+     * Get si ce parcours est accessible à tout les auteurs.
659
+     *
660
+     * @return  bool
661
+     */
662
+    public function getIsAccessAtAllAuthor()
663
+    {
664
+        return $this->isAccessAtAllAuthor;
665
+    }
666
+
667
+    /**
668
+     * Set si ce parcours est accessible à tout les auteurs.
669
+     *
670
+     * @param  bool  $isAccessAtAllAuthor  Si ce parcours est accessible à tout les auteurs.
671
+     *
672
+     * @return  self
673
+     */
674
+    public function setIsAccessAtAllAuthor(bool $isAccessAtAllAuthor)
675
+    {
676
+        $this->isAccessAtAllAuthor = $isAccessAtAllAuthor;
677
+
678
+        return $this;
679
+    }
735 680
 }

+ 1
- 1
src/Phoenix/Entity/ProgramItem.php View File

@@ -75,7 +75,7 @@ class ProgramItem extends AbstractEntity
75 75
 	
76 76
 
77 77
 	/**
78
-	 *
78
+	 * @deprecated use LearningPathHandler:duplicateTemplate instead
79 79
 	 */
80 80
 	public function __clone()
81 81
 	{

+ 61
- 99
src/Phoenix/Entity/Sequence.php View File

@@ -1,4 +1,5 @@
1 1
 <?php
2
+
2 3
 namespace Logipro\Phoenix\Entity;
3 4
 
4 5
 use Logipro\Phoenix\Entity\Common\AbstractUploadableEntity;
@@ -46,14 +47,14 @@ class Sequence extends AbstractUploadableEntity
46 47
 	protected $description;
47 48
 
48 49
 	/**
49
-     * @var string
50
-     */
50
+	 * @var string
51
+	 */
51 52
 	private $image;
52 53
 
53
-    /**
54
-     */
54
+	/**
55
+	 */
55 56
 	private $imageFile = null;
56
-	
57
+
57 58
 	/**
58 59
 	 *
59 60
 	 * @var LearningPath
@@ -75,38 +76,11 @@ class Sequence extends AbstractUploadableEntity
75 76
 	}
76 77
 
77 78
 	/**
78
-	 *
79
+	 * @deprecated use LearningPathHandler:duplicateTemplate instead
79 80
 	 */
80 81
 	public function __clone()
81 82
 	{
82 83
 		$this->sequenceId = null;
83
-
84
-		// Copie les éléments
85
-		$items = new ArrayCollection();
86
-		$counter = 0;
87
-		foreach ($this->sequenceItems as $item)
88
-		{
89
-	
90
-			if ($item->getItemType() == 'conditionpursuit')
91
-			{
92
-				$previousSequenceItem = ($items->get($counter-1));
93
-				$item->setAssociatedSequenceItem($previousSequenceItem);
94
-				$newItem = clone $item;
95
-				$newItem->setSequence($this);
96
-			}
97
-			else
98
-			{
99
-				$newItem = clone $item;
100
-				$newItem->setSequence($this);
101
-			}
102
-
103
-
104
-
105
-			$items->add($newItem);
106
-			$counter++;
107
-		}
108
-
109
-		$this->sequenceItems = $items;
110 84
 	}
111 85
 
112 86
 	/**
@@ -132,7 +106,8 @@ class Sequence extends AbstractUploadableEntity
132 106
 	 *
133 107
 	 * @return int
134 108
 	 */
135
-	public function getSequenceId() {
109
+	public function getSequenceId()
110
+	{
136 111
 		return $this->sequenceId;
137 112
 	}
138 113
 
@@ -140,7 +115,8 @@ class Sequence extends AbstractUploadableEntity
140 115
 	 *
141 116
 	 * @return string
142 117
 	 */
143
-	public function getTitle() {
118
+	public function getTitle()
119
+	{
144 120
 		return $this->title;
145 121
 	}
146 122
 
@@ -148,7 +124,8 @@ class Sequence extends AbstractUploadableEntity
148 124
 	 *
149 125
 	 * @param string $title
150 126
 	 */
151
-	public function setTitle($title) {
127
+	public function setTitle($title)
128
+	{
152 129
 		$this->title = $title;
153 130
 	}
154 131
 
@@ -156,7 +133,8 @@ class Sequence extends AbstractUploadableEntity
156 133
 	 *
157 134
 	 * @return string
158 135
 	 */
159
-	public function getDescription() {
136
+	public function getDescription()
137
+	{
160 138
 		return $this->description;
161 139
 	}
162 140
 
@@ -164,7 +142,8 @@ class Sequence extends AbstractUploadableEntity
164 142
 	 *
165 143
 	 * @param string $description
166 144
 	 */
167
-	public function setDescription($description) {
145
+	public function setDescription($description)
146
+	{
168 147
 		$this->description = $description;
169 148
 	}
170 149
 
@@ -192,7 +171,7 @@ class Sequence extends AbstractUploadableEntity
192 171
 	 */
193 172
 	public function hasSequenceItems()
194 173
 	{
195
-		if (count ($this->getSequenceItems()) > 0) {
174
+		if (count($this->getSequenceItems()) > 0) {
196 175
 			return true;
197 176
 		}
198 177
 		return false;
@@ -217,10 +196,10 @@ class Sequence extends AbstractUploadableEntity
217 196
 		$this->sequenceItems = $sequenceItems;
218 197
 		return $this;
219 198
 	}
220
-	
199
+
221 200
 	/**
222
-	* @param SequenceItem $sequenceItem
223
-	*/
201
+	 * @param SequenceItem $sequenceItem
202
+	 */
224 203
 	public function addSequenceItem($sequenceItem)
225 204
 	{
226 205
 		if ($this->sequenceItems->contains($sequenceItem)) {
@@ -240,10 +219,8 @@ class Sequence extends AbstractUploadableEntity
240 219
 
241 220
 		$sequenceItems = $this->getSequenceItems();
242 221
 
243
-		foreach ($sequenceItems as $sequenceItem)
244
-		{
245
-			if ($sequenceItem instanceof ActivityInterface)
246
-			{
222
+		foreach ($sequenceItems as $sequenceItem) {
223
+			if ($sequenceItem instanceof ActivityInterface) {
247 224
 				$number++;
248 225
 			}
249 226
 		}
@@ -261,10 +238,8 @@ class Sequence extends AbstractUploadableEntity
261 238
 
262 239
 		$sequenceItems = $this->getSequenceItems();
263 240
 
264
-		foreach ($sequenceItems as $sequenceItem)
265
-		{
266
-			if ($sequenceItem instanceof EventInterface || $sequenceItem instanceof ActivityInterface)
267
-			{
241
+		foreach ($sequenceItems as $sequenceItem) {
242
+			if ($sequenceItem instanceof EventInterface || $sequenceItem instanceof ActivityInterface) {
268 243
 				$number++;
269 244
 			}
270 245
 		}
@@ -282,10 +257,8 @@ class Sequence extends AbstractUploadableEntity
282 257
 
283 258
 		$sequenceItems = $this->getSequenceItems();
284 259
 
285
-		foreach ($sequenceItems as $sequenceItem)
286
-		{
287
-			if ($sequenceItem instanceof EventInterface)
288
-			{
260
+		foreach ($sequenceItems as $sequenceItem) {
261
+			if ($sequenceItem instanceof EventInterface) {
289 262
 				$number++;
290 263
 			}
291 264
 		}
@@ -304,10 +277,8 @@ class Sequence extends AbstractUploadableEntity
304 277
 
305 278
 		$sequenceItems = $this->getSequenceItems();
306 279
 
307
-		foreach ($sequenceItems as $sequenceItem)
308
-		{
309
-			if ($sequenceItem instanceof EventInterface && $sequenceItem->getStartTime() != null && $now > $sequenceItem->getStartTime())
310
-			{
280
+		foreach ($sequenceItems as $sequenceItem) {
281
+			if ($sequenceItem instanceof EventInterface && $sequenceItem->getStartTime() != null && $now > $sequenceItem->getStartTime()) {
311 282
 				$number++;
312 283
 			}
313 284
 		}
@@ -325,10 +296,8 @@ class Sequence extends AbstractUploadableEntity
325 296
 
326 297
 		$sequenceItems = $this->getSequenceItems();
327 298
 
328
-		foreach ($sequenceItems as $sequenceItem)
329
-		{
330
-			if ($sequenceItem instanceof EventInterface)
331
-			{
299
+		foreach ($sequenceItems as $sequenceItem) {
300
+			if ($sequenceItem instanceof EventInterface) {
332 301
 				if ($sequenceItem->isReadyToBePlayed() === true) {
333 302
 					$number++;
334 303
 				}
@@ -348,10 +317,8 @@ class Sequence extends AbstractUploadableEntity
348 317
 
349 318
 		$sequenceItems = $this->getSequenceItems();
350 319
 
351
-		foreach ($sequenceItems as $sequenceItem)
352
-		{
353
-			if ($sequenceItem instanceof ActivityInterface)
354
-			{
320
+		foreach ($sequenceItems as $sequenceItem) {
321
+			if ($sequenceItem instanceof ActivityInterface) {
355 322
 				if ($sequenceItem->isReadyToBePlayed() === true) {
356 323
 					$number++;
357 324
 				}
@@ -359,14 +326,14 @@ class Sequence extends AbstractUploadableEntity
359 326
 		}
360 327
 		return $number;
361 328
 	}
362
-	
329
+
363 330
 	/**
364 331
 	 * Set the value of updateDate
365 332
 	 *
366 333
 	 * @param  \DateTime  $updateDate
367 334
 	 *
368 335
 	 * @return  self
369
-	 */ 
336
+	 */
370 337
 	public function setUpdateDate(\DateTime $updateDate)
371 338
 	{
372 339
 		$this->updateDate = $updateDate;
@@ -386,34 +353,34 @@ class Sequence extends AbstractUploadableEntity
386 353
 	}
387 354
 
388 355
 	public function setImageFile(?File $image = null)
389
-    {
390
-        $this->imageFile = $image;
356
+	{
357
+		$this->imageFile = $image;
391 358
 
392
-        if ($image) {
359
+		if ($image) {
393 360
 
394 361
 			/**
395 362
 			 * Ce champ n'est pas mappé dans la DB donc il est nécessaire
396 363
 			 * de mettre à jour un champ mappé pour que Dotrine fasse
397 364
 			 * son job de mise à jour.
398 365
 			 */
399
-            $this->updateDate = new \DateTime('now');
400
-        }
401
-    }
366
+			$this->updateDate = new \DateTime('now');
367
+		}
368
+	}
402 369
 
403 370
 	/**
404 371
 	 * retourne le fichier de l'image
405 372
 	 * @return string
406 373
 	 */
407
-    public function getImageFile()
408
-    {
409
-        return $this->imageFile;
410
-    }
374
+	public function getImageFile()
375
+	{
376
+		return $this->imageFile;
377
+	}
411 378
 
412 379
 	/**
413 380
 	 * Get the value of image
414 381
 	 *
415 382
 	 * @return  string
416
-	 */ 
383
+	 */
417 384
 	public function getImage()
418 385
 	{
419 386
 		return $this->image;
@@ -425,7 +392,7 @@ class Sequence extends AbstractUploadableEntity
425 392
 	 * @param  string  $image
426 393
 	 *
427 394
 	 * @return  self
428
-	 */ 
395
+	 */
429 396
 	public function setImage($image)
430 397
 	{
431 398
 		$this->image = $image;
@@ -445,20 +412,19 @@ class Sequence extends AbstractUploadableEntity
445 412
 			'image/gif'
446 413
 		);
447 414
 	}
448
-	
449
-	public function getDownloadName($property = "name",$includeExtension = true)
415
+
416
+	public function getDownloadName($property = "name", $includeExtension = true)
450 417
 	{
451 418
 		$path = $this->image;
452 419
 		$infos = pathinfo($path);
453 420
 
454 421
 		$endName = $this->sanitizeFileName($this->getTitle());
455
-		if (!$includeExtension)
456
-		{
422
+		if (!$includeExtension) {
457 423
 			return $endName;
458 424
 		}
459
-		return $endName .  ".". $infos['extension'];
425
+		return $endName .  "." . $infos['extension'];
460 426
 	}
461
-	
427
+
462 428
 	/**
463 429
 	 * Definit si une sequence est verouillée (en fonction du sequence item conditionable qui la précède)
464 430
 	 */
@@ -467,9 +433,8 @@ class Sequence extends AbstractUploadableEntity
467 433
 		// Recuperation du sequenceItem portant la condition sur celle là
468 434
 		$repository = $this->entityManager->getRepository(SequenceItem::class);
469 435
 		$sequenceItemCondition = $repository->findReferringSequenceItemOfTheConditionBySequence($this);
470
-		
471
-		if ($sequenceItemCondition)
472
-		{
436
+
437
+		if ($sequenceItemCondition) {
473 438
 			$information = $sequenceItemCondition->getInfoLocked($learner);
474 439
 			return $information['locked'];
475 440
 		}
@@ -488,14 +453,11 @@ class Sequence extends AbstractUploadableEntity
488 453
 		$totalSeconds = 0;
489 454
 
490 455
 		$sequenceItems = $this->getSequenceItems();
491
-		
492
-		foreach ($sequenceItems as $sequenceItem)
493
-		{
494
-			if ($sequenceItem->getSequenceItemId())
495
-			{
456
+
457
+		foreach ($sequenceItems as $sequenceItem) {
458
+			if ($sequenceItem->getSequenceItemId()) {
496 459
 				$sequenceItemDuration = $sequenceItem->getDuration();
497
-				if ($sequenceItemDuration)
498
-				{
460
+				if ($sequenceItemDuration) {
499 461
 					$totalSeconds += $sequenceItemDuration->h * 3600;
500 462
 					$totalSeconds += $sequenceItemDuration->i * 60;
501 463
 					$totalSeconds += $sequenceItemDuration->s;
@@ -503,8 +465,8 @@ class Sequence extends AbstractUploadableEntity
503 465
 			}
504 466
 		}
505 467
 
506
-		$dateIntervalReturn = new \DateInterval('PT'.$totalSeconds.'S');
507
-		
468
+		$dateIntervalReturn = new \DateInterval('PT' . $totalSeconds . 'S');
469
+
508 470
 		return $dateIntervalReturn;
509
-	}	
471
+	}
510 472
 }

+ 1
- 1
src/Phoenix/Entity/SequenceItem/ConditionPursuit.php View File

@@ -30,7 +30,7 @@ implements ConditionInterface
30 30
 	}
31 31
 
32 32
 	/**
33
-	 *
33
+	 * @deprecated use LearningPathHandler:duplicateTemplate instead
34 34
 	 */
35 35
 	public function __clone()
36 36
 	{

+ 1
- 1
src/Phoenix/Entity/SequenceItem/SequenceItem.php View File

@@ -113,7 +113,7 @@ abstract class SequenceItem extends AbstractUploadableEntity
113 113
 	}
114 114
 
115 115
 	/**
116
-	 *
116
+	 * @deprecated use LearningPathHandler:duplicateTemplate instead
117 117
 	 */
118 118
 	public function __clone()
119 119
 	{

+ 110
- 22
src/Phoenix/Service/EntityDuplicator.php View File

@@ -1,4 +1,5 @@
1 1
 <?php
2
+
2 3
 namespace Logipro\Phoenix\Service;
3 4
 
4 5
 use Doctrine\Common\Persistence\ManagerRegistry;
@@ -12,6 +13,9 @@ use Symfony\Component\DependencyInjection\ContainerAwareInterface;
12 13
 use Symfony\Component\DependencyInjection\ContainerAwareTrait;
13 14
 use Symfony\Component\DependencyInjection\ContainerInterface;
14 15
 use Logipro\Phoenix\Entity\Session\Session;
16
+use Symfony\Component\Security\Core\Security;
17
+use Logipro\Phoenix\Entity\ProgramItem;
18
+use Doctrine\Common\Collections\ArrayCollection;
15 19
 
16 20
 /**
17 21
  * Service de duplication des entités.
@@ -20,52 +24,136 @@ class EntityDuplicator implements ContainerAwareInterface
20 24
 {
21 25
     use ContainerAwareTrait;
22 26
 
27
+    private $security;
28
+    private $fileUploader;
29
+
23 30
     /**
24 31
      * Constructeur.
25 32
      * @param ContainerInterface $container
26 33
      */
27
-    public function __construct(ContainerInterface $container)
28
-    {
34
+    public function __construct(
35
+        ContainerInterface $container,
36
+        Security $security,
37
+        FileUploader $fileUploader
38
+    ) {
29 39
         $this->setContainer($container);
40
+        $this->security = $security;
41
+        $this->fileUploader = $fileUploader;
30 42
     }
31 43
 
32 44
     /**
33 45
      * Duplique un parcours
34 46
      *
35 47
      * @param LearningPath $learningPath
36
-     * @param bool $isTemplate
37 48
      * @return LearningPath
38 49
      */
39
-    public function duplicateLearningPath(LearningPath $learningPath,Session $session, bool $isTemplate = false)
50
+    public function duplicateLearningPath(LearningPath $learningPath, Session $session = null, bool $isTemplate = false): LearningPath
40 51
     {
41 52
         $em = $this->getDoctrine()->getManager();
42 53
 
43 54
         $newLearningPath = null;
44 55
 
45
-        // Si le parcours existe
46
-        if (!empty($learningPath)) {
47
-            // Si c'est une duplication de template
48
-            if ($isTemplate) {
49
-                $title = '[copie] '.$learningPath->getTitle();
50
-                $newLearningPath = $learningPath->cloneThisTemplate(true);
51
-                $newLearningPath->setTitle($title);
52
-            } else {
53
-                $newLearningPath = $learningPath->cloneThisTemplate();
54
-            }
56
+        // Si c'est une duplication de template
57
+        if ($isTemplate) {
58
+            $title = '[copie] ' . $learningPath->getTitle();
59
+            $newLearningPath = $this->cloneLearningPath($learningPath, true);
60
+            $newLearningPath->setTitle($title);
61
+        } else {
62
+            $newLearningPath = $this->cloneLearningPath($learningPath);
63
+        }
64
+
65
+        $autor = $this->security->getUser();
66
+        $newLearningPath->setCreatingUser($autor);
55 67
 
68
+        if ($session) {
56 69
             $newLearningPath->setSession($session);
57 70
             $session->setLearningPath($newLearningPath);
71
+        }
72
+
73
+        $em->persist($newLearningPath);
74
+        $em->flush();
58 75
 
59
-            $em->persist($newLearningPath);
60
-            $em->flush();
76
+        // Duplication des cours au niveau du moteur SCORM
77
+        $this->duplicateScormCoursesFromPaths($learningPath, $newLearningPath);
61 78
 
62
-            // Duplication des cours au niveau du moteur SCORM
63
-            $this->duplicateScormCoursesFromPaths($learningPath, $newLearningPath);
64
-            
65
-            return $newLearningPath;
79
+        return $newLearningPath;
80
+    }
81
+
82
+    private function cloneLearningPath(LearningPath $learningPath, bool $isTemplate = false): LearningPath
83
+    {
84
+        //FIXME Peut-on copier un parcours qui n'est pas un gabarit ?
85
+        if (!$learningPath->isTemplate()) {
86
+            throw new PhoenixException('Ce parcours n\'est pas un gabarit');
66 87
         }
67 88
 
68
-        throw new PhoenixException($this->container->get('translator')->trans('exception_duplicator_no_learning_path'));
89
+        // Clonage du parcours (et de ses éléments enfants en cascade)
90
+        $pathCopy = clone $learningPath;
91
+
92
+        // Copie les séquences
93
+        $sequences = new ArrayCollection();
94
+        foreach ($learningPath->getSequences() as $sequence) {
95
+            $newSequence = $this->cloneSequence($sequence);
96
+            $newSequence->setLearningPath($pathCopy);
97
+
98
+            $sequences->add($newSequence);
99
+        }
100
+        $pathCopy->setSequences($sequences);
101
+
102
+        // Copie les éléments de parcours
103
+        $programItems = new ArrayCollection();
104
+        foreach ($learningPath->getProgramItems() as $programItem) {
105
+            $newProgramItem = $this->cloneProgramItem($programItem);
106
+            $newProgramItem->setLearningPath($pathCopy);
107
+
108
+            $programItems->add($newProgramItem);
109
+        }
110
+        $pathCopy->setProgramItems($programItems);
111
+
112
+        $pathCopy->setTemplate($learningPath);
113
+        $pathCopy->setIsTemplate($isTemplate);
114
+
115
+        return $pathCopy;
116
+    }
117
+
118
+    private function cloneSequence(Sequence $sequence): Sequence
119
+    {
120
+        $sequenceCopy = clone $sequence;
121
+        // Copie les éléments
122
+        $items = new ArrayCollection();
123
+        $counter = 0;
124
+        foreach ($sequence->getSequenceItems() as $item) {
125
+
126
+            if ($item->getItemType() == 'conditionpursuit') {
127
+                $previousSequenceItem = ($items->get($counter - 1));
128
+                $item->setAssociatedSequenceItem($previousSequenceItem);
129
+                $newItem = $this->cloneSequenceItem($item);
130
+                $newItem->setSequence($sequenceCopy);
131
+            } else {
132
+                $newItem = clone $item;
133
+                $newItem->setSequence($sequenceCopy);
134
+            }
135
+            $items->add($newItem);
136
+            $counter++;
137
+        }
138
+        $sequenceCopy->setSequenceItems($items->toArray());
139
+
140
+        // clone l'image de la sequence
141
+        $name = $this->fileUploader->cloneFile($sequence, 'image');
142
+        $sequenceCopy->setImage($name);
143
+
144
+        return $sequenceCopy;
145
+    }
146
+
147
+    private function cloneProgramItem(ProgramItem $programItem): ProgramItem
148
+    {
149
+        // FIXME à corriger
150
+        return clone $programItem;
151
+    }
152
+
153
+    private function cloneSequenceItem(SequenceItem $sequenceItem): SequenceItem
154
+    {
155
+        // FIXME à corriger
156
+        return clone $sequenceItem;
69 157
     }
70 158
 
71 159
     /**
@@ -115,7 +203,7 @@ class EntityDuplicator implements ContainerAwareInterface
115 203
             // Pour chaque item
116 204
             for ($j = 0; $j < count($originalItems); ++$j) {
117 205
                 $original = $originalItems[$j];
118
-                
206
+
119 207
                 if ($original instanceof ActivityPackage && $original->getPackageType() == AbstractPackageFile::TYPE_SCORM2004) {
120 208
                     $new  = $newItems[$j];
121 209
                     $response = $scormEngine->duplicateCourse($original->getSequenceItemId(), $new->getSequenceItemId());

+ 71
- 13
src/Phoenix/Service/FileUploader.php View File

@@ -6,22 +6,26 @@ use Symfony\Component\DependencyInjection\ContainerAwareInterface;
6 6
 use Symfony\Component\DependencyInjection\ContainerAwareTrait;
7 7
 use Symfony\Component\DependencyInjection\ContainerInterface;
8 8
 use Logipro\Phoenix\Service\FileUploaderInterface;
9
+use Symfony\Component\Filesystem\Filesystem;
10
+use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
11
+use Vich\UploaderBundle\Mapping\PropertyMappingFactory;
12
+use Logipro\Phoenix\Entity\Common\AbstractEntity;
9 13
 
10 14
 /**
11 15
  * Service de gestion des fichiers uploadés.
12 16
  */
13 17
 class FileUploader
14
-implements ContainerAwareInterface, FileUploaderInterface
18
+implements FileUploaderInterface
15 19
 {
16
-	use ContainerAwareTrait;
20
+	private $params;
17 21
 
18 22
 	/**
19 23
 	 * Constructeur.
20
-	 * @param ContainerInterface $container
21 24
 	 */
22
-	public function __construct(ContainerInterface $container)
25
+	public function __construct(ParameterBagInterface $params, PropertyMappingFactory $factory)
23 26
 	{
24
-		$this->setContainer($container);
27
+		$this->params = $params;
28
+		$this->factory = $factory;
25 29
 	}
26 30
 
27 31
 	/**
@@ -66,7 +70,7 @@ implements ContainerAwareInterface, FileUploaderInterface
66 70
 	 */
67 71
 	protected function getUploadPublicRootPath()
68 72
 	{
69
-		return $this->container->getParameter('phoenix.upload_public_directory');
73
+		return $this->params->get('phoenix.upload_public_directory');
70 74
 	}
71 75
 
72 76
 	/**
@@ -75,7 +79,7 @@ implements ContainerAwareInterface, FileUploaderInterface
75 79
 	 */
76 80
 	protected function getUploadPublicRootUrl()
77 81
 	{
78
-		return $this->container->getParameter('phoenix.upload_public_url');
82
+		return $this->params->get('phoenix.upload_public_url');
79 83
 	}
80 84
 
81 85
 	/**
@@ -84,7 +88,7 @@ implements ContainerAwareInterface, FileUploaderInterface
84 88
 	 */
85 89
 	public function getUploadTmpDir()
86 90
 	{
87
-		return $this->container->getParameter('phoenix.upload_tmp_directory');
91
+		return $this->params->get('phoenix.upload_tmp_directory');
88 92
 	}
89 93
 
90 94
 	/**
@@ -93,14 +97,27 @@ implements ContainerAwareInterface, FileUploaderInterface
93 97
 	 * @param string $path Chemin relatif du fichier
94 98
 	 * @return string
95 99
 	 */
96
-	public function buildUploadPublicPath(string $path)
100
+	public function buildUploadPublicPath(string $path = null, AbstractEntity $entity = null, string $propertyName = null)
97 101
 	{
98
-		$pathPrefix = $this->getUploadPublicRootPath();
99
-
100 102
 		// Elimine le slash au début
101
-		$path = ltrim($path, '/');
103
+		$path = ltrim($path, DIRECTORY_SEPARATOR);
102 104
 
103
-		return sprintf('%s/%s', $pathPrefix, $path);
105
+		if ($entity && $propertyName) {
106
+			// ici, sert uniquement à tester si la méthode de l'entité existe
107
+			$this->getEntityValue($entity, $propertyName);
108
+
109
+			// plugin vich uploader
110
+			$mapping = $this->factory->fromObject($entity);
111
+			foreach ($mapping as $map) {
112
+
113
+				if ($map->getFileNamePropertyName() == $propertyName) {
114
+					$pathPrefix = $map->getUploadDestination();
115
+					return $pathPrefix . DIRECTORY_SEPARATOR . $path;
116
+				}
117
+			}
118
+		}
119
+		$pathPrefix = $this->getUploadPublicRootPath();
120
+		return $pathPrefix . DIRECTORY_SEPARATOR . $path;
104 121
 	}
105 122
 
106 123
 	/**
@@ -119,6 +136,14 @@ implements ContainerAwareInterface, FileUploaderInterface
119 136
 		return sprintf('%s/%s', $pathPrefix, $path);
120 137
 	}
121 138
 
139
+	public function getUploadPublicPath(AbstractEntity $entity, string $propertyName)
140
+	{
141
+		$oldFileName = $this->getEntityValue($entity, $propertyName);
142
+
143
+		// fonctionnement normal
144
+		return $this->buildUploadPublicPath($oldFileName, $entity, $propertyName);
145
+	}
146
+
122 147
 	/**
123 148
 	 * Retourne l'URL complète vers un fichier à partir de son chemin
124 149
 	 * relatif dans le répertoire public des uploads.
@@ -134,4 +159,37 @@ implements ContainerAwareInterface, FileUploaderInterface
134 159
 
135 160
 		return sprintf('%s/%s', $urlPrefix, $path);
136 161
 	}
162
+
163
+	private function getEntityValue(AbstractEntity $entity, string $propertyName)
164
+	{
165
+		// test le lien entre le propriété et l'objet
166
+		$getter = 'get' . ucfirst($propertyName);
167
+		if (!method_exists($entity, $getter)) {
168
+			throw new \Exception();
169
+		}
170
+		return $entity->{$getter}();
171
+	}
172
+
173
+	public function generateNewName(string $oldFileName): string
174
+	{
175
+		return uniqid() . '.' . pathinfo($oldFileName, PATHINFO_EXTENSION);
176
+	}
177
+
178
+	public function cloneFile(AbstractEntity $entity, string $propertyName): string
179
+	{
180
+		$filesystem = new Filesystem();
181
+		$oldFileName = $this->getEntityValue($entity, $propertyName);
182
+		$newFileName = $this->generateNewName($oldFileName);
183
+
184
+		try {
185
+			$filesystem->copy(
186
+				$this->buildUploadPublicPath($oldFileName, $entity, $propertyName),
187
+				$this->buildUploadPublicPath($newFileName, $entity, $propertyName)
188
+			);
189
+		} catch (\Exception $exp) {
190
+			dd($exp->getMessage());
191
+		}
192
+
193
+		return $newFileName;
194
+	}
137 195
 }

+ 6
- 10
src/Phoenix/Service/LearningPath/LearningPathHandler.php View File

@@ -9,6 +9,7 @@ use Symfony\Component\Security\Core\Security;
9 9
 use Logipro\Phoenix\Exception\PhoenixException;
10 10
 use Symfony\Component\Translation\TranslatorInterface;
11 11
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
12
+use Logipro\Phoenix\Service\EntityDuplicator;
12 13
 
13 14
 class LearningPathHandler
14 15
 {
@@ -19,12 +20,14 @@ class LearningPathHandler
19 20
 		EntityManagerInterface $manager,
20 21
 		TranslatorInterface $translator,
21 22
 		FlashPhxHandler $flashPhxHandler,
22
-		Security $security
23
+		Security $security,
24
+		EntityDuplicator $entityDuplicator
23 25
 	) {
24 26
 		$this->manager = $manager;
25 27
 		$this->translator = $translator;
26 28
 		$this->flashPhxHandler = $flashPhxHandler;
27 29
 		$this->security = $security;
30
+		$this->entityDuplicator = $entityDuplicator;
28 31
 	}
29 32
 
30 33
 
@@ -59,7 +62,7 @@ class LearningPathHandler
59 62
 	 * @param int $id
60 63
 	 * @return LearningPath|null
61 64
 	 */
62
-	public function duplicateTemplate($id): LearningPath
65
+	public function duplicateTemplate($id)
63 66
 	{
64 67
 		$learningPath = $this->requireLearningPath($id);
65 68
 
@@ -70,15 +73,8 @@ class LearningPathHandler
70 73
 			}
71 74
 
72 75
 			// Clonage du gabarit
73
-
74 76
 			$title = '[' . $this->translator->trans('prefix_learning_path_title_duplicated') . '] ' . $learningPath->getTitle();
75
-			$newLearningPath = $learningPath->cloneThisTemplate(true);
76
-			$newLearningPath->setTitle($title);
77
-			$autor = $this->security->getUser();
78
-			$newLearningPath->setCreatingUser($autor);
79
-
80
-			$this->manager->persist($newLearningPath);
81
-			$this->manager->flush();
77
+			$newLearningPath = $this->entityDuplicator->duplicateLearningPath($learningPath, null, $learningPath->isTemplate());
82 78
 
83 79
 			$this->flashPhxHandler->addFlash('success', $this->translator->trans('success_learning_path_duplicated'));
84 80
 

Loading…
Cancel
Save