KnpMenuBundle + Sonata。 データベースからメニューを作成する

親愛なるハブロビテス。 symfonyが大好きです。 私は彼女が好きで、彼女が大好きです。 SonataAdminBundleも好きです。 皆さんも多いと思います。 したがって、この記事では、KNPMenuBundle + SonataAdminBundleがこのプロセスに参加するときに、サイトのメニューを作成するプロセスを検討します。 実際、メニューの作成プロセスは非常に単純で、バンドル自体のgithubで詳細に説明されていますが、メニューを管理パネルから管理できるようにする必要がある場合はどうでしょうか。 に興味がありますか? それから猫をお願いします。



私はすぐに以下に述べることについて謝罪したいのですが、計画を立てる方法の明確な説明が見つかりませんでした。 誰かがあなたのように見た場合は、リンクを共有してください。 たぶん私の記事のいくつかは有用で役に立つでしょう。 それでは始めましょう。 最初は、Sonataがすでにインストールされており、動作していると想定しています。 それでは、まず、メニューのバンドルを生成することから始めましょう。



コンソールを開き、プロジェクトフォルダーに移動して次のように記述します。

#php app / console generate:バンドル



バンドルの名前は自分で自由に選択できます。MenuBundleと呼びます。

2つのエンティティを作成する必要がある場合。 バンドルフォルダーにエンティティフォルダーがない場合は、作成します。 したがって、ファイルの回数はMenu.phpです。 ファイル番号2はMenuType.phpです。 2番目のファイルは何ですか、後で説明します。



ファイルのソースコードに回数を指定します。



namespace MyFolder\MenuBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="menu") * @ORM\Entity(repositoryClass="MyFolder\MenuBundle\Entity\MenuRepository") */ class Menu{ /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(type="string", length=100) */ protected $title; /** * @ORM\Column(type="string", length=100) */ protected $route; /** * @ORM\Column(type="string", nullable=true) */ protected $alias; /** * @ORM\Column(type="boolean") */ protected $static; /** * @ORM\ManyToOne(targetEntity="MyFolder\MenuBundle\Entity\MenuType", inversedBy="menuTypeId") * @ORM\JoinColumn(name="menuTypeId", referencedColumnName="id") */ protected $menuTypeId; }
      
      







ファイル番号2を見てみましょう。

 namespace MyFolder\MenuBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="menu_type") * @ORM\Entity(repositoryClass="MyFolder\MenuBundle\Entity\MenuTypeRepository") */ class MenuType { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(type="string", length=100) */ protected $title; /** * @ORM\OneToMany(targetEntity="Menu", mappedBy="menuTypeId") */ private $typeId; }
      
      







そこで、2つのモデルを作成しました。それらのゲッターとセッターを生成しましょう。

#php app / console doctrine:generate:エンティティMyFolder / MenuBundle / Entity / Menu

そして

#php app / console doctrine:generate:エンティティMyFolder / MenuBundle / Entity / MenuType



すべてがうまくいけば、クラスを変換し、ゲッターとセッターを自由に使えるようにする必要があります。



その後、データベースにテーブル自体を作成する必要があります。

#php app / console doctrine:schema:update --force



したがって、ManyToOneによって互いに接続された2つのテーブルがあります。 つまり、実際には、テーブルTIMEはテーブルTWOと多くの関係を持つことができます。



少し余談。 知らない人のために、モデルでのコミュニケーションについて話しましょう。



TIMEファイルの行の下。

 /** * @ORM\ManyToOne(targetEntity="MyFolder\MenuBundle\Entity\MenuType", inversedBy="menuTypeId") * @ORM\JoinColumn(name="menuTypeId", referencedColumnName="id") */ protected $menuTypeId;
      
      







ファイルMyFolder \ MenuBundle \ Entity \ Menuの多くの行は、ファイルMyFolder \ MenuBundle \ Entity \ MenuTypeの1行のみを参照できることを教えてくれます。これは、TWOファイルからの注釈によって親切に通知されます。

 /** * @ORM\OneToMany(targetEntity="Menu", mappedBy="menuTypeId") */ private $typeId;
      
      







したがって、これはSymfonyのエンティティ間の関係を確立する1つの方法です。



コードに戻ります。 そこで、エンティティを準備し、データベースを作成しました。 admin部分に渡します。



