Kaynağa Gözat

Evolution #738: Playlist

Sevajol Bastien 11 yıl önce
ebeveyn
işleme
fcf3400a71

+ 7 - 0
src/Muzich/CoreBundle/Entity/Playlist.php Dosyayı Görüntüle

@@ -209,6 +209,13 @@ class Playlist
209 209
     $this->setElements($elements_manager->getContent());
210 210
   }
211 211
   
212
+  public function removeElementWithId($element_id)
213
+  {
214
+    $elements_manager = new ElementCollectionManager(json_decode($this->elements, true));
215
+    $elements_manager->removeWithReference($element_id);
216
+    $this->setElements($elements_manager->getContent());
217
+  }
218
+  
212 219
   public function getElementsIds()
213 220
   {
214 221
     $elements_manager = new ElementCollectionManager(json_decode($this->elements, true));

+ 39 - 0
src/Muzich/CoreBundle/Form/Playlist/PlaylistForm.php Dosyayı Görüntüle

@@ -0,0 +1,39 @@
1
+<?php
2
+
3
+namespace Muzich\CoreBundle\Form\Playlist;
4
+
5
+use Symfony\Component\Form\AbstractType;
6
+use Symfony\Component\Form\FormBuilderInterface;
7
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
8
+
9
+class PlaylistForm extends AbstractType
10
+{
11
+  public function buildForm(FormBuilderInterface $builder, array $options)
12
+  {
13
+    $builder->add('name', 'text', array(
14
+      'required' => true,
15
+    ));
16
+    $builder->add('public', 'checkbox', array(
17
+      'required' => false,
18
+    ));
19
+  }
20
+
21
+  public function getName()
22
+  {
23
+    return 'playlist';
24
+  }
25
+  
26
+  public function setDefaultOptions(OptionsResolverInterface $resolver)
27
+  {
28
+    $resolver->setDefaults(array(
29
+      'name'   => '',
30
+      'public' => true,
31
+    ));
32
+  
33
+    $resolver->setAllowedValues(array(
34
+      'public' => array(true, false)
35
+    ));
36
+  }
37
+}
38
+
39
+

+ 48 - 3
src/Muzich/CoreBundle/Managers/PlaylistManager.php Dosyayı Görüntüle

@@ -29,6 +29,12 @@ class PlaylistManager
29 29
     ;
30 30
   }
31 31
   
32
+  public function getOwnedsPlaylists(User $user)
33
+  {
34
+    return $this->getUserPublicsOrOwnedPlaylists($user, $user);
35
+  }
36
+  
37
+  /** @return Playlist */
32 38
   public function findOneAccessiblePlaylistWithId($playlist_id, User $user = null)
33 39
   {
34 40
     return $this->entity_manager->getRepository('MuzichCoreBundle:Playlist')
@@ -37,6 +43,15 @@ class PlaylistManager
37 43
     ;
38 44
   }
39 45
   
46
+  /** @return Playlist */
47
+  public function findOwnedPlaylistWithId($playlist_id, User $user)
48
+  {
49
+    return $this->entity_manager->getRepository('MuzichCoreBundle:Playlist')
50
+      ->findOnePlaylistOwned($playlist_id, $user)
51
+      ->getQuery()->getOneOrNullResult()
52
+    ;
53
+  }
54
+  
40 55
   public function getPlaylistElements(Playlist $playlist, $offset = null)
41 56
   {
42 57
     $element_ids = $playlist->getElementsIds();
@@ -53,7 +68,7 @@ class PlaylistManager
53 68
     return  $query_builder->getQuery()->getResult();
54 69
   }
55 70
   
56
-  public function getNewPlaylist(User $owner)
71
+  public function getNewPlaylist(User $owner = null)
57 72
   {
58 73
     $playlist = new Playlist();
59 74
     $playlist->setOwner($owner);
@@ -121,10 +136,11 @@ class PlaylistManager
121 136
     $this->actualizePlaylistTags($playlist);
122 137
   }
