Selaa lähdekoodia

Evolution #738: Playlist

Sevajol Bastien 11 vuotta sitten
vanhempi
commit
0efa0f5ea5
25 muutettua tiedostoa jossa 720 lisäystä ja 38 poistoa
  1. 1 0
      app/AppKernel.php
  2. 6 0
      app/config/routing.yml
  3. 28 0
      src/Muzich/CoreBundle/Controller/ElementController.php
  4. 64 1
      src/Muzich/CoreBundle/DataFixtures/ORM/LoadUsersElementsFavoritesData.php
  5. 82 0
      src/Muzich/CoreBundle/DoctrineExtensions/Query/Mysql/Field.php
  6. 10 4
      src/Muzich/CoreBundle/Entity/Playlist.php
  7. 1 1
      src/Muzich/CoreBundle/Entity/UserPlaylistPicked.php
  8. 54 16
      src/Muzich/CoreBundle/Managers/PlaylistManager.php
  9. 17 0
      src/Muzich/CoreBundle/Repository/ElementRepository.php
  10. 205 0
      src/Muzich/CoreBundle/Repository/PlaylistRepository.php
  11. 4 0
      src/Muzich/CoreBundle/Resources/config/routing.yml
  12. 19 6
      src/Muzich/CoreBundle/Resources/public/css/main.css
  13. 6 0
      src/Muzich/CoreBundle/Resources/public/js/autoplay.js
  14. 30 0
      src/Muzich/CoreBundle/Resources/public/js/muzich.js
  15. 10 0
      src/Muzich/CoreBundle/Resources/views/Tag/tag_cloud.html.twig
  16. 5 5
      src/Muzich/CoreBundle/Tests/Utils/CollectionManagerTest.php
  17. 6 5
      src/Muzich/CoreBundle/lib/Collection/CollectionManager.php
  18. 1 0
      src/Muzich/CoreBundle/lib/Collection/ElementCollectionManager.php
  19. 15 0
      src/Muzich/CoreBundle/lib/Controller.php
  20. 26 0
      src/Muzich/CoreBundle/lib/Tag.php
  21. 50 0
      src/Muzich/PlaylistBundle/Controller/ShowController.php
  22. 10 0
      src/Muzich/PlaylistBundle/MuzichPlaylistBundle.php
  23. 11 0
      src/Muzich/PlaylistBundle/Resources/config/routing.yml
  24. 34 0
      src/Muzich/PlaylistBundle/Resources/views/Show/show.html.twig
  25. 25 0
      src/Muzich/PlaylistBundle/Resources/views/Show/user.html.twig

+ 1 - 0
app/AppKernel.php Näytä tiedosto

@@ -44,6 +44,7 @@ class AppKernel extends Kernel
44 44
             new Muzich\FavoriteBundle\MuzichFavoriteBundle(),
45 45
             new Muzich\CommentBundle\MuzichCommentBundle(),
46 46
             new Muzich\AdminBundle\MuzichAdminBundle(),
47
+            new Muzich\PlaylistBundle\MuzichPlaylistBundle(),
47 48
         );
48 49
 
49 50
         if (in_array($this->getEnvironment(), array('dev', 'test'))) {

+ 6 - 0
app/config/routing.yml Näytä tiedosto

@@ -68,6 +68,12 @@ MuzichCommentBundle:
68 68
   requirements:
69 69
     _locale: fr|en
70 70
   
71
+MuzichPlaylistBundle:
72
+  resource: "@MuzichPlaylistBundle/Resources/config/routing.yml"
73
+  prefix:   /{_locale}/
74
+  requirements:
75
+    _locale: fr|en
76
+  
71 77
 AdmingeneratorDashboard_welcome:
72 78
     pattern: /admin/dashboard
73 79
     defaults: { _controller: MuzichAdminBundle:Dashboard:welcome }

+ 28 - 0
src/Muzich/CoreBundle/Controller/ElementController.php Näytä tiedosto

@@ -1072,6 +1072,34 @@ class ElementController extends Controller
1072 1072
     ));
1073 1073
   }
1074 1074
   
1075
+  
1076
+  public function getOneAction($element_id)
1077
+  {
1078
+    $es = new ElementSearcher();
1079
+    $es->init(array(
1080
+      'ids' => array($element_id)
1081
+    ));
1082
+    
1083
+    if (!($element = $es->getElements($this->getDoctrine(), $this->getUserId(true), 'single')))
1084
+    {
1085
+      return $this->jsonResponse(array(
1086
+      'status'  => 'error'
1087
+    ));
1088
+    }
1089
+    
1090
+    $html = $this->render('MuzichCoreBundle:SearchElement:element.html.twig', array(
1091
+      'element'               => $element,
1092
+      'display_edit_actions'  => true,
1093
+      'display_player'        => true,
1094
+      'display_comments'      => true
1095
+    ))->getContent();
1096
+    
1097
+    return $this->jsonResponse(array(
1098
+      'status'  => 'success',
1099
+      'data'    => $html
1100
+    ));
1101
+  }
1102
+  
1075 1103
   public function getOneDomAction(Request $request, $element_id, $type)
