CakePHP中的非公共可访问功能

时间:2012-12-17 13:40:32

标签: php cakephp

我在我的Cake应用程序中构建了一个简单的Notification系统,我想要一个函数,当我调用某个方法时会创建一个新的通知。因为这不是用户实际上直接访问的东西而且只是数据库逻辑,我把它放在Notification模型中,如下所示:

class Notification extends AppModel
{
    public $name = 'Notification';

    public function createNotification($userId, $content, $url)
    {
        $this->create();

        $this->request->data['Notification']['user_id'] = $userId;
        $this->request->data['Notification']['content'] = $content;
        $this->request->data['Notification']['url'] = $url;

        $result = $this->save($this->request->data);

        if ($result)
        {
            $this->saveField('datetime', date('Y-m-d H:i:s'));
            $this->saveField('status', 0);
        }
    }
}

然后每当我想在我的应用程序中创建通知时,我就会这样做:

$this->Notification->createNotification($userId,'Test','Test');

然而这不起作用!控制器正在与模型进行对话,但它没有在数据库中创建行...我不知道为什么......但是看起来我做错了只是做了所有的代码模型,然后通过应用程序调用它。

编辑:根据下面的答案和评论,我尝试了以下代码在我的通知控制器中创建受保护的方法:

protected function _createNotification($userId, $content, $url)
    {
        $this->Notification->create();

        $this->request->data['Notification']['user_id'] = $userId;
        $this->request->data['Notification']['content'] = $content;
        $this->request->data['Notification']['url'] = $url;

        $result = $this->save($this->request->data);

        if ($result)
        {
            $this->saveField('datetime', date('Y-m-d H:i:s'));
            $this->saveField('status', 0);
        }
    }

现在还有什么东西让我感到困惑(道歉,如果这对其他人来说非常简单,但我在之前没有在CakePHP中使用过受保护的方法)是如何从另一个控制器调用它?因此,例如,如果我的PostsController中有一个方法,并且想要在成功保存时创建通知,我该怎么做?

我在PostsController添加方法中想到了

if($this->save($this->request-data){

    $this->Notification->_createNotification($userId,'Test','Test');

}

但是受到保护我将无法从NotificationsController外部访问该方法。我也使用相同的语法,就像我从一个模型调用一个函数,所以再次感觉不对。

希望有人可以帮助我,让我回到正轨,因为这对我来说是个新领域。

5 个答案:

答案 0 :(得分:3)

控制器应将所有数据传递给模型

$this->createNotification($this->request->data);

然后模型可以使用数据:

public function createNotification(array $data) {
    $key = $data[$this->alias]['key'];
    $data[...] = ...;

    $this->create();
    return $this->save($data);
}

您永远不会尝试从模型中访问控制器(和/或其请求对象)。

你也可以从其他模特调用这个方法,当然:

public function otherModelsMethod() {
    $this->Notification = ClassRegistry::init('Notification');

    $data = array(
         'Notification' => array(...)
    );
    $this->Notification->createNotification($data);
}

并且你可以使你的方法冗长,但这通常会使得越来越多的参数更难阅读/理解/维护:

public function createNotification($userId, $content, $url) {
    $data = array();
    // assign the vars to $data
    $data['user_id'] = $userId;
    ...

    $this->create();
    return $this->save($data);
}

所以这通常不是蛋糕的方式..

答案 1 :(得分:1)

根据定义,模型中的方法不是“可公开访问的”。用户无法调用或调用模型中的方法。用户只能启动控制器操作,而不能启动模型中的任何操作。如果不从任何控制器调用模型方法,则永远不会调用它。所以忘记问题的“非公开”部分。

您的问题是您在模型中工作,就像您在控制器中一样。模型中没有request个对象。您只需将数据数组传递给模型方法并保存该数组。无需$this->request。只需定期array(),将控制器传递的数据放在那里并保存。

答案 2 :(得分:0)

整个方法在MVC上下文IMO中完全错误,并且对使用CakePHP事件系统感到尖叫。因为你想要的实际上是触发某种事件。阅读http://book.cakephp.org/2.0/en/core-libraries/events.html

触发事件并附加一个全局事件侦听器,它将侦听此类事件并在事件发生时执行它应该执行的任何操作(将某些内容保存到db)。它干净,灵活,可扩展。

如果你为你的应用程序做了一个适当的MVC堆栈,那么大多数(如果不是全部)事件也应该从模型中触发,就像成功保存帖子一样。

答案 3 :(得分:0)

这就是我最终要做的事情。虽然它肯定不是很迷人。它适用于我想要它做的事情,并且是一个很好的快速获胜,因为通知仅用于几种方法,因此我不会创建大量需要在将来改进的代码。

首先创建通知我执行以下操作:

$notificationContent = '<strong>'.$user['User']['username'].'</strong> has requested to be friends with you.';
$notificationUrl = Router::url(array('controller'=>'friends','action'=>'requests'));
$this->Notification->createNotification($friendId,$notificationContent,$notificationUrl);

在这里,我传递了我想要的内容和用户可以执行某些操作的URL,在这种情况下,请查看他们已收到通知的朋友请求。如果url是仅提供信息的通知,则该URL可以为null。

createNotification功能位于模型中,如下所示:

public function createNotification($userId, $content, $url = null)
{
    $this->saveField('user_id',$userId);
    $this->saveField('content',$content);
    $this->saveField('url',$url);
    $this->saveField('datetime', date('Y-m-d H:i:s'));
    $this->saveField('status', 0);
}

这会在表中创建一个包含传递内容的新记录,将其状态设置为0(表示未读)及其创建日期。然后,当用户访问通知页面时,通知将设置为已读。

对于这个问题中概述的问题,这很可能不是一个理想的解决方案... 但它有效且易于使用并且可能对正在学习CakePHP的人有用在构建原型应用程序时从模型运行函数。

记住没有什么可以阻止你将来改进的事情!

答案 4 :(得分:0)

首先,您可以通过以下方式改进上一个解决方案,以执行一次save()(而不是5):

public function createNotification($userId, $content, $url = null){

    $data = array(
        'user_id' => $userId,
        'content' => $content,
        'url' => $url,
        'datetime' => date('Y-m-d H:i:s'),
        'status' => 0
    );

    $this->create();
    $this->save($data);
}

一年多以前,当我开始编程CakePHP(1.3)时,我也遇到了这个问题。 (我想在任何其他控制器中使用控制器的功能。) 因为我不知道/研究在哪里放置这样的代码我在一个非常大的项目中做错了一年多。因为这个项目非常大,所以我决定这样做。 这就是我的工作:

我在 app_controller.php 中添加了一个函数(没有视图,强调了):

class AppController extends Controller {
    //........begin of controller..... skipped here

    function _doSomething(){
        //don't forget to load the used model
        $this->loadModel('Notification');
        //do ur magic (save or delete or find ;) )
        $tadaaa = $this->Notification->find('first');
        //return something
        return $tadaaa;
    }
}

这样您就可以通过以下方式从Notification控制器和Posts控制器访问该功能:

$this->_doSomething();

我使用这种函数来做与数据提交或阅读无关的事情,所以我决定将它们保存在app_controller中。在我的项目中,这些功能用于向用户提交电子邮件,例如..或者将用户操作从不同的控制器发布到Facebook。

希望我能让某人对此感到高兴;)但如果您计划制作很多这些功能,那么将它们放在模型中会好得多!