使用Symfony和Doctrine扩展FilteringSelect / AutoComplete

时间:2016-08-25 04:02:36

标签: php doctrine-orm autocomplete symfony

我在下面的代码中使用了一个自动完成模型名称。我无法扩展它以使自动完成包括品牌名称。

例如,如果有一个品牌的索尼ST1和ST2型号,我希望能够输入索尼并获得两排 - 索尼ST1和索尼ST2,但如果我输入ST1,我想要一排 - 索尼ST1。

控制器代码

treq.content

品牌和型号之间的连接(注释)

/**
 * @View()
 */
public function getModelsAction( Request $request )
{
    $this->denyAccessUnlessGranted( 'ROLE_ADMIN', null, 'Unable to access this page!' );

    $modelName = str_replace( '*', '%', $request->get( 'name' ) );

    $em = $this->getDoctrine()->getManager();

    $queryBuilder = $em->createQueryBuilder()
            ->select( 'm' )
            ->from( 'AppBundle:Model', 'm' );

    $queryBuilder->where(
            $queryBuilder->expr()->like( 'm.name', '?1' )
    );
    $queryBuilder->setParameter( 1, $modelName );

    $query = $queryBuilder->getQuery();
    $modelCollection = $query->getResult();
    $data = [];

    foreach( $modelCollection as $m )
    {
        $item = [
            'id' => $m->getId(),
            'name' => $m->getName(),
        ];

        $data[] = $item;
    }
    return $data;
}

数据库

品牌

/**
 * @var ArrayCollection $brands
 * @ORM\ManyToMany(targetEntity="Model", cascade={"persist"})
 * @ORM\JoinTable(name="brand_model",
 *      joinColumns={@ORM\JoinColumn(name="brand_id", referencedColumnName="id", onDelete="CASCADE")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="model_id", referencedColumnName="id", unique=true, nullable=false)}
 *      )
 */
protected $models = null;

模型

dev=# \d brand
                                  Table "public.brand"
   Column   |              Type              |                 Modifiers                 
------------+--------------------------------+-------------------------------------------
 id         | integer                        | not null
 name       | character varying(64)          | default NULL::character varying
 active     | boolean                        | not null
 deleted_at | timestamp(0) without time zone | default NULL::timestamp without time zone
 comment    | character varying(64)          | default NULL::character varying
Indexes:
    "brand_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "manufacturer_brand" CONSTRAINT "fk_170c6d4844f5d008" FOREIGN KEY (brand_id) REFERENCES brand(id)
    TABLE "brand_model" CONSTRAINT "fk_8c6cbbce44f5d008" FOREIGN KEY (brand_id) REFERENCES brand(id) ON DELETE CASCADE

brand_model

dev=# \d model
                                  Table "public.model"
   Column   |              Type              |                 Modifiers                 
------------+--------------------------------+-------------------------------------------
 id         | integer                        | not null
 name       | character varying(64)          | default NULL::character varying
 comment    | character varying(64)          | default NULL::character varying
 active     | boolean                        | not null
 deleted_at | timestamp(0) without time zone | default NULL::timestamp without time zone
Indexes:
    "model_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "brand_model" CONSTRAINT "fk_8c6cbbce7975b7e7" FOREIGN KEY (model_id) REFERENCES model(id)

1 个答案:

答案 0 :(得分:1)

您可以更改查询构建器:

$queryBuilder = $em->createQueryBuilder()
    ->select('m.id, CONCAT(CONCAT(b.name, ' '), m.name)')
    ->from('AppBundle:Model', 'm')
    ->innerJoin('m.brands', 'b')
    ->where("CONCAT(CONCAT(b.name, ' '), m.name)' LIKE :brand_model")
    ->setParameter('brand_model', $brandModel)
;

确保您已在Model实体上定义了多对多关系的另一面:

class Model
{
    // ...
    /**
     * @ManyToMany(targetEntity="Brand", mappedBy="models")
     */
    private $brands;
}

现在你的控制器更小了,这要归功于->select(...)表达式中定义的参数(不需要foreach,Doctrine会为你做这个):

public function getModelsAction(Request $request)
{
    // ...
    // $queryBuilder = ...

    $data = $queryBuilder->getQuery()->getResult();

    return $data;
}

请注意,我改变了您的PHP编码风格以符合PSR编码标准。