1076 1104
   {
1077 1105
     if (!in_array($type, array('autoplay')) || !$element_id)

+ 64 - 1
src/Muzich/CoreBundle/DataFixtures/ORM/LoadUsersElementsFavoritesData.php Näytä tiedosto

@@ -8,6 +8,8 @@ use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
8 8
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
9 9
 use Symfony\Component\DependencyInjection\ContainerInterface;
10 10
 use Muzich\CoreBundle\Entity\UsersElementsFavorites;
11
+use Muzich\CoreBundle\Entity\User;
12
+use Muzich\CoreBundle\Managers\PlaylistManager;
11 13
 
12 14
 class LoadUsersElementsFavoritesData  extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
13 15
 {
@@ -28,7 +30,7 @@ class LoadUsersElementsFavoritesData  extends AbstractFixture implements Ordered
28 30
   /**
29 31
    *  
30 32
    */
31
-  protected function createRecord($user, $element)
33
+  protected function createRecord(User $user, $element)
32 34
   {
33 35
     $favorite = new UsersElementsFavorites();
34 36
     $favorite->setUser($user);
@@ -37,6 +39,18 @@ class LoadUsersElementsFavoritesData  extends AbstractFixture implements Ordered
37 39
     //$this->addReference('user_tag_'.$user->getId().'_'.$tag->getId(), $userTag);
38 40
   }
39 41
   
42
+  protected function createPlaylist($name, User $user, $public, $elements)
43
+  {
44
+    $playlist_manager = new PlaylistManager($this->entity_manager);
45
+    $playlist = $playlist_manager->getNewPlaylist($user);
46
+    $playlist->setPublic($public);
47
+    $playlist->setName($name);
48
+    
49
+    $playlist_manager->addElementsToPlaylist($elements, $playlist);
50
+    $this->entity_manager->persist($playlist);
51
+    return $playlist;
52
+  }
53
+  
40 54
   public function load(ObjectManager $entity_manager)
41 55
   {
42 56
     $this->entity_manager = $entity_manager;
@@ -54,6 +68,55 @@ class LoadUsersElementsFavoritesData  extends AbstractFixture implements Ordered
54 68
     $this->createRecord($paul, $youtube_heretik_1);
55 69
     $this->createRecord($paul, $jamendo_caio_1);
56 70
     
71
+    // Playlists
72
+    $playlist1 = $this->createPlaylist("Un peu de basses ?",
73
+      $bux, true, array(
74
+        $this->getReference('element_soulfly_1'),
75
+        $youtube_heretik_1,
76
+        $youtube_djfab_1,
77
+        $jamendo_caio_1,
78
+        $this->getReference('element_youtube_dtc_passdrop'),
79
+        $this->getReference('element_youtube_antroppod_1'),
80
+        $this->getReference('element_youtube_koinkoin_1'),
81
+        $this->getReference('element_youtube_djantoine_1'),
82
+        $this->getReference('element_youtube_acroyek_1'),
83
+        $this->getReference('element_jamendo_caio_1'),
84
+        $this->getReference('element_jamendo_reverb_1'),
85
+        $this->getReference('element_jamendo_cardio_1'),
86
+        $this->getReference('element_dudeldrum'),
87
+        $this->getReference('element_infected_psycho'),
88
+        $this->getReference('element_infected_muse'),
89
+        $this->getReference('element_joelle_1'),
90
+        $this->getReference('element_joelle_2'),
91
+        $this->getReference('element_ukf_1'),
92
+        $this->getReference('element_beatbox_1'),
93
+        $this->getReference('element_soulfly_1'),
94
+        $this->getReference('element_youtube_koinkoin_1'),
95
+        $this->getReference('element_youtube_koinkoin_1'),
96
+        $this->getReference('element_youtube_koinkoin_1'),
97
+        $this->getReference('element_youtube_koinkoin_1'),
98
+        $this->getReference('element_youtube_koinkoin_1'),
99
+        $this->getReference('element_youtube_koinkoin_1'),
100
+        $this->getReference('element_youtube_koinkoin_1'),
101
+        $this->getReference('element_youtube_koinkoin_1'),
102
+        $this->getReference('element_youtube_koinkoin_1'),
103
+        $this->getReference('element_youtube_koinkoin_1'),
104
+        $this->getReference('element_youtube_koinkoin_1'),
105
+        $this->getReference('element_youtube_koinkoin_1'),
106
+        $this->getReference('element_youtube_koinkoin_1'),
107
+        $this->getReference('element_youtube_koinkoin_1'),
108
+        $this->getReference('element_youtube_koinkoin_1'),
109
+        $this->getReference('element_youtube_koinkoin_1'),
110
+        $this->getReference('element_youtube_koinkoin_1'),
111
+        $this->getReference('element_soulfly_1')
112
+      ));
113
+    
114
+    $playlist2 = $this->createPlaylist("Ma playlist perso",
115
+    $bux, false, array($youtube_heretik_1, $youtube_djfab_1));
116
+    
117
+    $playlist_manager = new PlaylistManager($this->entity_manager);
118
+    $playlist_manager->addPickedPlaylistToUser($paul, $playlist1);
119
+    
57 120
     $this->entity_manager->flush();
58 121
   }
59 122
 }

+ 82 - 0
src/Muzich/CoreBundle/DoctrineExtensions/Query/Mysql/Field.php Näytä tiedosto

@@ -0,0 +1,82 @@
1
+<?php
2
+
3
+/**
4
+ * DoctrineExtensions Mysql Function Pack
5
+ *
6
+ * LICENSE
7
+ *
8
+ * This source file is subject to the new BSD license that is bundled
9
+ * with this package in the file LICENSE.txt.
10
+ * If you did not receive a copy of the license and are unable to
11
+ * obtain it through the world-wide-web, please send an email
12
+ * to kontakt@beberlei.de so I can send you a copy immediately.
13
+ */
14
+
15
+/**
16
+ * Usage: FIELD(str,str1,str2,str3,...)
17
+ * 
18
+ * FIELD returns the index (position) of str in the str1, str2, str3, ... list. 
19
+ * Returns 0 if str is not found. If all arguments to FIELD() are strings, all 
20
+ * arguments are compared as strings. If all arguments are numbers, they are 
21
+ * compared as numbers. Otherwise, the arguments are compared as double.
22
+ * If str is NULL, the return value is 0 because NULL fails equality comparison 
23
+ * with any value. FIELD() is the complement of ELT(). (Taken from MySQL 
24
+ * documentation.)
25
+ * 
26
+ * @author  Jeremy Hicks <jeremy.hicks@gmail.com>
27
+ * @version 2011.06.09
28
+ */
29
+
30
+namespace Muzich\CoreBundle\DoctrineExtensions\Query\Mysql;
31
+
32
+use Doctrine\ORM\Query\AST\Functions\FunctionNode;
33
+use Doctrine\ORM\Query\Lexer;
34
+
35
+class Field extends FunctionNode
36
+{
37
+    private $field = null;
38
+    private $values = array();
39
+    
40
+    public function parse(\Doctrine\ORM\Query\Parser $parser)
41
+    {
42
+        $parser->match(Lexer::T_IDENTIFIER);
43
+        $parser->match(Lexer::T_OPEN_PARENTHESIS);
44
+		
45
+        // Do the field.
46
+        $this->field = $parser->ArithmeticPrimary();
47
+		
48
+        // Add the strings to the values array. FIELD must
49
+        // be used with at least 1 string not including the field.
50
+		
51
+        $lexer = $parser->getLexer();
52
+		
53
+        while (count($this->values) < 1 || 
54
+            $lexer->lookahead['type'] != Lexer::T_CLOSE_PARENTHESIS) {
55
+            $parser->match(Lexer::T_COMMA);
56
+            $this->values[] = $parser->ArithmeticPrimary();
57
+        }
58
+		
59
+        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
60
+    }
61
+	
62
+    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
63
+    {
64
+        $query = 'FIELD(';
65
+		
66
+        $query .= $this->field->dispatch($sqlWalker);
67
+		
68
+        $query .= ',';
69
+		
70
+        for ($i = 0; $i < count($this->values); $i++) {
71
+            if ($i > 0) {
72
+                $query .= ',';
73
+            }
74
+			
75
+            $query .= $this->values[$i]->dispatch($sqlWalker);
76
+        }
77
+		
78
+        $query .= ')';
79
+		
80
+        return $query;
81
+    }
82
+}

+ 10 - 4
src/Muzich/CoreBundle/Entity/Playlist.php Näytä tiedosto

@@ -13,6 +13,7 @@ use Muzich\CoreBundle\lib\Collection\TagCollectionManager;
13 13
 
14 14
 /**
15 15
  * @ORM\Entity
16
+ * @ORM\Entity(repositoryClass="Muzich\CoreBundle\Repository\PlaylistRepository")
16 17
  */
17 18
 class Playlist
18 19
 {
@@ -161,14 +162,19 @@ class Playlist
161 162
   {
162 163
     $tags_manager = new TagCollectionManager(json_decode($this->tags, true));
163 164
     $tags_manager->add($tag);
164
-    $this->tags = json_encode($tags_manager->getContent(), true);
165
+    $this->setTags($tags_manager->getContent());
165 166
   }
166 167
   
167 168
   public function removeTag(Tag $tag)
168 169
   {
169 170
     $tags_manager = new TagCollectionManager(json_decode($this->tags, true));
170 171
     $tags_manager->remove($tag);
171
-    $this->tags = json_encode($tags_manager->getContent(), true);
172
+    $this->setTags($tags_manager->getContent());
173
+  }
174
+  
175
+  public function cleanTags()
176
+  {
177
+    $this->setTags(array());
172 178
   }
173 179
   
174 180
   public function getTagsIds()
@@ -193,14 +199,14 @@ class Playlist
193 199
   {
194 200
     $elements_manager = new ElementCollectionManager(json_decode($this->elements, true));
195 201
     $elements_manager->add($element);
196
-    $this->elements = json_encode($elements_manager->getContent(), true);
202
+    $this->setElements($elements_manager->getContent());
197 203
   }
198 204
   
199 205
   public function removeElement(Element $element)
200 206
   {
201 207
     $elements_manager = new ElementCollectionManager(json_decode($this->elements, true));
202 208
     $elements_manager->remove($element);
203
-    $this->elements = json_encode($elements_manager->getContent(), true);
209
+    $this->setElements($elements_manager->getContent());
204 210
   }
205 211
   
206 212
   public function getElementsIds()

+ 1 - 1
src/Muzich/CoreBundle/Entity/UserPlaylistPicked.php Näytä tiedosto

@@ -25,7 +25,7 @@ class UserPlaylistPicked
25 25
   protected $user;
26 26
   
27 27
   /**
28
-   * @ORM\ManyToOne(targetEntity="Tag", inversedBy="users_favorites")
28
+   * @ORM\ManyToOne(targetEntity="Playlist", inversedBy="users_favorites")
29 29
    * @ORM\JoinColumn(name="tag_id", referencedColumnName="id", onDelete="CASCADE")
30 30
    */
31 31
   protected $playlist;

+ 54 - 16
src/Muzich/CoreBundle/Managers/PlaylistManager.php Näytä tiedosto

@@ -5,8 +5,10 @@ namespace Muzich\CoreBundle\Managers;
5 5
 use Doctrine\ORM\EntityManager;
6 6
 use Muzich\CoreBundle\Entity\Playlist;
7 7
 use Muzich\CoreBundle\Entity\User;
8
+use Muzich\CoreBundle\Entity\Element;
8 9
 use Muzich\CoreBundle\Entity\UserPlaylistPicked;
9 10
 use \Doctrine\Common\Collections\ArrayCollection;
11
+use Muzich\CoreBundle\lib\Tag as TagLib;
10 12
 
11 13
 class PlaylistManager
12 14
 {
@@ -19,24 +21,28 @@ class PlaylistManager
19 21
     $this->entity_manager = $entity_manager;
20 22
   }
21 23
   
22
-  public function findOnePlaylistWithId($playlist_id, User $user = null)
24
+  public function getUserPublicsOrOwnedPlaylists(User $user_viewed, User $user = null)
23 25
   {
24
-    $query_builder = $this->entity_manager->createQueryBuilder()
25
-      ->select('p')
26
-      ->from('MuzichCoreBundle:Playlist', 'p')
27
-      ->where('p.id = :playlist_id')
26
+    return $this->entity_manager->getRepository('MuzichCoreBundle:Playlist')
27
+      ->getUserPublicPlaylistsOrOwnedQueryBuilder($user_viewed, $user)
28
+      ->getQuery()->getResult()
29
+    ;
30
+  }
31
+  
32
+  public function findOneAccessiblePlaylistWithId($playlist_id, User $user = null)
33
+  {
34
+    return $this->entity_manager->getRepository('MuzichCoreBundle:Playlist')
35
+      ->findOnePlaylistOwnedOrPublic($playlist_id, $user)
36
+      ->getQuery()->getOneOrNullResult()
37
+    ;
38
+  }
39
+  
40
+  public function getPlaylistElements(Playlist $playlist)
41
+  {
42
+    return $this->entity_manager->getRepository('MuzichCoreBundle:Element')
43
+      ->getElementsWithIdsOrderingQueryBuilder($playlist->getElementsIds())
44
+      ->getQuery()->getResult()
28 45
     ;
29
-    
30
-    if ($user)
31
-    {
32
-      $query_builder->andWhere('p.public = 1 OR p.owner = :user_id');
33
-    }
34
-    else
35
-    {
36
-      $query_builder->andWhere('p.public = 1');
37
-    }
38
-    
39
-    return $query_builder->getWuery()->getResult();
40 46
   }
41 47
   
42 48
   public function getNewPlaylist(User $owner)
@@ -92,4 +98,36 @@ class PlaylistManager
92 98
     $this->entity_manager->persist($user);
93 99
   }
94 100
   
101
+  public function addElementToPlaylist(Element $element, Playlist $playlist)
102
+  {
103
+    $playlist->addElement($element);
104
+    $this->actualizePlaylistTags($playlist);
105
+  }
106
+  
107
+  public function addElementsToPlaylist($elements, Playlist $playlist)
108
+  {
109
+    foreach ($elements as $element)
110
+    {
111
+      $playlist->addElement($element);
112
+    }
113
+    $this->actualizePlaylistTags($playlist);
114
+  }
115
+  
116
+  public function removeElementFromPlaylist(Element $element, Playlist $playlist)
117
+  {
118
+    $playlist->removeElement($element);
119
+    $this->actualizePlaylistTags($playlist);
120
+  }
121
+  
122
+  protected function actualizePlaylistTags(Playlist $playlist)
123
+  {
124
+    $tag_lib = new TagLib();
125
+    $playlist->cleanTags();
126
+    foreach ($tag_lib->getOrderedEntityTagsWithElements($this->getPlaylistElements($playlist)) as $tag)
127
+    {
128
+      $playlist->addTag($tag);
129
+    }
130
+    $this->entity_manager->persist($playlist);
131
+  }
132
+  
95 133
 }

