symfony2admingenerator / AvocodeFormExtensionsBundle

(old-legacy) Symfony2 form extensions for Admingenerator project (also working standalone!)
Other
48 stars 31 forks source link

DoubleList problem #16

Closed denys281 closed 11 years ago

denys281 commented 11 years ago

I don't now if this bug, there are no any documentation for double_list so I use it like in old admingenerator.

In db I have many to many so my entity:

  /**
   * @ORM\ManyToMany(targetEntity="\Webmil\Frontend\PartnerBundle\Entity\Price",  inversedBy="product")
   * @ORM\JoinTable(name="product_price",
   *      joinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id", onDelete="Cascade")},
   *      inverseJoinColumns={@ORM\JoinColumn(name="price_id", referencedColumnName="id", onDelete="Cascade")}
   *      )
   */
  private $price;

second entity

  /**
   * @ORM\ManyToMany(targetEntity="\Webmil\Frontend\ProductBundle\Entity\Product", mappedBy="price")
   */
  private $product;

when I set relations through phpmyadmin, it is all ok.

In admingenerator (for product)

price:
        label:   Price lists
        formType: double_list_entity
        addFormOptions:
         property: title

And I have cool double list. But it don't show selected item, that I set in phpmyadmin.

When I try set from admin, I get error.

Neither the property "price" nor one of the methods "setPrice()", "__set()" or "__call()" exist and have public access in class "Webmil\Frontend\ProductBundle\Entity\Product". 

So I add method in product entity (in old forms it works without this method):

  public function setPrice($price)
  {
    $this->price = $price;
    return $this;
  }

But I have other error

Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in /home/dan/WEB/www/nerey-dev.my/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 528 and defined in /home/dan/WEB/www/nerey-dev.my/vendor/doctrine/common/lib/Doctrine/Common/Collections/ArrayCollection.php line 48 

And I can't understand what's wrong...Maybe problem in my entity, but I can't catch.

ioleo commented 11 years ago

@denys281 sorry for 3 days of silence.. i've had some problems in private life, please paste your entity

denys281 commented 11 years ago

@loostro this is not critical.

My first entity:


namespace Webmil\Frontend\PartnerBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

/**
 * Price
 *
 * @ORM\Table(name="price_list")
 * @ORM\Entity(repositoryClass="Webmil\Frontend\PartnerBundle\Entity\PriceRepository")
 * @Vich\Uploadable
 */
class Price
{

  use ORMBehaviors\Translatable\Translatable,
      ORMBehaviors\Timestampable\Timestampable,
      ORMBehaviors\Sluggable\Sluggable
  ;

  /**
   * @var integer
   *
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  private $id;

  /**
   * @var string
   *
   * @ORM\Column(name="title", type="string", length=255)
   */
  private $title;

  /**
   * @Assert\File(
   *     maxSize="10M",
   *     mimeTypes={"application/x-rar-compressed", "application/octet-stream", "application/zip", "application/octet-stream"}
   * )
   * @Vich\UploadableField(mapping="catalog", fileNameProperty="price")
   *
   * @var File $file
   */
  public $file;

  /**
   * @var string
   *
   * @ORM\Column(name="price", type="string", length=255, nullable=true)
   */
  private $price;

  /**
   * @ORM\ManyToOne(targetEntity="Webmil\Frontend\PartnerBundle\Entity\Partner", inversedBy="price")
   * @ORM\JoinColumn(name="partner_id", referencedColumnName="id", nullable=true)
   * */
  private $partner;

  /**
   * @ORM\ManyToMany(targetEntity="\Webmil\Frontend\ProductBundle\Entity\Product", mappedBy="price")
   */
  private $product;

  public function __construct()
  {
    $this->product = new \Doctrine\Common\Collections\ArrayCollection();
  }

  /**
   * Get id
   *
   * @return integer 
   */
  public function getId()
  {
    return $this->id;
  }

  /**
   * Set title
   *
   * @param string $title
   * @return Price
   */
  public function setTitle($title)
  {
    $this->title = $title;

    return $this;
  }

  /**
   * Get title
   *
   * @return string 
   */
  public function getTitle()
  {
    return $this->title;
  }

  /**
   * Set price
   *
   * @param string $price
   * @return Price
   */
  public function setPrice($price)
  {
    $this->price = $price;

    return $this;
  }

  /**
   * Get price
   *
   * @return string 
   */
  public function getPrice()
  {
    return $this->price;
  }

  public function getPartner()
  {
    return $this->partner;
  }

