Отбор по дате в timestamp

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Отбор по дате в timestamp

Сообщение Drugpunker »

Здравствуйте.
Не удаётся победить казалось бы тривиальную задачку.

Поле в базе - created_at.
Заполняется with TimestampBehavior.

Хочу сделать выборку последних записей за месяц.

В контроллере пытаюсь задать условие отбора:

Код: Выделить всё

	$date = new DateTime();
        $minus_month = $date->modify("-1 month");
        //Количество секунд для отбора
        $criteria = $minus_month->getTimestamp();

        $searchModel = new NotesSearch();
        $dataProvider = $searchModel->search([
            'NotesSearch' => ['created_at' >= $criteria]
        ]);


В методе search поисковой модели почти всё по дефолту:

Код: Выделить всё

	$query = Notes::find();

        // add conditions that should always apply here

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'sort' => [
                'defaultOrder' => [
                    'created_at' => SORT_DESC,
                ]
            ]
        ]);
И отбор не работает в таком исполнении.
Пробовал задавать andFilterWhere, извращался как мог.
Увы результата null.

Куда здесь копать? Подскажите пжл.
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Отбор по дате в timestamp

Сообщение skynin »

Когда не работает базовый функционал - ищи ошибку в своем коде

А вы рассказываете о базовом функционале и приводите примеры из документации.

Если бы все сделали как нужно - то базовый функционал - работал бы

Ищите что вы сделали не так

-- Куда здесь копать?
здесь - никуда

копайте в свой код, схему БД, и т.д.

например вы привели инициализацию
dataProvider

а кто знает что вы с этой переменной дальше делаете?
может ничего, может передеете не ту, может повторно инициализируете, может используете не в том виджете, может ...

копайте свой код
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Отбор по дате в timestamp

Сообщение Drugpunker »

skynin писал(а): 2020.07.01, 08:32 Когда не работает базовый функционал - ищи ошибку в своем коде

А вы рассказываете о базовом функционале и приводите примеры из документации.

Если бы все сделали как нужно - то базовый функционал - работал бы

Ищите что вы сделали не так

-- Куда здесь копать?
здесь - никуда

копайте в свой код, схему БД, и т.д.

например вы привели инициализацию
dataProvider

а кто знает что вы с этой переменной дальше делаете?
может ничего, может передеете не ту, может повторно инициализируете, может используете не в том виджете, может ...

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

Вопрос мой заключается в том, а правильно ли я задаю условие отбора.
Вижу, что нет.
И не знаю как.
За сим и пришёл сюда.
Какой там ещё может быть код. :|
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Отбор по дате в timestamp

Сообщение unknownby »

Drugpunker писал(а): 2020.07.01, 09:15 Вопрос мой заключается в том, а правильно ли я задаю условие отбора.
Вижу, что нет.
И не знаю как.
За сим и пришёл сюда.
Для чего такая запись?
Для чего вообще логика в контроллере?

Код: Выделить всё

$dataProvider = $searchModel->search([
            'NotesSearch' => ['created_at' >= $criteria]
        ]);
Если по логике можно было бы сделать вот как, чтобы брало инфу из фильтров грида.

Код: Выделить всё

$dataProvider = $searchModel->search(\Yii::$app->getRequest()->get());
А внутри NotesSearch

Код: Выделить всё

public function search($params)
    {
        $query = Notes::find()
            ->where(['>=', 'created_at', date("Y-m-d H:i:s", strtotime('-1 month'))]);

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'sort' => ['defaultOrder' => ['created_at' => SORT_DESC]],
        ]);

        $this->load($params);

        if (!$this->validate()) {
            // uncomment the following line if you do not want to any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }

       //add some $query->andFilterWhere(['some' => $this->some]);

        return $dataProvider;
    }
Преобразовать в строке where нужно под своё значение, если у тебя секунды, то date("U")
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Отбор по дате в timestamp

Сообщение skynin »

Drugpunker писал(а): 2020.07.01, 09:15 Какой там ещё может быть код. :|
Поле в базе - created_at - глазами смотрели? поле заполнено правильно?

про переменные
в одном случае у вас:
$dataProvider = $searchModel->search
в другом
$dataProvider = new ActiveDataProvider

так какой вы из этих двоих используете?
а может у вас еще какие-то $dataProvider есть. кто вас знает, что у вас там в коде еще припрятано.

далее
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
]

работает?
не работает отбор?
так он должен быть в 'query' => $query,
то есть
$query = Notes::find();
$query->andWhere бла-бла-бла
он там есть?

смотрим выше
Хочу сделать выборку последних записей за месяц.