+ 17 - 0
src/Muzich/CoreBundle/Repository/ElementRepository.php Näytä tiedosto

@@ -510,4 +510,21 @@ class ElementRepository extends EntityRepository
510 510
     ;
511 511
   }
512 512
   
513
+  /**
514
+   * WARNING: Seulement compatibel avec MySQL !!
515
+   */
516
+  public function getElementsWithIdsOrderingQueryBuilder($element_ids)
517
+  {
518
+    $doctrineConfig = $this->getEntityManager()->getConfiguration();
519
+    $doctrineConfig->addCustomStringFunction('FIELD', 'Muzich\CoreBundle\DoctrineExtensions\Query\Mysql\Field');
520
+    
521
+    return $this->getEntityManager()->createQueryBuilder()
522
+      ->select('e, field(e.id, ' . implode(', ', $element_ids) . ') as HIDDEN field')
523
+      ->from('MuzichCoreBundle:Element', 'e')
524
+      ->where('e.id IN (:element_ids)')
525
+      ->setParameter('element_ids', $element_ids)
526
+      ->orderBy('field')
527
+    ;
528
+  }
529
+  
513 530
 }

+ 205 - 0
src/Muzich/CoreBundle/Repository/PlaylistRepository.php Näytä tiedosto

@@ -0,0 +1,205 @@
1
+<?php
2
+
3
+namespace Muzich\CoreBundle\Repository;
4
+
5
+use Doctrine\ORM\EntityRepository;
6
+use Doctrine\ORM\Mapping as ORM;
7
+use Muzich\CoreBundle\Entity\User;
8
+
9
+class PlaylistRepository extends EntityRepository
10
+{
11
+  
12
+  protected function getPlaylistsQueryBuilder()
13
+  {
14
+    return $this->getEntityManager()->createQueryBuilder()
15
+      ->select('p')
16
+      ->from('MuzichCoreBundle:Playlist', 'p')
17
+    ;
18
+  }
19
+  
20
+  public function getPublicPlaylistsQueryBuilder()
21
+  {
22
+    return $this->getPlaylistsQueryBuilder()
23
+      ->andWhere('p.public = 1')
24
+    ;
25
+  }
26
+  
27
+  public function getUserPublicPlaylistsQueryBuilder(User $user)
28
+  {
29
+    return $this->getPublicPlaylistsQueryBuilder()
30
+      ->andWhere('p.owner = :owner_id')
31
+      ->setParameter('owner_id', $user->getId())
32
+    ;
33
+  }
34
+  
35
+  public function getUserPublicPlaylistsOrOwnedQueryBuilder(User $viewed_user, User $current_user = null)
36
+  {
37
+    if (!$current_user)
38
+    {
39
+      return $this->getUserPublicPlaylistsQueryBuilder($viewed_user);
40
+    }
41
+    
42
+    if ($viewed_user->getId() != $current_user->getId())
43
+    {
44
+      return $this->getUserPublicPlaylistsQueryBuilder($viewed_user);
45
+    }
46
+    
47
+    return $this->getPlaylistsQueryBuilder()
48
+      ->where('p.owner = :owner_id')
49
+      ->setParameter('owner_id', $current_user->getId())
50
+    ;
51
+  }
52
+  
53
+  public function findOnePlaylistOwnedOrPublic($playlist_id, User $user = null)
54
+  {
55
+    $query_builder = $this->getPlaylistsQueryBuilder()
56
+      ->andWhere('p.id = :playlist_id');
57
+      
58
+    if ($user)
59
+    {
60
+      $query_builder->andWhere('p.public = 1 OR p.owner = :owner_id');
61
+      $query_builder->setParameters(array(
62
+        'playlist_id' => $playlist_id,
63
+        'owner_id'    => $user->getId()
64
+      ));
65
+    }
66
+    else
67
+    {
68
+      $query_builder->andWhere('p.public = 1');
69
+      $query_builder->setParameters(array(
70
+        'playlist_id' => $playlist_id
71
+      ));
72
+    }
73
+    
74
+    return $query_builder;
75
+  }
76
+  
77
+  /**
78
+   * Retourne un tableau de groupe correspondant a un chaine de caractère
79
+   * La recherche est effectué sur le name.
80
+   * 
81
+   * @param type $string
82
+   * @return Doctrine\ORM\Query
83
+   */
84
+  public function findByString($string)
85
+  {
86
+    return $this->getEntityManager()
87
+      ->createQuery("
88
+        SELECT g FROM MuzichCoreBundle:Group g
89
+        WHERE UPPER(g.name) LIKE :str
90
+        ORDER BY g.name ASC"
91
+      )
92
+      ->setParameters(array(
93
+        'str' => '%'.strtoupper(trim($string)).'%'
94
+      ))
95
+    ;
96
+  }
97
+  
98
+  /**
99
+   * Retourne une Query sleectionnant un Group par son slug
100
+   * 
101
+   * @param type string 
102
+   * @return Doctrine\ORM\Query
103
+   */
104
+  public function findOneBySlug($slug)
105
+  {
106
+    return $this->getEntityManager()
107
+      ->createQuery("
108
+        SELECT g FROM MuzichCoreBundle:Group g
109
+        LEFT JOIN g.tags tr 
110
+        LEFT JOIN tr.tag t
111
+        WHERE g.slug = :str
112
+      ")
113
+      ->setParameters(array(
114
+        'str' => $slug
115
+      ))
116
+    ;
117
+  }
118
+  
119
+  /**
120
+   * Retourne un tableau de groupes étant publics, ou possédé par l'user
121
+   * 
122
+   * @param int $user_id
123
+   * @return array id => name
124
+   */
125
+  public function getPublicAndOwnedArray($user_id)
126
+  {
127
+    $group_array = array();
128
+    foreach ($this->getEntityManager()
129
+      ->createQuery('
130
+        SELECT g.id, g.name FROM MuzichCoreBundle:Group g
131
+        LEFT JOIN g.owner o 
132
+        WHERE g.open = \'1\' OR o.id = :uid'
133
+      )->setParameter('uid', $user_id)
134
+      ->getArrayResult() as $group)
135
+    {
136
+      $group_array[$group['id']] = $group['name'];
137
+    }
138
+    return $group_array;
139
+  }
140
+  
141
+  /**
142
+   * Retourne tous les tags des elements postés
143
+   * 
144
+   * @return doctrine_collection
145
+   */
146
+  public function getElementsTags($group_id, $current_user_id)
147
+  {
148
+    $parameters = array('gid' => $group_id);
149
+    $current_user_sql = '';
150
+    if ($current_user_id)
151
+    {
152
+      $parameters['uidt'] = '%"'.$current_user_id.'"%';
153
+      $current_user_sql = 'OR t.privateids LIKE :uidt';
154
+    }
155
+    
156
+    return $this->getEntityManager()
157
+      ->createQuery('
158
+        SELECT t FROM MuzichCoreBundle:Tag t
159
+        LEFT JOIN t.elements e
160
+        WHERE e.group = :gid
161
+        AND (t.tomoderate = \'FALSE\' OR t.tomoderate IS NULL
162
+          '.$current_user_sql.')
163
+        ORDER BY t.name ASC'
164
+      )
165
+      ->setParameters($parameters)
166
+      ->getResult()
167
+    ;
168
+  }
169
+ 
170
+  public function getElementIdsOwned($group_id)
171
+  {
172
+    $ids = array();
173
+    foreach ($this->getEntityManager()
174
+      ->createQuery('SELECT e.id FROM MuzichCoreBundle:Element e
175
+        WHERE e.group = :gid')
176
+      ->setParameter('gid', $group_id)
177
+      ->getScalarResult() as $row)
178
+    {
179
+      $ids[] = $row['id'];
180
+    }
181
+    return $ids;
182
+  }
183
+  
184
+  public function countFollowers($group_id)
185
+  {
186
+    $data = $this->getEntityManager()
187
+      ->createQuery('SELECT COUNT(f) FROM MuzichCoreBundle:FollowGroup f
188
+        WHERE f.group = :gid')
189
+      ->setParameter('gid', $group_id)
190
+      ->getScalarResult()
191
+    ;
192
+    
193
+    if (count($data))
194
+    {
195
+      if (count($data[0]))
196
+      {
197
+        return $data[0][1];
198
+      }
199
+    }
200
+    
201
+    return 0;
202
+  }
203
+  
204
+}
205
+  

+ 4 - 0
src/Muzich/CoreBundle/Resources/config/routing.yml Näytä tiedosto

@@ -198,6 +198,10 @@ element_dom_get_one:
198 198
   pattern: /ajax/element/dom/get/{type}/{element_id}
199 199
   defaults: { _controller: MuzichCoreBundle:Element:getOneDom, element_id: null }
200 200
 
201
+element_get_one:
202
+  pattern: /ajax/element/get/{element_id}
203
+  defaults: { _controller: MuzichCoreBundle:Element:getOne }
204
+
201 205
 element_get_stream_data:
202 206
   pattern: /ajax/element/data/get/stream/{element_id}
203 207
   defaults: { _controller: MuzichCoreBundle:Element:geJamendotStreamDatas, element_id: null }

+ 19 - 6
src/Muzich/CoreBundle/Resources/public/css/main.css Näytä tiedosto

@@ -455,7 +455,7 @@ ul.element_links_actions li:last-child
455 455
   margin-left: 0px;
456 456
 }
457 457
   
458
-.elements ul.element_tags li, ul#autoplay_element ul.element_tags li
458
+.elements ul.element_tags li, ul#autoplay_element ul.element_tags li, ul.elements ul.element_tags li
459 459
 {
460 460
   display: inline;
461 461
   font-size: 90%;
@@ -493,7 +493,7 @@ ul.element_tags .button
493 493
 
494 494
 }
495 495
 
496
-a.button.element_tag, ul.tagbox li.tag, ul.search_tag_list li, ul#favorite_tags li
496
+a.button.element_tag, ul.tagbox li.tag, ul.search_tag_list li, ul#favorite_tags li, ul.tags_cloud li
497 497
 {
498 498
   padding: 6px;
499 499
   border: none;
@@ -915,7 +915,7 @@ ul.tagbox li.tag
915 915
   padding-right: 18px;
916 916
 }
917 917
 
918
-ul.tagbox li.tag, ul#favorite_tags li
918
+ul.tagbox li.tag, ul#favorite_tags li, ul.tags_cloud li
919 919
 {
920 920
   border-radius: 3px 3px 3px 3px;
921 921
   display: inline-block;
@@ -1382,7 +1382,7 @@ ul#autoplay_element
1382 1382
   padding: 0px;
1383 1383
 }
1384 1384
 
1385
-ul#autoplay_element li
1385
+ul#autoplay_element li, ul.elements li
1386 1386
 {
1387 1387
   list-style-type: none;
1388 1388
 }
@@ -1399,7 +1399,7 @@ ul.tagbox li {
1399 1399
 margin:0;
1400 1400
 }
1401 1401
 
1402
-ul#favorite_tags
1402
+ul#favorite_tags, ul.tags_cloud
1403 1403
 {
1404 1404
   padding:0;
1405 1405
   margin-top:10px;
@@ -1408,7 +1408,7 @@ ul#favorite_tags
1408 1408
   list-style-type:none;
1409 1409
 }
1410 1410
 
1411
-ul#favorite_tags li a
1411
+ul#favorite_tags li a, ul.tags_cloud li a
1412 1412
 {
1413 1413
   color: white;
1414 1414
 }
@@ -2219,4 +2219,17 @@ div#facebook_login
2219 2219
 div#login_box
2220 2220
 {
2221 2221
   margin-top: 23px;
2222
+}
2223
+
2224
+ul.playlists ul.tags_cloud
2225
+{
2226
+  margin-top: 5px;
2227
+  margin-bottom: 5px;
2228
+}
2229
+
2230
+ul.playlists ul.tags_cloud li
2231
+{
2232
+  font-size: 11px;
2233
+  font-weight: normal;
2234
+  padding: 4px;
2222 2235
 }

+ 6 - 0
src/Muzich/CoreBundle/Resources/public/js/autoplay.js Näytä tiedosto

@@ -144,6 +144,12 @@ $(document).ready(function() {
144 144
     return false;
145 145
   });
146 146
   
147
+  $('a.autoplay_playlist').live('click', function(){
148
+    window.autoplay.start($(this));
149
+    $('html, body').animate({ scrollTop: 0 }, 'fast');
150
+    return false;
151
+  });
152
+  
147 153
   $('a#autoplay_previous').click(function(){window.autoplay.playPrevious()});
148 154
   
149 155
   $('a#autoplay_next').click(function(){window.autoplay.playNext()});

+ 30 - 0
src/Muzich/CoreBundle/Resources/public/js/muzich.js Näytä tiedosto

@@ -3087,6 +3087,36 @@ $(document).ready(function(){
3087 3087
    });
3088 3088
    
3089 3089
    
3090
+   /**
3091
+    *PLAYLISTS
3092
+    */
3093
+   
3094
+  $('ul.playlist_elements li a.open_element').live('click', function(){
3095
+    
3096
+    var line = $(this).parents('li.playlist_element');
3097
+    
3098
+    $.getJSON($(this).attr('href'), function(response) {
3099
+      
3100
+      window.ResponseController.execute(
3101
+        response,
3102
+        function(){},
3103
+        function(){}
3104
+      );
3105
+      
3106
+      if (response.status == 'success')
3107
+      {
3108
+        line.append('<ul class="elements"><li class="element">' + response.data + '</li></ul>');
3109
+      }
3110
+      
3111
+    });
3112
+    
3113
+    return false;
3114
+  });
3115
+  
3116
+  $('a.autoplay_playlist').live('click', function(){
3117
+    
3118
+  });
3119
+   
3090 3120
 });