  /**
   * Set category
   *
   * @param \Webmil\Frontend\PartnerBundle\Entity\Partner $category
   * @return Model
   */
  public function setPartner(\Webmil\Frontend\PartnerBundle\Entity\Partner $partner)
  {
    $this->partner = $partner;
    return $this;
  }

  public function getSluggableFields()
  {
    return [ 'title'];
  }

}

Second entity, where I have double list.

namespace Webmil\Frontend\ProductBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;

/**
 * Product
 *
 * @ORM\Table(name="product")
 * @ORM\Entity(repositoryClass="Webmil\Frontend\ProductBundle\Entity\ProductRepository")
 */
class Product
{

  use ORMBehaviors\Translatable\Translatable,
      ORMBehaviors\Timestampable\Timestampable,
      ORMBehaviors\Sluggable\Sluggable
  ;

  /**
   * @var integer
   *
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  private $id;

  /**
   * @var string
   *
   * @ORM\Column(name="title", type="string", length=255)
   */
  private $title;

  /**
   * @var string
   *
   * @ORM\Column(name="description", type="text", nullable=true)
   */
  private $description;

  /**
   * @ORM\ManyToOne(targetEntity="Webmil\Frontend\CategoryBundle\Entity\Category", inversedBy="product")
   * @ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=true)
   * */
  private $category;

  /**
   * @ORM\ManyToMany(targetEntity="\Webmil\Frontend\PartnerBundle\Entity\Price",  inversedBy="product")
   * @ORM\JoinTable(name="product_price",
   *      joinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id", onDelete="Cascade")},
   *      inverseJoinColumns={@ORM\JoinColumn(name="price_id", referencedColumnName="id", onDelete="Cascade")}
   *      )
   */
  private $price;

  public function __construct()
  {
    $this->category = new \Doctrine\Common\Collections\ArrayCollection();
    $this->price = new \Doctrine\Common\Collections\ArrayCollection();
  }

  /**
   * Get id
   *
   * @return integer 
   */
  public function getId()
  {
    return $this->id;
  }

  /**
   * Set title
   *
   * @param string $title
   * @return Product
   */
  public function setTitle($title)
  {
    $this->title = $title;

    return $this;
  }

  /**
   * Get title
   *
   * @return string 
   */
  public function getTitle()
  {
    return $this->title;
  }

  /**
   * Set description
   *
   * @param string $description
   * @return Product
   */
  public function setDescription($description)
  {
    $this->description = $description;

    return $this;
  }

  /**
   * Get description
   *
   * @return string 
   */
  public function getDescription()
  {
    return $this->description;
  }

  public function getCategory()
  {
    return $this->category;
  }

  /**
   * Set category
   *
   * @param \Webmil\Frontend\CategoryBundle\Entity\Category $category
   * @return Model
   */
  public function setCategory($category)
  {
    $this->category = $category;
    return $this;
  }

  public function getSluggableFields()
  {
    return [ 'title'];
  }

  public function getPrice()
  {
    return $this->price;
  }

  public function setPrice($price)
  {
    $this->price = $price;

    return $this;
  }

}
ioleo commented 11 years ago

@denys281 to me it looks like you've got the wrong methods

For a Collection field you should have:

protected $prices

But you have:

protected $price

instead, which is probably the cause of your problem.

denys281 commented 11 years ago

@loostro thank you, I update entity:


namespace Webmil\Frontend\ProductBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;

/**
 * Product
 *
 * @ORM\Table(name="product")
 * @ORM\Entity(repositoryClass="Webmil\Frontend\ProductBundle\Entity\ProductRepository")
 */
class Product
{

  use ORMBehaviors\Translatable\Translatable,
      ORMBehaviors\Timestampable\Timestampable,
      ORMBehaviors\Sluggable\Sluggable
  ;

  /**
   * @var integer
   *
   * @ORM\Column(name="id", type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  private $id;

  /**
   * @var string
   *
   * @ORM\Column(name="title", type="string", length=255)
   */
  private $title;

  /**
   * @var string
   *
   * @ORM\Column(name="description", type="text", nullable=true)
   */
  private $description;

  /**
   * @ORM\ManyToOne(targetEntity="Webmil\Frontend\CategoryBundle\Entity\Category", inversedBy="product")
   * @ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=true)
   * */
  private $category;

  /**
   * @ORM\ManyToMany(targetEntity="\Webmil\Frontend\PartnerBundle\Entity\Price",  inversedBy="product")
   * @ORM\JoinTable(name="product_price",
   *      joinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id", onDelete="Cascade")},
   *      inverseJoinColumns={@ORM\JoinColumn(name="price_id", referencedColumnName="id", onDelete="Cascade")}
   *      )
   */
  private $prices;