и где код который это делает?
его нет
['created_at' >= $criteria] - это код
if (created_at == дата месячной давности)

то есть, непонятно что вы хотите. вы говорите что хотите выбрать за последний месяц, а в коде написали
что хотите за 1 день месяц тому

конструкцию
'NotesSearch' => ['created_at' >= $criteria]

я вообще не понял, и кода не видно
$searchModel->search

метод search у объекта $searchModel понимает такой параметр, массив
с ключем 'NotesSearch' и значением NotesSearch' - массив?
он обрабатывает этот параметр?

кода вы не показали.

итого - копайте тот код который вы не показали.
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Отбор по дате в timestamp

Сообщение Drugpunker »

unknownby писал(а): 2020.07.01, 09:32
Drugpunker писал(а): 2020.07.01, 09:15 Вопрос мой заключается в том, а правильно ли я задаю условие отбора.
Вижу, что нет.
И не знаю как.
За сим и пришёл сюда.
Для чего такая запись?
Для чего вообще логика в контроллере?

Код: Выделить всё

$dataProvider = $searchModel->search([
            'NotesSearch' => ['created_at' >= $criteria]
        ]);
Пока так проще.
И метод сёрч должен фильтровать по месяцу, неделе, году, в зависимости от экшна.
Как сделать логику только лишь в модели я ещё не придумал.

Отбор в контроллере временно сделал так:

Код: Выделить всё

$dataProvider->query->andWhere('created_at >=' . $criteria);
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Отбор по дате в timestamp

Сообщение skynin »

Drugpunker писал(а): 2020.07.01, 10:04 Отбор в контроллере временно сделал так:

Код: Выделить всё

$dataProvider->query->andWhere('created_at >=' . $criteria);
и все равно не работает?

посмотрите запросы к БД. они такие как нужно?
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Отбор по дате в timestamp

Сообщение unknownby »

Drugpunker писал(а): 2020.07.01, 10:04 Пока так проще.
Так не проще, так не правильно. Логика должна быть в модели, в контроллере не должно быть логики. Я написал выше, как должно быть в контроллере и модели search.
Drugpunker писал(а): 2020.07.01, 10:04 И метод сёрч должен фильтровать по месяцу, неделе, году, в зависимости от экшна.
Как сделать логику только лишь в модели я ещё не придумал.
Для того, чтобы искало по месяцу, неделе или году по разным экшенам, то должно быть чуток по другому. А именно сюда (в контроллере в каждом экшене) передаем дату $date. Формируем её с нужным "за месяц", "за год", "за день".

Код: Выделить всё

$dataProvider = $searchModel->search(\Yii::$app->getRequest()->get(), $date);
Drugpunker писал(а): 2020.07.01, 10:04 Отбор в контроллере временно сделал так:

Код: Выделить всё

$dataProvider->query->andWhere('created_at >=' . $criteria);
Контроллер должен быть минимальным
Вот такие примерно экшны должны быть, если ты намерен где-то по кнопкам жмякать, чтобы выводила разные данные.

Код: Выделить всё

public function findGridDate($date){
        $searchModel  = new NotesSearch;
	$dataProvider = $searchModel->search(\Yii::$app->getRequest()->get(), $date);

       	 return $this->render('YOUR_VIEW', [
            	'dataProvider' => $dataProvider,
           	 'searchModel' => $searchModel,
        ]);
}

//-1 month
public function actionMonth()
{
	return $this->findGridDate( date("Y-m-d H:i:s", strtotime('-1 month')));
}
    
//-1 week
public function actionWeek()
{
    	return $this->findGridDate( date("Y-m-d H:i:s", strtotime('-1 week')));
}
    
//-1 year
public function actionYear()
{
    	return $this->findGridDate( date("Y-m-d H:i:s", strtotime('-1 year')));
}
В search меняем на такое

Код: Выделить всё