3091 3121
 
3092 3122
 function open_ajax_popin(url, callback)

+ 10 - 0
src/Muzich/CoreBundle/Resources/views/Tag/tag_cloud.html.twig Näytä tiedosto

@@ -0,0 +1,10 @@
1
+<ul class="tags_cloud">
2
+  {% for key, tag in tags %}
3
+    <li class="{{ css_list_length_class(key, tags|length) }}" {% if loop.index0 > cloud_tags_limit_to_display %}style="display: none;"{% endif %}>
4
+      <a data-tagid="{{ tag.id }}" href="#" class="tag">
5
+        {{ tag.name }}
6
+      </a>
7
+    </li>
8
+  {% endfor %}
9
+</ul>
10
+<div class="clearboth" ></div>

+ 5 - 5
src/Muzich/CoreBundle/Tests/Utils/CollectionManagerTest.php Näytä tiedosto

@@ -24,26 +24,26 @@ class CollectionManagerTest extends \PHPUnit_Framework_TestCase
24 24
     
25 25
     $tag_pop = new TagTest(1, 'Pop');
26 26
     $tags_collection_manager->add($tag_pop);
27
-    $this->assertEquals('[{"Id":"1","Name":"Pop"}]', json_encode($tags_collection_manager->getContent(), true));
27
+    $this->assertEquals('[{"id":"1","name":"Pop"}]', json_encode($tags_collection_manager->getContent(), true));
28 28
     
