Выбор самой новой записи отношения hasMany - PullRequest
3 голосов
/ 02 октября 2011

В моем приложении CakePHP есть две базовые модели: пользователь и логин. Пользователь имеет отношение hasMany к логинам (то есть новая запись для входа в систему создается каждый раз, когда пользователь входит в систему).

Теперь я хочу сделать 2 отношения от модели User до модели Login: Пользователь имеетМного Вход а также Пользователь hasOne lastLogin

Это последнее отношение должно включать только последнюю запись модели входа в систему для выбранного пользователя.

Я попробовал это следующим образом:

var $belongsTo = array
(
    'LastLogin' => array
    (
        'className' => 'Login',
        'order' => 'LastLogin.created DESC',
        'limit' =>  1

    )
); 

Однако это не работает. Любые идеи о том, как заставить это работать?

Ответы [ 2 ]

1 голос
/ 02 октября 2011

ОБНОВЛЕНИЕ ОТВЕТА НА ОТЗЫВЫ

При отношении belongsTo внешний ключ должен быть в модели current .

Это означает, что если вы хотите иметь отношение, в котором User принадлежит To LastLogin, таблица users должна иметь поле last_login_id.

В вашем случае вы, вероятно, захотите использовать вместо этого отношение hasOne, и вам придется использовать функцию MAX() SQL в ключе fields. Обратите внимание, что получение last_login работает полностью независимо от ваших отношений между пользователем и многими пользователями. Поэтому, если вам нужен только последний вход в систему, вы можете удалить отношение hasMany и просто оставить hasOne.

С примером кода ниже вы получите это:

Вывод / users / index:

Array
(
    [User] => Array
        (
            [id] => 1
            [name] => user1
            [last_login] => 2011-05-01 14:00:00
        )
    [Login] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [user_id] => 1
                    [created] => 2011-05-01 12:00:00
                )
            [1] => Array
                (
                    [id] => 2
                    [user_id] => 1
                    [created] => 2011-05-01 13:00:00
                )
            [2] => Array
                (
                    [id] => 3
                    [user_id] => 1
                    [created] => 2011-05-01 14:00:00
                )
        )
)

Если вы не используете обратный вызов Model :: afterFind (), ваши результаты будут выглядеть примерно так (Массив логина, обрезанный для экономии места):

Array
(
    [User] => Array
        (
            [id] => 1
            [name] => user1
        )

    [0] => Array
        (
            [last_login] => 2011-05-01 14:00:00
        )
)

<ч /> Пример кода:

таблица пользователей:

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
)

таблица логинов:

CREATE TABLE `logins` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)

Модель пользователя:

class User extends AppModel {
    var $name = 'User';
    var $hasMany = array('Login');
    var $hasOne = array(
        'LastLogin' => array(
            'className' => 'Login',
            'fields' => array('MAX(LastLogin.created) as last_login')
        )
    );

    // This takes the last_login field from the [0] keyed array and puts it into 
    // [User]. You could also put this into your AppModel and it would work for 
    // all find operations where you use an SQL function in the 'fields' key.
    function afterFind($results, $primary=false) {
        if (!empty($results)) {
            foreach ($results as $i => $result) {
                if (!empty($result[0])) { // If the [0] key exists in a result...
                    foreach ($result[0] as $key => $value) { // ...cycle through all its fields...
                        $results[$i][$this->alias][$key] = $value; // ...move them to the main result...
                    }
                    unset($results[$i][0]); // ...and finally remove the [0] array
                }
            }
        }
        return parent::afterFind($results, $primary=false); // Don't forget to call the parent::afterFind()
    }
}

Пользовательский контроллер:

class UsersController extends AppController {
    var $name = 'Users';

    function index() {
        $this->autoRender = false;
        pr($this->User->find('all'));
    }
}
0 голосов
/ 14 сентября 2013

У меня была похожая ситуация, но у меня была

Product hasMany Price

Я хотел Product hasOne CurrentPrice с CurrentPrice, определенным как самая верхняя найденная запись, если она отсортирована по created в порядке убывания.

Я решил мой таким образом.Но вместо этого я собираюсь использовать ваш User и LastLogin.

class User extends AppModel {
    var $name = 'User';
    var $hasMany = array('Login');
    var $hasOne = array(
        'LastLogin' => array(
            'className' => 'Login',
            'order' => 'LastLogin.created DESC'
       )
   );

Если вы думаете об этом, созданный и id имеют одинаковое значение.поэтому вы также можете использовать id в порядке убывания.

Я предполагаю, что схема вашей таблицы похожа на one , предложенную mtnorthrop .

то есть

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
)
logins table:

CREATE TABLE `logins` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...