#php #mysql #laravel #eloquent
#php #mysql #laravel #eloquent
Вопрос:
Я новичок в laravel, только начал несколько дней назад, и я уже искал об этом, но ничего не нашел по моему вопросу. Например… У меня есть таблица offers и offers_prices.
Предложения:
---- -----------
| id | name |
---- -----------
| 1 | Product 1 |
| 2 | Product 2 |
| 3 | Product 3 |
| 4 | Product 4 |
---- -----------
offers_prices:
---- ------------ ------- ---------------------
| id | offer_id | price | created_at |
---- ------------ ------- ---------------------
| 1 | 1 | 65.90 | 2020-12-17 16:00:00 |
| 2 | 1 | 64.99 | 2020-12-17 17:00:00 |
| 3 | 1 | 58.90 | 2020-12-17 18:00:00 |
| 4 | 1 | 60.99 | 2020-12-17 19:00:00 |
---- ------------ ------- ---------------------
Чтобы получить текущую цену предложения (60,99) Я создал приведенную ниже функцию, чтобы получить ее из модели relationship eloquent:
Models/Offer.php
public function price() {
return parent::hasOne(OfferPrices::class)
->where("date", "<=", CarbonCarbon::now()->toDateTimeString())
->orderBy("date", "DESC")
->limit(1);
}
И теперь я хочу получить самую последнюю предыдущую цену, но выше текущей цены, как в приведенном ниже запросе:
SELECT *
FROM offers_prices
WHERE offers_prices.offer_id = 1
AND
offers_prices.price > (
SELECT offers_prices.price
FROM offers_prices
WHERE offers_prices.offer_id = 1
AND offers_prices.date <= NOW()
ORDER BY offers_prices.date DESC
LIMIT 1
)
AND offers_prices.date <= NOW()
ORDER BY offers_prices.date DESC
LIMIT 1;
Это означает, что недавняя предыдущая и более высокая, чем текущая цена, не может быть 58,90, потому что она ниже текущей (60,99). Должно быть 64,99.
Как я могу это сделать? Я попытался создать другую функцию в модели self eloquent:
Models/Offer.php
public function prev_high_price() {
return parent::hasOne(OfferPrices::class)
->where("date", "<=", CarbonCarbon::now()->toDateTimeString())
->where("price", ">", $this->price()->price)
->orderBy("date", "DESC")
->limit(1);
}
Но это не работает..
Ответ №1:
Вы используете hasOne
связь для связи с базой данных, которая больше похожа на hasMany
. У вас Offers
может быть много Prices
. Ваше именование таблицы также противоречит соглашению, поскольку вы не используете сводную таблицу, но назвали свою offers_prices
таблицу так, как если бы она была.
Не по теме вопроса, но имеет отношение к вашей ситуации, желательно не хранить значения валюты в виде чисел с плавающей запятой или удвоений. Сохраните их как целые числа в наименьшем знаменателе.
Чтобы ответить на ваш вопрос, учитывая следующие две миграции:
Предлагает перенос таблиц
class CreateOffersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('offers', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('name');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('offers');
}
}
Миграция таблицы цен
class CreatePricesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('prices', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->foreignId('offer_id');
$table->integer('price');
$table->foreign('offer_id')->references('id')->on('offers');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('prices');
}
}
Определите следующее в вашей Offer
модели:
class Offer extends Model
{
use HasFactory;
public function prices()
{
return $this->hasMany(Price::class);
}
public function lastPrice()
{
return $this->prices()->orderBy('id', 'desc')->limit(1);
}
public function lastHighPrice()
{
return $this->prices()
->where('id', '<', $this->lastPrice()->first()->id)
->orderBy('price', 'desc')
->limit(1);
}
}
Запустите средства миграции и обработки базы данных (если они у вас есть, в противном случае просто добавьте данные вручную). В вашем терминале, пока вы находитесь в текущем рабочем каталоге, находится ваш проект Laravel, запустите tinker
:
php artisan tinker
Теперь внутри tinker вы можете играть со своими данными и моделями.
// get a collection of all prices for the Offer with id 1
Offer::find(1)->prices
// get a collection with the last price for the offer with id 1
Offer::find(1)->lastPrice
// get a collection with the previous highest price for the offer with id 1
Offer::find(1)->lastHighPrice
Комментарии:
1. Это работает, когда «find (id)», но не работает, когда я пытаюсь получить его от UserOffersFavorited в пользовательской модели: См. prnt.sc/w53ben Но когда он запускается
$this->price()->first()->price
, он не получает цену из идентификатора иностранного предложения. Когда я отслеживаю переменную выше, она просто возвращает первую цену из всей таблицы, независимой от offer_id (чего не должно произойти)2. @CarlosLoureiro Ну да, нигде в вашем первоначальном вопросе вы не ссылались на
User
UserOffersFavorited
таблицу модели или базы данных, и ни один из примеров таблицы не содержит ссылки на aUser
. Это звучит как совершенно другой вопрос.3. Да. Но вы знаете, как я могу заставить его работать так, как мне нужно?
4. @CarlosLoureiro Не зная больше о вашем варианте использования, например, как вы определяете UserOffersFavorited. Однако это вопрос, отличный от того, который вы задали, и поэтому должен быть новый поток. На заданный вами вопрос был дан ответ.