管理パネルが機能するために、次のことを行います。 バンドルを含むフォルダーで、Adminフォルダーとその中に2つのファイルを作成します。 ファイル時間-MenuAdmin、ファイル2-MenuTypeAdmin。 ファイルONCEからのコード:

 namespace MyFolder\MenuBundle\Admin; use Sonata\AdminBundle\Admin\Admin; use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Show\ShowMapper; class MenuAdmin extends Admin{ protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('title', null, array()) ->add('route', null, array()) ->add('alias', null, array()) ->add('static', null, array('required' => false)) ->add('menuTypeId', 'sonata_type_model', array( 'class'=>'MenuBundle:MenuType', 'property'=>'title', 'required' => false ) ) ; } protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('title', null, array()) ->add('id', null, array()) ->add('route', null, array()) ; } public function configureShowField(ShowMapper $showMapper){ $showMapper ->add('title', null, array()) ->add('id', null, array()) ->add('route', null, array()) ; } protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('title', null, array()) ->add('route', null, array()) ->add('id', null, array()) ->add('menuTypeId', 'entity', array( 'class'=>'MenuBundle:MenuType', 'property'=>'title' ) ) ; } }
      
      







私はすぐに謝罪しますが、この記事はソナタに捧げられていないので、この行またはその行の意味をここに書きません。 そのような必要が生じた場合、将来的に私はそれに署名するでしょう。



2つのファイルからのコード:

 namespace MyFolder\MenuBundle\Admin; use Sonata\AdminBundle\Admin\Admin; use Sonata\AdminBundle\Datagrid\ListMapper; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Show\ShowMapper; class MenuTypeAdmin extends Admin{ protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('title', null, array()) ; } protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('title', null, array()) ->add('id', null, array()) ; } public function configureShowField(ShowMapper $showMapper){ $showMapper ->add('title', null, array()) ->add('id', null, array()) ; } protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('title', null, array()) ->add('id', null, array()) ; } }
      
      







次に、ソナタにフォルダと2つのファイルが表示されるように指示する必要があります。 これを行うには、サービスを登録する必要があります。 ファイルMyFolder / MenuBundle / Resources / config / services.ymlを開き、変更を加えます。 矛盾がないように、ファイル全体のコードを提供します。

 parameters: services: admin.menu: class: MyFolder\MenuBundle\Admin\MenuAdmin tags: - { name: sonata.admin, manager_type: orm, group: , label: } arguments: [null, MyFolder\MenuBundle\Entity\Menu, SonataAdminBundle:CRUD] admin.menu_type: class: MyFolder\MenuBundle\Admin\MenuTypeAdmin tags: - { name: sonata.admin, manager_type: orm, group:  , label:  } arguments: [null, MyFolder\MenuBundle\Entity\MenuType, SonataAdminBundle:CRUD]
      
      







したがって、すべてを正しく行った場合、サイトの管理部分に2つのポイントが表示され、次のようになります。

画像



これがうまくいかなかった場合、あなたは私(sin666m4a1fox@gmail.com)に手紙を書くことができます、私は喜んであなたの手紙に答えます。



したがって、すべてを正しく行うと、メニュー項目を追加、変更、削除できるようになります。



なぜあなたはそのような複雑さを求めますか? おそらくこれから始める価値はありますが、それでも、この方法でここでやったからだけではありません。 実際、そのようなメニューを作成するまさにそのプロセスは、新しいアイテムのその後の変更と追加の単純さ、共通ページテンプレートとそのさまざまなコンテンツの結論などを目的としています。



続けましょう。 すべてを正しく行った場合、最初のタイプのメニューを作成することをお勧めします。 これを行うには、「メニュータイプ」タブに移動し、プラス記号の付いたボタンを押します。 ですから、すべてが必要です。 1つのフィールドはタイトルです。 したがって、後でメニュー項目をバインドできるメニュータイプを作成できます。 2種類のメニューを作成しました(「メインメニュー」と「地下のメニュー」)。 メニュー自体に移動して、新しいメニューを追加した後。 ここではもっと面白いです。

画像



実際、タイトルは理解できる理由であり、ルートはKNPMenuBundleに移動するリンクです。 エイリアスは私の個人的な好みです。これはできません。 Staticチェックボックスは、ページがカスタムであり、コントローラーでActionメソッドを必要としないことをシステムに伝えるように設計されています。 実際にメニュータイプIDが表示され、上記で作成したメニュー項目が表示されます。 これはバインディング自体であり、特定の場合に選択するメニュー項目をシステムが理解するのに役立ちます。



一瞬。 カスタムルートを作成する必要があるため、このようなJSコードを適用する必要がありました。

 $(document).ready(function () { $('input[id$="_static"]').click(function(){ var $_thisRoute = $('input[id$="_route"]'), defaultValues = $_thisRoute.val().split('/'); if($(this).is(':checked')) { $_thisRoute.val('/custom/'+defaultValues[defaultValues.length -1]); } else { $_thisRoute.val('/'+defaultValues[defaultValues.length -1]); } }) });
      
      







つまり、静的アイテムをクリックすると、ルートが変わります。たとえば、about-usと書いた場合は、/ custom / about-usになります。



ソナタの管理部分にjsを追加する方法については説明しません。これは、この領域の範囲外です。必要に応じて、お尋ねします。



7つのメニュー項目を作成しました



画像