29 29
     $tag_rock = new TagTest(2, 'Rock');
30 30
     $tags_collection_manager->add($tag_rock);
31
-    $this->assertEquals('[{"Id":"1","Name":"Pop"},{"Id":"2","Name":"Rock"}]', json_encode($tags_collection_manager->getContent(), true));
31
+    $this->assertEquals('[{"id":"1","name":"Pop"},{"id":"2","name":"Rock"}]', json_encode($tags_collection_manager->getContent(), true));
32 32
     
33 33
     $this->assertTrue($tags_collection_manager->have($tag_rock));
34 34
     
35 35
     $tags_collection_manager->add($tag_rock);
36
-    $this->assertEquals('[{"Id":"1","Name":"Pop"},{"Id":"2","Name":"Rock"}]', json_encode($tags_collection_manager->getContent(), true));
36
+    $this->assertEquals('[{"id":"1","name":"Pop"},{"id":"2","name":"Rock"}]', json_encode($tags_collection_manager->getContent(), true));
37 37
     
38 38
     $tag_metal = new TagTest(3, 'Metal');
39 39
     $tags_collection_manager->add($tag_metal);
40
-    $this->assertEquals('[{"Id":"1","Name":"Pop"},{"Id":"2","Name":"Rock"},{"Id":"3","Name":"Metal"}]', json_encode($tags_collection_manager->getContent(), true));
40
+    $this->assertEquals('[{"id":"1","name":"Pop"},{"id":"2","name":"Rock"},{"id":"3","name":"Metal"}]', json_encode($tags_collection_manager->getContent(), true));
41 41
     
