web-dev-qa-db-ja.com

フォームのコレクションを埋め込むエラー:プロパティのアクセスタイプを特定できませんでした

このチュートリアル に従って、TagフォームのコレクションをServiceフォームに埋め込もうとしています。 TagエンティティとServiceエンティティには多対多の関係があります。

フォームは正しくレンダリングされています。しかし、フォームを送信すると、

プロパティ「tagList」のアクセスタイプを判別できませんでした

エラー。 addTag()メソッドを呼び出しても新しいTagオブジェクトがServiceクラスに追加されない理由がわかりません。

サービスの種類

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('title', TextType::class, array(
            'label' => 'Title'
        ))
    ;

    $builder->add('tagList', CollectionType::class, array(
        'entry_type' => TagType::class,
        'allow_add' => true,
        'allow_delete' => true,
        'by_reference' => false
    )));
}

サービスクラス

{
....
 /**
 * @ORM\ManyToMany(targetEntity="Tag", mappedBy="serviceList",cascade={"persist"})
 */ 
private $tagList;

/**
 * @return ArrayCollection
 */
public function getTagList()
{
    return $this->tagList;
}

/**
 * @param Tag $tag
 * @return Service
 */
public function addTag(Tag $tag)
{
    if ($this->tagList->contains($tag) == false) {
        $this->tagList->add($tag);
        $tag->addService($this);
    }
}

/**
 * @param Tag $tag
 * @return Service
 */
public function removeTag(Tag $tag)
{
    if ($this->tagList->contains($tag)) {
        $this->tagList->removeElement($tag);
        $tag->removeService($this);
    }
    return $this;
}
}

タグクラス

 {
  /**
 * @ORM\ManyToMany(targetEntity="Service", inversedBy="tagList")
 * @ORM\JoinTable(name="tags_services")
 */
private $serviceList;
 /**
 * @param Service $service
 * @return Tag
 */
public function addService(Service $service)
{
    if ($this->serviceList->contains($service) == false) {
        $this->serviceList->add($service);
        $service->addTag($this);
    }
    return $this;
}

/**
 * @param Service $service
 * @return Tag
 */
public function removeService(Service $service)
{
    if ($this->serviceList->contains($service)) {
        $this->serviceList->removeElement($service);
        $service->removeTag($this);
    }
    return $this;
}
 }

ServiceController

  public function newAction(Request $request)
{
    $service = new Service();
    $form = $this->createForm('AppBundle\Form\ServiceType', $service);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {

        $em = $this->getDoctrine()->getManager();
        $em->persist($service);
        $em->flush();

        return $this->redirectToRoute('service_show', array('id' => $service->getId()));
    }

    return $this->render('AppBundle:Service:new.html.twig', array(
        'service' => $service,
        'form' => $form->createView(),
    ));
}
19
blahblah

このURLからコードを実装してみてください。

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#owning-and-inverse-side-on-a-manytomany-association

まず、マップされた/逆の側面を変更して、_Tag::addService_メソッドから$service->addTag($this);を削除してください。

4
michail_w

おそらく問題は、Symfonyがそのプロパティにアクセスできないことですか?

その例外がスローされる場所(PropertyAccessorクラスのwritePropertyメソッド)を見ると、スローされる可能性があることがわかります。

プロパティが存在しないか、公開されていない場合。

チュートリアルで、プロパティ$ tagsとメソッドaddTagがあると述べました。ここで推測しているだけですが、メソッド名add($singularForm)を呼び出そうとする規則があり、プロパティがtagListで、メソッドがaddTag

100%確信はありませんが、そのSymfonyメソッドにストップポイントを設定してデバッグを試み、なぜスローされるのかを確認することができます。

2
mickadoo

ショートバージョン:

私はこの問題に遭遇し、影響を受けるプロパティのセッターを追加することで解決しました。

プロパティのアクセスタイプを判別できませんでした "tagList"

_public function setTagList(Array $tagList)
{
    $this->tagList = $tagList;
}
_

ロングバージョン:

エラーメッセージは、Symfonyがオブジェクトの状態を変更しようとしていることを示していますが、クラスの設定方法が原因で、実際に変更を加える方法を理解できません。

