【问题标题】:CakePHP 2.x - Persistent virtual fields issueCakePHP 2.x - 持久虚拟字段问题
【发布时间】:2015-11-29 14:48:45
【问题描述】:

我有一个关于关联模型上的虚拟字段的脑筋急转弯。我知道它有其局限性,您可以在此处阅读:http://book.cakephp.org/2.0/en/models/virtual-fields.html#limitations-of-virtualfields。 但在我的具体情况下,我不能应用将 virtualField 属性从一个模型传递到另一个模型的理论(即使我阅读了这个主题:Using virtual fields in cakePHP 2.x)。

我会尽量解释清楚我的情况。

数据库信息

我有 3 个表格可以在我的网站上进行导航:

菜单

  • 身份证
  • 姓名

页面

  • 身份证
  • 标题
  • 内容

menu_page_links

  • 身份证
  • menu_id
  • page_id
  • 标题
  • ft
  • rgt
  • 插件
  • 控制器
  • 动作

一个页面可以添加到多个菜单,这就是为什么我在菜单和页面之间制作了一个链接表(MenuPageLink)。

申请信息

菜单模型

class Menu extends AppModel
{
    public $hasMany = array(
        'MenuPageLink' => array(
            'className' => 'MenuPageLink',
            'foreignKey' => 'menu_id'
        )
    );
}

页面模型

class Page extends AppModel
{
    public $hasMany = array(
        'MenuPageLink' => array(
            'className' => 'MenuPageLink',
            'foreignKey' => 'page_id'
        )
    );
}

MenuPageLink 模型

class MenuPageLink extends AppModel
{
    public $belongsTo = array(
        'Menu',
        'Page'
    );

    // to calculate the depth of every menu page link

    public $virtualFields = array(
        'depth' => 'COUNT(MenuPageLink.title) - 1'
    );
}

应用控制器

现在在我的应用程序中,我想在每个页面上加载一个特定的菜单,例如“菜单”表中的“主菜单”。 所以在 AppController.php 中,我提到了树需要的模型('Menu''Page''MenuPageLink')如下:

public $uses = array(
    'Menu',
    'Page',
    'MenuPageLink'
);

然后我得到属于我的特定菜单的菜单页面,ID 为“2”:

$menu = $this->MenuPageLink->find('all', array(
    'fields' => array(
        'MenuPageLink.id',
        'MenuPageLink.title',
        'MenuPageLink.plugin',
        'MenuPageLink.controller',
        'MenuPageLink.action',
        'MenuPageLink.depth'
    ),
    'joins' => array(
        array(
            'table' => $this->MenuPageLink->table,
            'alias' => 'Parent',
            'type' => 'LEFT',
            'conditions' => array(
                'MenuPageLink.lft BETWEEN Parent.lft AND Parent.rgt',
                'MenuPageLink.menu_id' => 1
            )
        )
    ),
    'conditions' => array(
        'MenuPageLink.menu_id' => 2,
        'MenuPageLink.lft >' => 1,
        'MenuPageLink.deleted' => null
    ),
    'group' => 'MenuPageLink.id',
    'order' => array(
        'MenuPageLink.lft ASC'
    )
));

这是我调试$menu 变量时的结果:

array(
(int) 0 => array( 'MenuPageLink' => array( 'id' => '36', 'title' => 'Home', 'plugin' => '', 'controller' => 'home', 'action' => 'index', 'depth' => '1' ) ),
(int) 1 => array( 'MenuPageLink' => array( 'id' => '39', 'title' => 'News', 'plugin' => '', 'controller' => 'news_articles', 'action' => 'index', 'depth' => '1' ) ),
(int) 2 => array( 'MenuPageLink' => array( 'id' => '37', 'title' => 'About the park', 'plugin' => '', 'controller' => 'pages', 'action' => 'view', 'depth' => '1' ) ),
(int) 3 => array( 'MenuPageLink' => array( 'id' => '41', 'title' => 'Attractions', 'plugin' => '', 'controller' => 'attractions', 'action' => 'index', 'depth' => '2' ) ),
(int) 4 => array( 'MenuPageLink' => array( 'id' => '42', 'title' => 'Animals', 'plugin' => '', 'controller' => 'animals', 'action' => 'index', 'depth' => '2' ) ),
(int) 5 => array( 'MenuPageLink' => array( 'id' => '43', 'title' => 'Events', 'plugin' => '', 'controller' => 'events', 'action' => 'index', 'depth' => '2' ) ),
(int) 6 => array( 'MenuPageLink' => array( 'id' => '44', 'title' => 'Shows', 'plugin' => '', 'controller' => 'shows', 'action' => 'index', 'depth' => '2' ) ),
(int) 7 => array( 'MenuPageLink' => array( 'id' => '45', 'title' => 'History', 'plugin' => '', 'controller' => 'pages', 'action' => 'history', 'depth' => '2' ) ),
(int) 8 => array( 'MenuPageLink' => array( 'id' => '38', 'title' => 'Info', 'plugin' => '', 'controller' => 'pages', 'action' => 'view2', 'depth' => '1' ) ),
(int) 9 => array( 'MenuPageLink' => array( 'id' => '40', 'title' => 'Media', 'plugin' => '', 'controller' => 'pages', 'action' => 'media', 'depth' => '1' ) )
)