123 138
   
124
-  public function removeElementFromPlaylist(Element $element, Playlist $playlist)
139
+  public function removePlaylistElementWithId(Playlist $playlist, $element_id)
125 140
   {
126
-    $playlist->removeElement($element);
141
+    $playlist->removeElementWithId($element_id);
127 142
     $this->actualizePlaylistTags($playlist);
143
+    $this->entity_manager->persist($playlist);
128 144
   }
129 145
   
130 146
   protected function actualizePlaylistTags(Playlist $playlist)
@@ -138,4 +154,33 @@ class PlaylistManager
138 154
     $this->entity_manager->persist($playlist);
139 155
   }
140 156
   
157
+  public function updatePlaylistElementsOrder(Playlist $playlist, $elements_ids_ordereds)
158
+  {
159
+    $elements_origin_order = $playlist->getElements();
160
+    $elements_ordereds = array();
161
+    foreach ($elements_ids_ordereds as $element_id)
162
+    {
163
+      if (($element_record_match = $this->findElementRecordWithId($elements_origin_order, $element_id)))
164
+      {
165
+        $elements_ordereds[] = $element_record_match;
166
+      }
167
+    }
168
+    
169
+    $playlist->setElements($elements_ordereds);
170
+    $this->entity_manager->persist($playlist);
171
+  }
172
+  
173
+  protected function findElementRecordWithId($elements, $searched_id)
174
+  {
175
+    foreach ($elements as $element_record)
176
+    {
177
+      if ($element_record['id'] == $searched_id)
178
+      {
179
+        return $element_record;
180
+      }
181
+    }
182
+    
183
+    return null;
184
+  }
185
+  
141 186
 }

+ 11 - 0
src/Muzich/CoreBundle/Repository/PlaylistRepository.php Dosyayı Görüntüle

@@ -50,6 +50,17 @@ class PlaylistRepository extends EntityRepository
50 50
     ;
51 51
   }
52 52
   
53
+  public function findOnePlaylistOwned($playlist_id, User $user)
54
+  {
55
+    return $this->getPlaylistsQueryBuilder()
56
+      ->andWhere('p.owner = :owner_id AND p.id = :playlist_id')
57
+      ->setParameters(array(
58
+        'owner_id'    => $user->getId(),
59
+        'playlist_id' => $playlist_id
60
+      ))
61
+    ;
62
+  }
63
+  
53 64
   public function findOnePlaylistOwnedOrPublic($playlist_id, User $user = null)
54 65
   {
55 66
     $query_builder = $this->getPlaylistsQueryBuilder()

+ 8 - 0
src/Muzich/CoreBundle/Resources/public/css/main.css Dosyayı Görüntüle

@@ -2232,4 +2232,12 @@ ul.playlists ul.tags_cloud li
2232 2232
   font-size: 11px;
2233 2233
   font-weight: normal;
2234 2234
   padding: 4px;
2235
+}
2236
+
2237
+div.playlists_prompt
2238
+{
2239
+  padding: 10px;
2240
+  border: 1px solid red;
2241
+  width: 320px;
2242
+  background-color: white;
2235 2243
 }

+ 92 - 1
src/Muzich/CoreBundle/Resources/public/js/muzich.js Dosyayı Görüntüle