ご覧のとおり、ルートは最後のポイントを除いて、すべての人にとってほぼ同じです。 これらはすべてメインメニューにのみ関連付けられています。 実際にこの部分で完了です。 KNPMenuBundleに移動します。



2.2を既に持っているという事実にもかかわらず、バンドル1.1のバージョンをインストールしましたが、2.2ソナタと友達を作ることに成功しませんでした。また、ソナタでは要件にKNPMenuBundle 1.1があるため、何も違反しません。



続けます。 バンドルのあるフォルダーで、その中にBuilder.phpファイルのMenuフォルダーを作成します。 彼のコードは次のとおりです。

 namespace MyFolder\MenuBundle\Menu; use Knp\Menu\FactoryInterface; use Knp\Menu\ItemInterface; use Symfony\Component\DependencyInjection\ContainerAware; class Builder extends ContainerAware { public function mainMenu(FactoryInterface $factory, array $options) { $menuItems = $this->container->get('menu')->getMainMenu(); $menu = $factory->createItem('root'); $this->setCurrentItem($menu); $menu->setChildrenAttribute('class', 'nav'); $menu->setExtra('currentElement', 'active'); foreach($menuItems as $item) { $menu->addChild($item->getTitle(), array('uri' => $item->getRoute())); } return $menu; } protected function setCurrentItem(ItemInterface $menu) { $menu->setCurrentUri($this->container->get('request')->getPathInfo()); } }
      
      







ここにいくつかのポイントがあります。 Builder自体がContainerAwareを継承しているため、$ this-> container-> get()を使用する機能が明らかにあり、必要であれば、必要なメニュー項目を選択するサービスをすばやく作成できます。 すぐに言ってやった。



バンドルフォルダーにServiceフォルダーを作成し、その中に1つのMenuService.phpファイルを作成します。 コードの記述を開始する前に、サービスを利用可能にします。つまり、ファイルMyFolder / MenuBundle / Resources / config / services.ymlを編集して、次のようにします。

 parameters: services: menu: class: MyFolder\MenuBundle\Service\MenuService arguments: [@service_container] admin.menu: class: MyFolder\MenuBundle\Admin\MenuAdmin tags: - { name: sonata.admin, manager_type: orm, group: , label: } arguments: [null, MyFolder\MenuBundle\Entity\Menu, SonataAdminBundle:CRUD] admin.menu_type: class: MyFolder\MenuBundle\Admin\MenuTypeAdmin tags: - { name: sonata.admin, manager_type: orm, group:  , label:  } arguments: [null, MyFolder\MenuBundle\Entity\MenuType, SonataAdminBundle:CRUD]
      
      







実際には、ファイルコードはMyFolder / MenuBundle / Service / MenuServiceです

 namespace MyFolder\MenuBundle\Service; use Symfony\Component\DependencyInjection\Container; class MenuService { private $doctrine; private $container; private $menuRepository; public function __construct(Container $container) { $this->container = $container; $this->doctrine = $this->container->get('doctrine'); $this->menuRepository = $this->doctrine->getRepository('MenuBundle:Menu'); } public function getMainMenu() { return $this->menuRepository->getMainMenu(); } }
      
      







Menu.phpエンティティの1行を思い出させてください

ORM \ Entity(repositoryClass =“ MyFolder \ MenuBundle \ Entity \ MenuRepository”)

これは、エンティティを含むフォルダーでMenuRepository.phpファイルを作成し、その中のコードが次のようになることを意味します。

 namespace MyFolder\MenuBundle\Entity; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query\ResultSetMapping; class MenuRepository extends EntityRepository { public function getMainMenu() { return $this->findBy(array('menuTypeId' => 1)); } }
      
      







実際、これはまさに「メインメニュー」タイプにのみ適用されるすべてのメニュー項目を返す選択です。



仕上げ:メニューを表示するには、Twigテンプレートエンジンで次の行を記述します。

 {{ knp_menu_render('MenuBundle:Builder:mainMenu', { 'currentClass': 'active'}) }}
      
      







アクティブなCSSクラスは、現在アクティブな値になります。 私のようなメニューを作成した場合は、コントローラーのいずれかでこの方法を実行できます

 /** * @Template() * @Route("/custom/{link}", name="_custom_page", defaults={"link" = "/"}) */ public function customAction($link) { return $this->render('CommonBundle:Default:commonPage.html.twig', array('page' => $link)); }
      
      







このコードは、単なる例としての万能薬ではありません。 ただし、最後のメニュー項目については、独自のメソッドを作成する必要があります。



記事がすべてを複雑にしているだけで、より簡単に、またはより速く書く方法があると思われる場合は、まずフレームワークを勉強して、すべてを複雑にするのが好きなので、私と共有してください。



PS何かが正しく説明されていないか、説明されていないものがあれば、メールに書いてください。 ご清聴ありがとうございました。 じゃあね



All Articles