到目前为止一切顺利!

我正在尝试什么

我的问题来了。我只想选择depth = 1的页面。我尝试制作一个新的'conditions'参数:

$menu = $this->MenuPageLink->find('all', array(
    'fields' => array(
        'MenuPageLink.id',
        'MenuPageLink.title',
        'MenuPageLink.plugin',
        'MenuPageLink.controller',
        'MenuPageLink.action',
        'MenuPageLink.depth'
    ),
    'joins' => array(
        array(
            'table' => $this->MenuPageLink->table,
            'alias' => 'Parent',
            'type' => 'LEFT',
            'conditions' => array(
                'MenuPageLink.lft BETWEEN Parent.lft AND Parent.rgt',
                'MenuPageLink.menu_id' => 1
            )
        )
    ),
    'conditions' => array(
        'MenuPageLink.menu_id' => 2,
        'MenuPageLink.lft >' => 1,
        'MenuPageLink.deleted' => null,
        'MenuPageLink.depth' => 1 // <-- new rule in my query
    ),
    'group' => 'MenuPageLink.id',
    'order' => array(
        'MenuPageLink.lft ASC'
    )
));

在费了很多脑筋之后,我什至尝试使用Model::query() 方法:

$this->MenuPageLink->query(
    "SELECT
        `MenuPageLink`.`id`
        , `MenuPageLink`.`title`
        , `MenuPageLink`.`lft`
        , `MenuPageLink`.`rgt`
        , `MenuPageLink`.`show`
        , `MenuPageLink`.`deleted`
        , (COUNT(`MenuPageLink`.`title`) - 1) AS `MenuPageLink`.`depth`
    FROM
        `blwfun`.`menu_page_links` AS `MenuPageLink`
    LEFT JOIN
        `blwfun`.`menus` AS `Menu`
    ON
        (`MenuPageLink`.`menu_id` = `Menu`.`id`)
    LEFT JOIN
        `blwfun`.`pages` AS `Page`
    ON
        (`MenuPageLink`.`page_id` = `Page`.`id`)
    LEFT JOIN
        `blwfun`.`menu_page_links` AS `Parent`
    ON
        (`MenuPageLink`.`lft` BETWEEN `Parent`.`lft` AND `Parent`.`rgt` AND `MenuPageLink`.`menu_id` = 1)
    WHERE
        `Parent`.`menu_id` = 1 AND `MenuPageLink`.`lft` > 1 AND `MenuPageLink`.`deleted` IS NULL AND `MenuPageLink`.`depth` = 1
    GROUP BY
        `MenuPageLink`.`id`
    ORDER BY
        `MenuPageLink`.`lft` ASC"
));

我不断收到sql错误,但我不知道如何解决它。正如我所说,我不知道如何将 de CakePHP 文档 (http://book.cakephp.org/2.0/en/models/virtual-fields.html#limitations-of-virtualfields) 中的理论应用于我的具体案例。 请问有谁可以帮我解决这个问题吗?

你会成为我的英雄:)

【问题讨论】:

  • 1) 每当遇到 SQL 错误时,都需要分享。 2)查看您的代码,问题是您的 WHERE 子句中有一个聚合函数。您需要将 MenuPageLink.depth = 1 移动到 HAVING 子句
  • AgRizzo,谢谢,这是我能想到的最佳答案!

标签: cakephp cakephp-2.x


【解决方案1】:

感谢 AgRizzo,我将我的选择查询更改为这个,它工作正常:

$menuLinks = $this->MenuPageLink->find('all', array(
    'fields' => array(
        'MenuPageLink.id',
        'MenuPageLink.title',
        'MenuPageLink.lft',
        'MenuPageLink.rgt',
        'MenuPageLink.plugin',
        'MenuPageLink.controller',
        'MenuPageLink.action',
        'MenuPageLink.show',
        'MenuPageLink.depth',
        'MenuPageLink.deleted'
    ),
    'joins' => array(
        array(
            'table' => $this->MenuPageLink->table,
            'alias' => 'Parent',
            'type' => 'LEFT',
            'conditions' => array(
                'MenuPageLink.lft BETWEEN Parent.lft AND Parent.rgt',
                'MenuPageLink.menu_id' => 1
            )
        )
    ),
    'conditions' => array(
        'Parent.menu_id' => 1,
        'MenuPageLink.lft >' => 1,
        'MenuPageLink.deleted' => null
    ),
    'group' => 'MenuPageLink.id HAVING (COUNT(MenuPageLink.title) - 1) <= 1',
    'order' => array(
        'MenuPageLink.lft ASC'
    )
));

我希望它可以帮助有同样虚拟领域问题的人;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-23
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多