@@ -3093,6 +3093,9 @@ $(document).ready(function(){
3093 3093
    
3094 3094
   $('ul.playlist_elements li a.open_element').live('click', function(){
3095 3095
     
3096
+    // Pour le moment
3097
+    return false;
3098
+    
3096 3099
     var line = $(this).parents('li.playlist_element');
3097 3100
     
3098 3101
     $.getJSON($(this).attr('href'), function(response) {
@@ -3113,8 +3116,96 @@ $(document).ready(function(){
3113 3116
     return false;
3114 3117
   });
3115 3118
   
3116
-  $('a.autoplay_playlist').live('click', function(){
3119
+  $('ul.playlist_elements').sortable({
3120
+    update: function( event, ui ) {
3121
+      
3122
+      var form = ui.item.parents('form')
3123
+      
3124
+      $.ajax({
3125
+       type: 'POST',
3126
+       url: form.attr('action'),
3127
+       data: form.serialize(),
3128
+       success: function(response) {
3129
+        
3130
+          window.ResponseController.execute(
3131
+            response,
3132
+            function(){},
3133
+            function(){}
3134
+          );
3135
+          
3136
+          
3137
+        },
3138
+       dataType: "json"
3139
+     });
3140
+      
3141
+    }
3142
+  });
3143
+  
3144
+  $('html').click(function() {
3145
+    if ($("div.playlists_prompt").is(':visible'))
3146
+    {
3147
+      $("div.playlists_prompt").hide();
3148
+    }
3149
+  });
3150
+  $("div.playlists_prompt, div.playlists_prompt div, div.playlists_prompt a, div.playlists_prompt input").live('click', function(event){
3151
+    event.stopPropagation();
3152
+    $("div.playlists_prompt").show();
3153
+  });
3154
+  
3155
+  $('ul.elements a.add_to_playlist').live('click', function(event){
3117 3156
     
3157
+    var prompt = $('<div class="playlists_prompt"><img class="loader" src="/bundles/muzichcore/img/ajax-loader.gif" alt="loading..." /></div>');
3158
+    $('body').append(prompt);
3159
+    
3160
+    prompt.position({
3161
+      my: "left+3 bottom+0",
3162
+      of: event,
3163
+      collision: "fit"
3164
+    });
3165
+    
3166
+    $.getJSON($(this).attr('href'), function(response) {
3167
+      window.ResponseController.execute(
3168
+        response,
3169
+        function(){},
3170
+        function(){}
3171
+      );
3172
+      
3173
+      prompt.find('img.loader').hide();
3174
+      if (response.status == 'success')
3175
+      {
3176
+        prompt.append(response.data);
3177
+      }
3178
+      
3179
+    });
3180
+    
3181
+    return false;
3182
+  });
3183
+  
3184
+  $('a.add_element_to_playlist').live('click', function(){
3185
+    $.getJSON($(this).attr('href'), function(response) {
3186
+      window.ResponseController.execute(
3187
+        response,
3188
+        function(){},
3189
+        function(){}
3190
+      );
3191
+    });
3192
+    
3193
+    $(this).parents('div.playlists_prompt').remove();
3194
+    return false;
3195
+  });
3196
+  
3197
+  $('ul.playlist_elements a.remove_element').live('click', function () {
3198
+    
3199
+    $.getJSON($(this).attr('href'), function(response) {
3200
+      window.ResponseController.execute(
3201
+        response,
3202
+        function(){},
3203
+        function(){}
3204
+      );
3205
+    });
3206
+    
3207
+    $(this).parents('li.playlist_element').remove();
3208
+    return false;
3118 3209
   });
3119 3210
    
3120 3211
 });

+ 7 - 0
src/Muzich/CoreBundle/Resources/views/SearchElement/element.html.twig Dosyayı Görüntüle

@@ -266,6 +266,13 @@
266 266
             </a>
267 267
           </li>
268 268
         {% endif %}
269
+        
270
+        <li>
271
+          <a class="add_to_playlist" href="{{ path('playlists_add_element_prompt', { 'element_id' : element.id }) }}">
272
+            +
273
+          </a>
274
+        </li>
275
+        
269 276
       </ul>
270 277
       
271 278
       <span class="element_name">

+ 14 - 0
src/Muzich/CoreBundle/lib/Collection/CollectionManager.php Dosyayı Görüntüle

@@ -70,6 +70,20 @@ abstract class CollectionManager
70 70
     $this->content = $new_content;
71 71
   }
72 72
   
73
+  public function removeWithReference($reference)
74
+  {
75
+    $new_content = array();
76
+    foreach ($this->content as $content_line)
77
+    {
78
+      if ($reference != $content_line[lcfirst($this->object_reference_attribute)])
79
+      {
80
+        $new_content[] = $content_line;
81
+      }
82
+    }
83
+    
84
+    $this->content = $new_content;
85
+  }
86
+  
73 87
   public function getAttributes($attribute)
74 88
   {
75 89
     if (!in_array($attribute, $this->schema))

+ 26 - 0
src/Muzich/CoreBundle/lib/Controller.php Dosyayı Görüntüle

@@ -205,6 +205,16 @@ class Controller extends BaseController
205 205
     }
206 206
   }
207 207
   
208
+  protected function getUserOrNullIfVisitor()
209
+  {
210
+    if (($user = $this->getUser()) === 'anon.')
211
+    {
212
+      return null;
213
+    }
214
+    
215
+    return $user;
216
+  }
217
+  
208 218
   /**
209 219
    *  Retourne l'id de l'utilisateur en cours
210 220
    */
@@ -427,6 +437,16 @@ class Controller extends BaseController
427 437
     return $response;
428 438
   }
429 439
   
440
+  protected function jsonSuccessResponse($data = array())
441
+  {
442
+    $response = new Response(json_encode(array(
443
+      'status' => 'success',
444
+      'data'   => $data
445
+    )));
446
+    $response->headers->set('Content-Type', 'application/json; charset=utf-8');
447
+    return $response;
448
+  }
449
+  
430 450
   /**
431 451
    * Permet d'utiliser la méthode Assert que l'on utilise dans les templates
432 452
    * afin d'avoir une url correcte vers une ressource web (img, js, ...)
@@ -653,4 +673,10 @@ class Controller extends BaseController
653 673
     return null;
654 674
   }
655 675
   
676
+  protected function getElementWithId($element_id)
677
+  {
678
+    return $this->getEntityManager()->getRepository('MuzichCoreBundle:Element')
679
+      ->findOneById($element_id);
680
+  }
681
+  
656 682
 }

+ 47 - 0
src/Muzich/PlaylistBundle/Controller/EditController.php Dosyayı Görüntüle

@@ -0,0 +1,47 @@
1
+<?php
2
+
3
+namespace Muzich\PlaylistBundle\Controller;
4
+
5
+use Muzich\CoreBundle\lib\Controller;
6
+use Muzich\CoreBundle\Entity\Playlist;
7
+use Symfony\Component\HttpFoundation\Request;
8
+
9
+class EditController extends Controller
10
+{
11
+  
12
+  // TODO: Cette méthode ET les autres: Mettre à jour avec le gestionnaire d'accès (Security)
13
+  public function updateOrderAction(Request $request, $playlist_id)
14
+  {
15
+    $playlist_manager = $this->getPlaylistManager();
16
+    if (!($playlist = $playlist_manager->findOwnedPlaylistWithId($playlist_id, $this->getUser())) || !$request->get('elements'))
17
+      return $this->jsonNotFoundResponse();
18
+    
19
+    $playlist_manager->updatePlaylistElementsOrder($playlist, $request->get('elements'));
20
+    $this->flush();
21
+    return $this->jsonSuccessResponse();
22
+  }
23
+  
24
+  public function removeElementAction($playlist_id, $element_id)
25
+  {
26
+    $playlist_manager = $this->getPlaylistManager();
27
+    if (!($playlist = $playlist_manager->findOwnedPlaylistWithId($playlist_id, $this->getUser())))
28
+      return $this->jsonNotFoundResponse();
29
+    
30
+    $playlist_manager->removePlaylistElementWithId($playlist, $element_id);
31
+    $this->flush();
32
+    return $this->jsonSuccessResponse();
33
+  }
34
+  
35
+  public function addElementAction($playlist_id, $element_id)
36
+  {
37
+    $playlist_manager = $this->getPlaylistManager();
38
+    if (!($playlist = $playlist_manager->findOwnedPlaylistWithId($playlist_id, $this->getUser()))
39
+        || !($element = $this->getElementWithId($element_id)))
40
+      return $this->jsonNotFoundResponse();
41
+    
42
+    $playlist_manager->addElementToPlaylist($element, $playlist);
43
+    $this->flush();
44
+    return $this->jsonSuccessResponse();
45
+  }
46
+  
47
+}

+ 17 - 0
src/Muzich/PlaylistBundle/Controller/ShowController.php Dosyayı Görüntüle

@@ -5,6 +5,7 @@ namespace Muzich\PlaylistBundle\Controller;
5 5
 use Muzich\CoreBundle\lib\Controller;
6 6
 use Muzich\CoreBundle\Entity\Playlist;
7 7
 use Muzich\CoreBundle\lib\AutoplayManager;
8
+use Muzich\CoreBundle\Form\Playlist\PlaylistForm;
8 9
 
9 10
 class ShowController extends Controller
10 11
 {
@@ -47,4 +48,20 @@ class ShowController extends Controller
47 48
     ));
48 49
   }
49 50
   
51
+  public function getAddElementPromptAction($element_id)
52
+  {
53
+    return $this->jsonSuccessResponse(
54
+      $this->render('MuzichPlaylistBundle:Show:prompt.html.twig', array(
55
+        'form'       => $this->getPlaylistForm()->createView(),
56
+        'element_id' => $element_id,
57
+        'playlists'  => (!$this->isVisitor())?$this->getPlaylistManager()->getOwnedsPlaylists($this->getUser()):array()
58
+      ))->getContent()
59
+    );
60
+  }
61
+  
62
+  protected function getPlaylistForm()
63
+  {
64
+    return $this->createForm(new PlaylistForm(), $this->getPlaylistManager()->getNewPlaylist($this->getUserOrNullIfVisitor()));
65
+  }
66
+  
50 67
 }

+ 22 - 1
src/Muzich/PlaylistBundle/Resources/config/routing.yml Dosyayı Görüntüle

@@ -8,4 +8,25 @@ playlist:
8 8
 
9 9
 playlist_datas_for_autoplay:
10 10
   pattern: /ajax/autoplay/playlist/datas/{playlist_id}/{offset}
11
-  defaults: { _controller: MuzichPlaylistBundle:Show:getAutoplayData, offset: null }
11
+  defaults: { _controller: MuzichPlaylistBundle:Show:getAutoplayData, offset: null }
12
+
13
+playlist_update_order:
14
+  pattern: /ajax/playlist/order/update/{playlist_id}
15
+  defaults: { _controller: MuzichPlaylistBundle:Edit:updateOrder }
16
+
17
+playlist_remove_element:
18
+  pattern: /ajax/playlist/element/remove/{playlist_id}/{element_id}
19
+  defaults: { _controller: MuzichPlaylistBundle:Edit:removeElement }
20
+
21
+playlists_add_element_prompt:
22
+  pattern: /ajax/playlist/element/add/prompt/{element_id}
23
+  defaults: { _controller: MuzichPlaylistBundle:Show:getAddElementPrompt }
24
+
25
+playlists_add_element:
26
+  pattern: /ajax/playlist/element/add/{playlist_id}/{element_id}
27
+  defaults: { _controller: MuzichPlaylistBundle:Edit:addElement }
28
+
29
+playlist_add_element_and_create:
30
+  pattern: /ajax/playlist/element/add-and-create/{element_id}
31
+  defaults: { _controller: MuzichPlaylistBundle:Edit:addElementAndcreate }
32
+  

+ 33 - 0
src/Muzich/PlaylistBundle/Resources/views/Show/prompt.html.twig Dosyayı Görüntüle

@@ -0,0 +1,33 @@
1
+
2
+<div class="create_playlist">
3
+  <form action="{{ path('playlist_add_element_and_create', { 'element_id' : element_id }) }}" method="post">
4
+    
5
+    <div class="field">
6
+      {{ form_widget(form.name, {'attr':{'class':'niceinput'}}) }}
7
+      {{ form_widget(form.public) }}
8
+    </div>
9
+    
10
+    {{ form_rest(form) }}
11
+    
12
+    <input type="submit" value="CREATE" />
13
+  </form>
14
+</div>
15
+
16
+<div class="playlists_for_element">
17
+  {% if playlists|length %}
18
+    <ul>
19
+      {% for playlist in playlists %}
20
+        <li>
21
+          <a class="add_element_to_playlist" href="{{ path('playlists_add_element', {
22
+            'playlist_id' : playlist.id,
23
+            'element_id'  : element_id
24
+          }) }}">
25
+            {{ playlist.name }}
26
+          </a>
27
+        </li>
28
+      {% endfor %}
29
+    </ul>
30
+  {% else %}
31
+    <p>NO PLAYLIST</p>
32
+  {% endif %}
33
+</div>

+ 18 - 12
src/Muzich/PlaylistBundle/Resources/views/Show/show.html.twig Dosyayı Görüntüle

@@ -18,18 +18,24 @@
18 18
     } %}
19 19
     
20 20
     {% if playlist.elements|length %}
21
-      <ul class="playlist_elements">
22
-        {% for element in playlist.elements %}
23
-          <li class="playlist_element">
24
-            <a class="autoplay_playlist" href="{{ path('playlist_datas_for_autoplay', { 'playlist_id' : playlist.id, 'offset' : loop.index0 }) }}">
25
-              play
26
-            </a>
27
-            <a class="open_element" href="{{ path('element_get_one', { 'element_id' : element.id }) }}" data-id="{{ element.id }}">
28
-              {{ element.name }}
29
-            </a>
30
-          </li>
31
-        {% endfor %}
32
-      </ul>
21
+      <form action="{{ path('playlist_update_order', { 'playlist_id' : playlist.id }) }}" method="post">
22
+        <ul class="playlist_elements">
23
+          {% for element in playlist.elements %}
24
+            <li class="playlist_element">
25
+              <input type="hidden" name="elements[]"  value="{{ element.id }}" />
26
+              <a class="autoplay_playlist" href="{{ path('playlist_datas_for_autoplay', { 'playlist_id' : playlist.id, 'offset' : loop.index0 }) }}">
27
+                play
28
+              </a>
29
+              <a class="open_element" href="{{ path('element_get_one', { 'element_id' : element.id }) }}" data-id="{{ element.id }}">
30
+                {{ element.name }}
31
+              </a>
32
+              <a class="remove_element" href="{{ path('playlist_remove_element', { 'playlist_id' : playlist.id, 'element_id' : element.id }) }}">
33
+                X
34
+              </a>
35
+            </li>
36
+          {% endfor %}
37
+        </ul>
38
+      </form>
33 39
     {% endif %}
34 40
   
35 41
   </div>

+ 5 - 0
src/Muzich/PlaylistBundle/Resources/views/Show/user.html.twig Dosyayı Görüntüle

@@ -9,6 +9,11 @@
9 9
   <ul class="playlists">
10 10
     {% for playlist in playlists %}
11 11
       <li>
12
+        
13
+        <a class="autoplay_playlist" href="{{ path('playlist_datas_for_autoplay', { 'playlist_id' : playlist.id }) }}" >
14
+          Lire
15
+        </a>
16
+        
12 17
         <a href="{{ path('playlist', { 'user_slug' : viewed_user.slug, 'playlist_id' : playlist.id }) }}">
13 18
           {{ playlist.name }}
14 19
         </a>