Symfony 3: как изменить порядок коллекции массивов с помощью действия маршрута?

У меня есть сущность Product. Каждый продукт может иметь 0 или N изображений. У меня есть объект ProductPhoto, у которого есть свойство order (0 = первое).

На странице я перечисляю все изображения моего текущего продукта. Я хотел бы управлять порядком изображений с помощью 2 стрелок вверх/вниз.

Когда пользователь нажимает на стрелку, она перемещается вверх/вниз по изображению по сравнению с другими.

введите здесь описание изображения

Итак, на каждой стрелке есть ссылка, соответствующая действию маршрута в моем ProductController.

Не очень сложно обновить только порядок перемещенного изображения, но я не знаю, как обновить порядок других изображений в ArrayCollection...

/**
 * Manage picture order
 *
 * @Route("/products/{id}/photos/{idphoto}/move-{direction}", name="prod_move_photo")
 */
public function movePhotoAction($id, $idphoto, $direction, Request $request) {
    $em     = $this->getDoctrine()->getManager();
    $photo  = $em->getRepository('AppBundle:ProductPhoto')->find($idphoto);

    if ($direction == 'up') {
        $order = $photo->getOrder() - 1;

        if ($order >= 0)
            $photo->setOrder($order);
        else
            $photo->setOrder(0);

    } elseif ($direction == 'down') {
        $order = $photo->getOrder() + 1;
        $photo->setOrder($order);

    } else {
        throw $this->createNotFoundException("The type of ordering '" . $direction . "' doesn't exist.");
    }

    $em->flush();

    // redirection
    return $this->redirectToRoute('prod_photos', array('id' => $id));
}

Может быть, используя PHP uksort()?


person Eve    schedule 02.03.2018    source источник


Ответы (2)


Похоже, вы хотите обновить поля order в двух полях ProductPhoto, перемещаемых друг за другом, верно? Поэтому, пожалуйста, попробуйте это:

/**
 * Manage picture order
 *
 * @Route("/products/{id}/photos/{idphoto}/move-{direction}", name="prod_move_photo")
 */
public function movePhotoAction($id, $idphoto, $direction, Request $request) {
    $em     = $this->getDoctrine()->getManager();
    $photo  = $em->getRepository('AppBundle:ProductPhoto')->find($idphoto);

    $order = $photo->getOrder();

    switch($direction) {

        case 'up':
            $newOrder = ($order >= 1) ? ($order - 1) : (int) 0;
            break;

        case 'down':
            $newOrder = $order + 1;
            break;

        default:                
            throw $this->createNotFoundException("The type of ordering '" . $direction . "' doesn't exist.");
    }

    $anotherPhoto = $em->getRepository('AppBundle:ProductPhoto')->findOneByOrder($newOrder);

    $photo->setOrder($newOrder);
    $anotherPhoto->setOrder($order);

    $em->flush();

    // redirection
    return $this->redirectToRoute('prod_photos', array('id' => $id));
}
person Snegirekk    schedule 02.03.2018
comment
Спасибо, но тем временем я нашел решение, которое поддерживает N изображений, в то время как ваше поддерживает только 2. ;-) Я опубликую его. - person Eve; 05.03.2018
comment
Хм.. Может быть, я не понимаю вашего вопроса, но когда вы нажимаете стрелку вверх/вниз, вам нужно изменить порядок только двух фотографий =) - person Snegirekk; 05.03.2018
comment
Да, вы совершенно правы, я не подумал об этом! Ваше решение работает отлично, спасибо! Это проще, чем у меня. - person Eve; 05.03.2018
comment
Можете ли вы отредактировать свой пост только на 2 строки, вы забыли $ при обновлении порядка $anotherPhoto (++$order и --$order) - person Eve; 05.03.2018
comment
О да, извините.. Отредактировал ) - person Snegirekk; 05.03.2018

Решение @Snegirekk работает очень хорошо (и я его использую), но вот решение, которое я нашел, если оно может помочь...

/**
 * Manage picture order
 *
 * @Route("/products/{id}/photos/{idphoto}/move-{direction}", name="prod_move_photo")
 */
public function movePhotoAction($id, $idphoto, $direction, Request $request) {
    $em     = $this->getDoctrine()->getManager();
    $photo  = $em->getRepository('AppBundle:ProductPhoto')->find($idphoto);

    // Current order of the photo
    $currentPos = $photo->getOrder();

    // Determine new order
    if ($direction == 'up') {
        $newPos = ($currentPos > 0) ? $currentPos - 1 : 0;

    } elseif ($direction == 'down') {
        $newPos = $currentPos + 1;

    } else {
        throw $this->createNotFoundException("The type of ordering '" . $direction . "' doesn't exist.");
    }

    $product = $em->getRepository('AppBundle:Product')->find($id);

    // Get product photos with actual order (moveElement() needs an array)
    $photos = $product->getPhotos()->toArray();

    // Reorder photos in ArrayCollection
    $this->moveElement($photos, $currentPos, $newPos);

    // Reorder photos in database (with keys of formatted ArrayCollection)
    foreach ($photos as $order => $p) {
        $p->setOrder($order);
    }

    $em->flush();

    // redirection
    return $this->redirectToRoute('prod_photos', array('id' => $id));
}

/**
 * Move an array element to a new index
 *
 * @param  array    $array      Array of elements to sort
 * @param  integer  $currentPos Current position of the element to move
 * @param  integer  $newPos     New position of the element to move
 * @return void
 */
public function moveElement(&$array, $currentPos, $newPos) {
    $out = array_splice($array, $currentPos, 1);
    array_splice($array, $newPos, 0, $out);
}
person Eve    schedule 05.03.2018