Symfonyの内部を見てください 、Symfonyはアクセスを許可する5つのチャンスを与え、上から下の順序で最良のものを選択することがわかります:

  1. setProperty()という名前のセッターメソッドと1つの引数:

これはSymfonyが最初にチェックすることであり、これを達成するための最も明確な方法です。私の知る限り、これがベストプラクティスです。

_class Entity {

    protected $tagList;

    //...

    public function getTagList()
    {
        return $this->tagList;
    }

    //...
}
_
  1. 1つの引数を持つ1つのメソッドでのゲッターとセッターの組み合わせ:

オブジェクトの状態をgetするために、このメソッドもSymfonyによってアクセスされることを理解することが重要です。これらのメソッド呼び出しには引数が含まれていないため、このメソッドの引数はオプションである必要があります。

_class Entity {

    protected $tagList;

    //...

    public function tagList($tags = null)
    {
        if($reps){
            $this->tagList = $tags;
        } else {
            return $this->tagList;
        }
    }

    //...
}
_
  1. パブリックとして宣言されている影響を受けるプロパティ:

    _class Entity {
    
        public $tagList;
        //... other properties here
    }
    _
  2. ___set_マジックメソッド:

これは、意図したプロパティだけでなく、すべてのプロパティに影響します。

_class Entity {

    public $tagList;

    //...

    public function __set($name, $value){
        $this->$name = $value;
    }
    //...
}
_
  1. ___call_マジックメソッド(場合によっては):

これを確認することはできませんでしたが、内部コードは、PropertyAccessorの構築でmagicが有効になっている場合にこれが可能であることを示しています。


上記の戦略のいずれかを使用するだけで済みます。

2
HPierce

ロングショットですが、アノテーションを見ると、問題はmanyToManyの関係に関連している可能性があると思います。特に両端から更新する必要がない限り、所有側と逆側を変更してみてください(関係を交換してください)(その場合、唯一の解決策はオブジェクトを手動で追加するか、oneToMany関係を使用することだと思います)。

アソシエーションの逆側にのみ加えられた変更は無視されます。双方向アソシエーションの両側(または、Doctrineの観点からは少なくとも所有側)を必ず更新してください。

これは、Doctrine以前に苦しんだことがある、参照: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference /unitofwork-associations.html

1
Strnm

たぶん、このように$ tagListと$ serviceListを初期化するためにServiceクラスとTagクラスの__construct()を忘れましたか?

$this->tagList = new ArrayCollection();

$this->serviceList = new ArrayCollection();

1
ste

これはコンストラクターのエラーのようです。これを試して :

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

Symfonyを使用していて、CollectionTypeの代わりにEntityRepositoryを使用している場合は、フォームビルドで'multiple' => true,を使用してください。そうしないと、入力が1つのエンティティに対して行われ、多くのエンティティに対して行われないため、setTagListメソッドaddTagListおよびremoveTagListを使用する代わりに。

0
ericksho

Symfony 3.3.10に基づく

私は実際に何度もこの問題に直面しましたが、最終的にこの問題がどこから来ているのかを発見すると、エンティティプロパティに付けた名前によっては、adder( removerコレクションプロパティは、期待どおりのものではありません。

例:エンティティのプロパティ名は「foo」で、加算器は「addFoo」、リムーバーは「removeFoo」と呼ばれると予想されますが、突然"プロパティのアクセスタイプを判別できませんでした" =表示されます。

そのため、コード内の問題を検索することを恐れ始めます。代わりに、Symfonyコアファイル内でこのファイルを調べる必要があります。

vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php

このファイルの中にはfindAdderAndRemoverというメソッドがあります。デバッガーを使ってそこに行くと、symfonyが加算器/リムーバーの奇妙な名前を検索していることがわかります。言語によっては実際には"um"または "on"または "us"で終わる場合があります。 (人間の言語)あなたはそれらに名前を付けていました。私はイタリア人なので、これはかなり頻繁に起こります。

修正は、エンティティ内のadd/removeメソッドに使用される名前を変更して、Symfonyコアが探しているものと一致させるのと同じくらい簡単な場合があるため、注意してください。

これは、bin/console doctrine:generate:entitiesを使用してメソッドを自動的に作成すると発生します

0