public function search($params, $date)
    {
        $query = Notes::find()
            ->where(['>=', 'created_at', $date]);
            //somecode...
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Отбор по дате в timestamp

Сообщение Drugpunker »

unknownby писал(а): 2020.07.01, 10:44
Drugpunker писал(а): 2020.07.01, 10:04 Пока так проще.
Так не проще, так не правильно. Логика должна быть в модели, в контроллере не должно быть логики. Я написал выше, как должно быть в контроллере и модели search.
Drugpunker писал(а): 2020.07.01, 10:04 И метод сёрч должен фильтровать по месяцу, неделе, году, в зависимости от экшна.
Как сделать логику только лишь в модели я ещё не придумал.
Для того, чтобы искало по месяцу, неделе или году по разным экшенам, то должно быть чуток по другому. А именно сюда (в контроллере в каждом экшене) передаем дату $date. Формируем её с нужным "за месяц", "за год", "за день".

Код: Выделить всё

$dataProvider = $searchModel->search(\Yii::$app->getRequest()->get(), $date);
Drugpunker писал(а): 2020.07.01, 10:04 Отбор в контроллере временно сделал так:

Код: Выделить всё

$dataProvider->query->andWhere('created_at >=' . $criteria);
Контроллер должен быть минимальным
Вот такие примерно экшны должны быть, если ты намерен где-то по кнопкам жмякать, чтобы выводила разные данные.

Код: Выделить всё

public function findGridDate($date){
        $searchModel  = new NotesSearch;
	$dataProvider = $searchModel->search(\Yii::$app->getRequest()->get(), $date);

       	 return $this->render('YOUR_VIEW', [
            	'dataProvider' => $dataProvider,
           	 'searchModel' => $searchModel,
        ]);
}

//-1 month
public function actionMonth()
{
	return $this->findGridDate( date("Y-m-d H:i:s", strtotime('-1 month')));
}
    
//-1 week
public function actionWeek()
{
    	return $this->findGridDate( date("Y-m-d H:i:s", strtotime('-1 week')));
}
    
//-1 year
public function actionYear()
{
    	return $this->findGridDate( date("Y-m-d H:i:s", strtotime('-1 year')));
}
В search меняем на такое

Код: Выделить всё

public function search($params, $date)
    {
        $query = Notes::find()
            ->where(['>=', 'created_at', $date]);
            //somecode...
Да я понимаю, что вся логика должна быть в модели.
В настоящее время нет должного опыта, чтобы сразу писать в парадигме mvc.
Поэтому делаю сначала как получится, т.к. приходится много изучать. А уже после, оптимизирую и вгоняю в рамки верного.

Спасибо большое. Примерно так и намеревался сделать, решив проблемы с запросом.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Отбор по дате в timestamp

Сообщение unknownby »

Drugpunker писал(а): 2020.07.01, 10:52 Спасибо большое. Примерно так и намеревался сделать, решив проблемы с запросом.
Так какие проблемы с запросом то?
Есть какие-нибудь ошибки? Какого формата лежат в created_at данные?
Если переделаешь под мой вариант, можно будет узнать получше в чём ошибка.

P.S. поделай хоть скриншотов, чтоб видеть то, что видешь ты. В чём у тебя отображаются данные (твой грид), может ошибку, которая есть в дебагере
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Отбор по дате в timestamp

Сообщение Drugpunker »

unknownby писал(а): 2020.07.01, 11:12
Drugpunker писал(а): 2020.07.01, 10:52 Спасибо большое. Примерно так и намеревался сделать, решив проблемы с запросом.
Так какие проблемы с запросом то?
Есть какие-нибудь ошибки? Какого формата лежат в created_at данные?
Если переделаешь под мой вариант, можно будет узнать получше в чём ошибка.

P.S. поделай хоть скриншотов, чтоб видеть то, что видешь ты. В чём у тебя отображаются данные (твой грид), может ошибку, которая есть в дебагере
Ошибок нет вобще.
Данные, как писал в первом посте, добавляются с помощью Таймстамп поведения, в интеджере то бишь.
Запрос в бд, дебаггер показывал без условия отбора по дате.
Данные через листвью отображаются.

Как сделаю обязательно напишу.
Пока не добрался до бука.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Отбор по дате в timestamp

Сообщение Drugpunker »

unknownby писал(а): 2020.07.01, 11:12
Drugpunker писал(а): 2020.07.01, 10:52 Спасибо большое. Примерно так и намеревался сделать, решив проблемы с запросом.
Так какие проблемы с запросом то?
Есть какие-нибудь ошибки? Какого формата лежат в created_at данные?
Если переделаешь под мой вариант, можно будет узнать получше в чём ошибка.

P.S. поделай хоть скриншотов, чтоб видеть то, что видешь ты. В чём у тебя отображаются данные (твой грид), может ошибку, которая есть в дебагере
Короче выборка работает, спасибо ещё раз.
И код красиво структуирован.

Подскажи пжл ещё о правильном моделировании :)

Метод сёрч в модели выполняет отбор по указанным датам.
Но он же должен выполнять поиск по определённому полю и уже без отбора по датам.

В контроллере сейчас у меня вот так:

Код: Выделить всё

$dataProvider = $searchModel->search([
            'NotesSearch' => ['category_id' => $id]
        ]);

Опять добавлять аргумент в метод?

Код: Выделить всё

public function search($params, $date = '', $id = '')
И уже после, в зависимости от количества не пустых аргументов выстраивать логику поиска?
Например так:

Код: Выделить всё

public function search($params, $date = '', $id = '')
    {
        $query = Notes::find();

        if(!empty($date)) {
            $query->where(['>=', 'created_at', $date]);
        }

        if(!empty($id)) {
            $query->where(['=', 'category_id', $id]);
        }
Верно мыслю?
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Отбор по дате в timestamp

Сообщение skynin »

Drugpunker писал(а): 2020.07.01, 13:15 Верно мыслю?
Неверно, потому что изобретаете что-то свое.
Зачем, с какой целью?

Посмотрите как геренирует код Gii например
А лучше поищите на гитхабе код проектов

кратко
search модель наследуется от основной

сам search обычно такой

Код: Выделить всё

public function search($params)

$query = self::find()....

$dataProvider = new ActiveDataProvider([ ....

$dataProvider->setSort(

$this->load($params);

if (!$this->validate()) {
return $dataProvider;
}

        $query->andFilterWhere([
            'AND',
            ['id' => $id],
            // и т.д.
        ]);

        $query->andFilterHaving([
            'AND',
            ['series_id' => $this->series_id],
            // и т.д.
        ]);

return $dataProvider;
в контроллере

$searchModel = new NotesActiveSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);

P.S. Посмотрел, все есть в документации

https://www.yiiframework.com/doc/guide/ ... ta-widgets
см Фильтрация данных
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Отбор по дате в timestamp

Сообщение unknownby »

Drugpunker писал(а): 2020.07.01, 13:15
Короче выборка работает, спасибо ещё раз.
И код красиво структуирован.

Подскажи пжл ещё о правильном моделировании :)

Метод сёрч в модели выполняет отбор по указанным датам.
Но он же должен выполнять поиск по определённому полю и уже без отбора по датам.

В контроллере сейчас у меня вот так:

Код: Выделить всё

$dataProvider = $searchModel->search([
            'NotesSearch' => ['category_id' => $id]
        ]);

Опять добавлять аргумент в метод?

Код: Выделить всё

public function search($params, $date = '', $id = '')
И уже после, в зависимости от количества не пустых аргументов выстраивать логику поиска?
Например так:

Код: Выделить всё

public function search($params, $date = '', $id = '')
    {
        $query = Notes::find();

        if(!empty($date)) {
            $query->where(['>=', 'created_at', $date]);
        }

        if(!empty($id)) {
            $query->where(['=', 'category_id', $id]);
        }
Верно мыслю?
Ну смотри, по полочкам.
Данный метод принимает в себя параметры, которые приходят из GET запроса + дата, которая тебе нужна была для разных экшенов

Код: Выделить всё

$searchModel->search(\Yii::$app->getRequest()->get(), $date);
По сути всё отталкивается от твоей логики выполнения. Но если я верно думаю, то тебе нужно помимо того, что выбрана дата создания за 1 месяц, то нужно еще дополнительно отфильтровать по категории, например.

Поэтому я и писал комментарий внутри search, и дополнительно просил скриншот, чтобы увидеть то, что видишь ты

Код: Выделить всё

public function search($params, $date)
    {
        $query = Notes::find()
            ->where(['>=', 'created_at', $date]);

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'sort' => ['defaultOrder' => ['created_at' => SORT_DESC]],
        ]);

        $this->load($params);

        if (!$this->validate()) {
            // uncomment the following line if you do not want to any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }

       //add some $query->andFilterWhere(['some' => $this->some]);
       //тут добавляем нужные фильтры, которые выбираются где-то в форме
       //например по категории
       
       $query->andFilterWhere([
       		'category_id' => $this->category_id,
       		//'some_id' => $this->some_id,
       		//'some_id' => $this->some_id,
       		//'some_id' => $this->some_id,
       		//'some_id' => $this->some_id,
       	]);
       	
       	//если нужно добавить фильтр по текстовому полю
       	//$query->andFilterWhere(['like', 'category_id', $this->category_id]);
       	//или такого плана можно, если много
       	//$query->andFilterWhere(['like', 'category_name', $this->category_name])
       	//	->andFilterWhere(['like', 'some_name', $this->some_name])
       	//	->andFilterWhere(['like', 'some_name', $this->some_name])
       	//	->andFilterWhere(['like', 'some_name', $this->some_name])
       	//	->andFilterWhere(['like', 'some_name', $this->some_name]);

        return $dataProvider;
    }
Проверку на пустую дату, стоит делать, если тебе нужно абсолютно все записи и не важно за какой период.
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Отбор по дате в timestamp

Сообщение Dominus »

Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
Ответить