  public function __construct()
  {
    $this->category = new \Doctrine\Common\Collections\ArrayCollection();
    $this->price = new \Doctrine\Common\Collections\ArrayCollection();
  }

  /**
   * Get id
   *
   * @return integer 
   */
  public function getId()
  {
    return $this->id;
  }

  /**
   * Set title
   *
   * @param string $title
   * @return Product
   */
  public function setTitle($title)
  {
    $this->title = $title;

    return $this;
  }

  /**
   * Get title
   *
   * @return string 
   */
  public function getTitle()
  {
    return $this->title;
  }

  /**
   * Set description
   *
   * @param string $description
   * @return Product
   */
  public function setDescription($description)
  {
    $this->description = $description;

    return $this;
  }

  /**
   * Get description
   *
   * @return string 
   */
  public function getDescription()
  {
    return $this->description;
  }

  public function getCategory()
  {
    return $this->category;
  }

  /**
   * Set category
   *
   * @param \Webmil\Frontend\CategoryBundle\Entity\Category $category
   * @return Model
   */
  public function setCategory($category)
  {
    $this->category = $category;
    return $this;
  }

  public function getSluggableFields()
  {
    return [ 'title'];
  }

  /**
   * Add price
   *
   * @param \Webmil\Frontend\PartnerBundle\Entity\Price $price
   * @return Product
   */
  public function addPrice(\Webmil\Frontend\PartnerBundle\Entity\Price $price)
  {
    $this->price[] = $price;

    return $this;
  }

  /**
   * Remove price
   *
   * @param \Webmil\Frontend\PartnerBundle\Entity\Price $price
   */
  public function removePrice(\Webmil\Frontend\PartnerBundle\Entity\Price $price)
  {
    $this->price->removeElement($price);
  }

  public function getPrices()
  {
    return $this->prices;
  }

}

But it is does not work. Method getPrices works, I made foreach($this->prices) and it showed me selected item, but widget does not show me selected items.

ioleo commented 11 years ago

@denys281 does the widget load at all? can you show a screenshot? or copy (relevant part) of HTML output?

denys281 commented 11 years ago

@loostro My screenshot

  <div class="control-group form_field field_double_list_entity field_prices">
      <div class="control-group prices">
        <label class="control-label" for="edit_product_prices">Прайси</label>
        <div class="controls">
          <div id="edit_product_prices_widget_container" class="double-list">
            <div class="list-unselected dropdown open">
              <div class="double-list-label">Не вибраний</div>
              <ul id="edit_product_prices_unselected" class="double-list-dropdown dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
                <li data-value="1"><a tabindex="-1" href="#"><i class="icon-ok"></i> test price</a></li>
              </ul>
            </div>
            <div class="list-controls">
              <div class="double-list-label">&nbsp;</div>
              <div class="double-list-controls">
                <div class="btn-group btn-group-vertical">
                  <button type="button" class="btn btn-large unselect">
                    <i class="icon-chevron-left icon-large"></i>
                  </button>
                  <button type="button" class="btn btn-large select">
                    <i class="icon-chevron-right icon-large"></i>
                  </button>
                </div>
              </div>
            </div>
            <div class="list-selected dropdown open">
              <div class="double-list-label">Вибрані</div>
              <ul id="edit_product_prices_selected" class="double-list-dropdown dropdown-menu" role="menu" aria-labelledby="dropdownMenu"></ul>
            </div>
            <select id="edit_product_prices" name="edit_product[prices]"    class="hidden-select">
              <option  value=""></option><option value="1">test price</option>
            </select>
          </div>
        </div>
      </div>
    </div>
ioleo commented 11 years ago

@denys281 from what I see, everything is OK:

ioleo commented 11 years ago

@denys281 the form type works like that:

And only this select tag is submitted.

But for nice GUI we have:

denys281 commented 11 years ago

@loostro hm, when in firebug I removed class hidden-select , I see simple select list, but not multiple.

ioleo commented 11 years ago

@denys281 It should be multiple defined here

denys281 commented 11 years ago

@loostro yessss. I just add to my config multiple: true and all works perfect.

 prices:
        label:   Прайси
        formType: double_list_entity
        addFormOptions:
         property: title
         multiple: true
ioleo commented 11 years ago

It should be added automatically. I need to investigate why it wasn't.

ioleo commented 11 years ago

@denys281 It seems that this PR should fix this error.