42 42
     $this->assertEquals(array('1', '2', '3'), $tags_collection_manager->getAttributes(TagCollectionManager::ATTRIBUTE_ID));
43 43
     $this->assertEquals(array('Pop', 'Rock', 'Metal'), $tags_collection_manager->getAttributes(TagCollectionManager::ATTRIBUTE_NAME));
44 44
     
45 45
     $tags_collection_manager->remove($tag_pop);
46
-    $this->assertEquals('[{"Id":"2","Name":"Rock"},{"Id":"3","Name":"Metal"}]', json_encode($tags_collection_manager->getContent(), true));
46
+    $this->assertEquals('[{"id":"2","name":"Rock"},{"id":"3","name":"Metal"}]', json_encode($tags_collection_manager->getContent(), true));
47 47
   }
48 48
   
49 49
 }

+ 6 - 5
src/Muzich/CoreBundle/lib/Collection/CollectionManager.php Näytä tiedosto

@@ -10,6 +10,7 @@ abstract class CollectionManager
10 10
   protected $content;
11 11
   protected $schema = array();
12 12
   protected $object_reference_attribute;
13
+  protected $allow_duplicates = false;
13 14
   
14 15
   public function __construct($content)
15 16
   {
@@ -27,13 +28,13 @@ abstract class CollectionManager
27 28
   
28 29
   public function add($object)
29 30
   {
30
-    if (!$this->have($object))
31
+    if (!$this->have($object) || $this->allow_duplicates)
31 32
     {
32 33
       $content_line = array();
33 34
       foreach ($this->schema as $attribute)
34 35
       {
35 36
         $method_name = 'get' . $attribute;
36
-        $content_line[$attribute] = (string)$object->$method_name();
37
+        $content_line[lcfirst($attribute)] = (string)$object->$method_name();
37 38
       }
38 39
       
39 40
       $this->content[] = $content_line;
@@ -45,7 +46,7 @@ abstract class CollectionManager
45 46
     $method_name = 'get' . $this->object_reference_attribute;
46 47
     foreach ($this->content as $content_line)
47 48
     {
48
-      if ($object->$method_name() == $content_line[$this->object_reference_attribute])
49
+      if ($object->$method_name() == $content_line[lcfirst($this->object_reference_attribute)])
49 50
       {
50 51
         return true;
51 52
       }
@@ -60,7 +61,7 @@ abstract class CollectionManager
60 61
     $method_name = 'get' . $this->object_reference_attribute;
61 62
     foreach ($this->content as $content_line)
62 63
     {
63
-      if ($object->$method_name() != $content_line[$this->object_reference_attribute])
64
+      if ($object->$method_name() != $content_line[lcfirst($this->object_reference_attribute)])
64 65
       {
65 66
         $new_content[] = $content_line;
66 67
       }
@@ -77,7 +78,7 @@ abstract class CollectionManager
77 78
     $attributes = array();
78 79
     foreach ($this->content as $content_line)
79 80
     {
80
-      $attributes[] = $content_line[$attribute];
81
+      $attributes[] = $content_line[lcfirst($attribute)];
81 82
     }
82 83
     
83 84
     return $attributes;

+ 1 - 0
src/Muzich/CoreBundle/lib/Collection/ElementCollectionManager.php Näytä tiedosto

@@ -10,6 +10,7 @@ class ElementCollectionManager extends CollectionManager
10 10
   const ATTRIBUTE_ID   = 'Id';
11 11
   const ATTRIBUTE_NAME = 'Name';
12 12
   
13
+  protected $allow_duplicates = true;
13 14
   protected $schema = array(
14 15
     self::ATTRIBUTE_ID,
15 16
     self::ATTRIBUTE_NAME

+ 15 - 0
src/Muzich/CoreBundle/lib/Controller.php Näytä tiedosto

@@ -13,6 +13,7 @@ use Muzich\CoreBundle\Entity\Element;
13 13
 use Muzich\CoreBundle\Entity\Presubscription;
14 14
 use Muzich\CoreBundle\Entity\User;
15 15
 use Muzich\CoreBundle\Security\Context as SecurityContext;
16
+use Muzich\CoreBundle\Managers\PlaylistManager;
16 17
 
17 18
 class Controller extends BaseController
18 19
 {
@@ -638,4 +639,18 @@ class Controller extends BaseController
638 639
     return $this->security_context;
639 640
   }
640 641
   
642
+  /** @return PlaylistManager */
643
+  protected function getPlaylistManager()
644
+  {
645
+    return new PlaylistManager($this->getEntityManager());
646
+  }
647
+  
648
+  protected function getLastDisplayedElementId($elements)
649
+  {
650
+    if (count($elements))
651
+      return $elements[count($elements)-1]->getId();
652
+    
653
+    return null;
654
+  }
655
+  
641 656
 }

+ 26 - 0
src/Muzich/CoreBundle/lib/Tag.php Näytä tiedosto

@@ -50,6 +50,32 @@ class Tag
50 50
     return $tags_ordered;
51 51
   }
52 52
   
53
+  public function getOrderedEntityTagsWithElements($elements)
54
+  {
55
+    $tag_ordered_reference = $this->getOrderedTagsWithElements($elements);
56
+    return $this->populateOrderedReferenceWithElementTags($elements, $tag_ordered_reference);
57
+  }
58
+  
59
+  public function populateOrderedReferenceWithElementTags($elements, $ordered_reference)
60
+  {
61
+    $tags = array();
62
+    $tags_ordered = array();
63
+    foreach ($elements as $element)
64
+    {
65
+      foreach ($element->getTags() as $tag)
66
+      {
67
+        $tags[$tag->getId()] = $tag;
68
+      }
69
+    }
70
+    
71
+    foreach ($ordered_reference as $tag_id)
72
+    {
73
+      $tags_ordered[] = $tags[$tag_id];
74
+    }
75
+    
76
+    return $tags_ordered;
77
+  }
78
+  
53 79
   /**
54 80
    * Range une liste de tags [0 => Tag] en fonction d'une
55 81
    * réfèrence sous la forme [0 => tag_id, 1 => tag_id]

+ 50 - 0
src/Muzich/PlaylistBundle/Controller/ShowController.php Näytä tiedosto

@@ -0,0 +1,50 @@
1
+<?php
2
+
3
+namespace Muzich\PlaylistBundle\Controller;
4
+
5
+use Muzich\CoreBundle\lib\Controller;
6
+use Muzich\CoreBundle\Entity\Playlist;
7
+use Muzich\CoreBundle\lib\AutoplayManager;
8
+
9
+class ShowController extends Controller
10
+{
11
+  
12
+  public function userAction($user_slug)
13
+  {
14
+    if (!($viewed_user = $this->findUserWithSlug($user_slug)))
15
+    {
16
+      throw $this->createNotFoundException();
17
+    }
18
+    
19
+    return $this->render('MuzichPlaylistBundle:Show:user.html.twig', array(
20
+      'viewed_user' => $viewed_user,
21
+      'playlists'   => $this->getPlaylistManager()->getUserPublicsOrOwnedPlaylists($viewed_user, $this->getUser(true))
22
+    ));
23
+  }
24
+  
25
+  public function showAction($user_slug, $playlist_id)
26
+  {
27
+    if (!($playlist = $this->getPlaylistManager()->findOneAccessiblePlaylistWithId($playlist_id, $this->getUser(true))))
28
+      throw $this->createNotFoundException();
29
+    
30
+    return $this->render('MuzichPlaylistBundle:Show:show.html.twig', array(
31
+      'playlist' => $playlist
32
+    ));
33
+  }
34
+  
35
+  public function getAutoplayDataAction($playlist_id)
36
+  {
37
+    $playlist_manager = $this->getPlaylistManager();
38
+    
39
+    if (!($playlist = $playlist_manager->findOneAccessiblePlaylistWithId($playlist_id, $this->getUser(true))))
40
+      throw $this->createNotFoundException();
41
+    
42
+    $autoplaym = new AutoplayManager($playlist_manager->getPlaylistElements($playlist), $this->container);
43
+    
44
+    return $this->jsonResponse(array(
45
+      'status'    => 'success',
46
+      'data'      => $autoplaym->getList()
47
+    ));
48
+  }
49
+  
50
+}

+ 10 - 0
src/Muzich/PlaylistBundle/MuzichPlaylistBundle.php Näytä tiedosto

@@ -0,0 +1,10 @@
1
+<?php
2
+
3
+namespace Muzich\PlaylistBundle;
4
+
5
+use Symfony\Component\HttpKernel\Bundle\Bundle;
6
+
7
+class MuzichPlaylistBundle extends Bundle
8
+{
9
+  
10
+}

+ 11 - 0
src/Muzich/PlaylistBundle/Resources/config/routing.yml Näytä tiedosto

@@ -0,0 +1,11 @@
1
+playlists_user:
2
+  pattern: /user/{user_slug}/playlists
3
+  defaults: { _controller: MuzichPlaylistBundle:Show:user }
4
+
5
+playlist:
6
+  pattern: /user/{user_slug}/playlist/{playlist_id}
7
+  defaults: { _controller: MuzichPlaylistBundle:Show:show }
8
+
9
+playlist_datas_for_autoplay:
10
+  pattern: /ajax/autoplay/playlist/datas/{playlist_id}
11
+  defaults: { _controller: MuzichPlaylistBundle:Show:getAutoplayData }

+ 34 - 0
src/Muzich/PlaylistBundle/Resources/views/Show/show.html.twig Näytä tiedosto

@@ -0,0 +1,34 @@
1
+{% extends "MuzichFavoriteBundle::layout.html.twig" %}
2
+
3
+{% block title %}{% endblock %}
4
+{% block mainbox_classes %}{% endblock %}
5
+
6
+{% block content %}
7
+  
8
+  <div class="top_tools">
9
+    
10
+    <a class="autoplay_playlist" href="{{ path('playlist_datas_for_autoplay', { 'playlist_id' : playlist.id }) }}" >
11
+      Lire
12
+    </a>
13
+    
14
+    <h2>{{ playlist.name }}</h2>
15
+    
16
+    {% include "MuzichCoreBundle:Tag:tag_cloud.html.twig" with {
17
+      'tags' : playlist.tags
18
+    } %}
19
+    
20
+    {% if playlist.elements|length %}
21
+      <ul class="playlist_elements">
22
+        {% for element in playlist.elements %}
23
+          <li class="playlist_element">
24
+            <a class="open_element" href="{{ path('element_get_one', { 'element_id' : element.id }) }}" data-id="{{ element.id }}">
25
+              {{ element.name }}
26
+            </a>
27
+          </li>
28
+        {% endfor %}
29
+      </ul>
30
+    {% endif %}
31
+  
32
+  </div>
33
+  
34
+{% endblock %}

+ 25 - 0
src/Muzich/PlaylistBundle/Resources/views/Show/user.html.twig Näytä tiedosto

@@ -0,0 +1,25 @@
1
+{% extends "MuzichHomeBundle::layout.html.twig" %}
2
+
3
+{% block title %}{% endblock %}
4
+{% block mainbox_classes %}{% endblock %}
5
+
6
+{% block content %}
7
+  
8
+  {% if playlists|length %}
9
+  <ul class="playlists">
10
+    {% for playlist in playlists %}
11
+      <li>
12
+        <a href="{{ path('playlist', { 'user_slug' : viewed_user.slug, 'playlist_id' : playlist.id }) }}">
13
+          {{ playlist.name }}
14
+        </a>
15
+        
16
+        {% include "MuzichCoreBundle:Tag:tag_cloud.html.twig" with {
17
+          'tags' : playlist.tags
18
+        } %}
19
+        
20
+      </li>
21
+    {% endfor %}
22
+  </ul>
23
+  {% endif %}
24
+  
25
+{% endblock %}