'components' => [
'queue' => [
'class' => \yii\queue\file\Queue::class,
'path' => '@console/runtime/queue',
'as log' => \yii\queue\LogBehavior::class,
],
'bootstrap' => [
'queue',
],
<?php
class QueueHelper
{
public static function setTask ($task) {
Yii::$app->queue->push($task);
}
public static function setDelayTask ($task , $delay = 5) { // delay - задержка выполнения в сек
Yii::$app->queue->delay($delay)->push($task);
}
}
class TaskEndEvent extends BaseObject implements \yii\queue\JobInterface
{
public $idTask;
public function execute($queue)
{
$e = Events::findOne($this->idTask);
if ($e->status != 1 ){
$e->ended_at = $e->creation_at + 7200 ;
$e->status = 1 ;
$e->save(false);
}
}
}
public function afterSave($insert, $changedAttributes)
{
parent::afterSave($insert, $changedAttributes);
if ($this->status != 1){
QueueHelper::setDelayTask(new TaskEndEvent(['idTask'=>$this->id]), 7200);
}
}
cron run * * * * * /usr/bin/php /var/www/my_project/yii queue/run
yii queue/listen
//dist расстояние , в моем случает от центра карты до лев верх угла карты в метрах.
// те это то расстояние от центра на котором мы поставим наши точки
// a = угол на который наклонить точки относительно нулевого азимута.
// lat и long координаты точки в центре экрана
var p180= 180/pi;
var dx = p180 * ((cos(a / 180 * pi) * dist) / 6378137) ;
var dy = p180 * ((sin(a / 180 * pi) * dist) / 6378137) ;
var toplat = latitude + dy;
var toplng = longitude + dx / cos(latitude);
var bottomlat = latitude - dy;
var bottomlng = longitude - dx / cos(latitude);
$topLeftLat = $_POST['topLeftLat'];
$topLefiLng = $_POST['topLeftLng'];
$bottomRightLat = $_POST['bottomRightLat'];
$bottomRightLng = $_POST['bottomRightLng'];
$zoom = $_POST['zoom'];
$params['bool']['filter'][]['bool']['must']=
[
[
"exists" => [
"field" => "location"
]
],
[
"geo_bounding_box" => [
"location" => [
"top_left" => $topLeftLat.','.$topLefiLng,
"bottom_right" => $bottomRightLat.','.$bottomRightLng
]
]
]
];
$query = ElasticObj::find();
$p = ($zoom > 10 )? 10 : 8-(6-$zoom);
$query->addAggregate('gridSplit', [
'geotile_grid' => [
'bounds' => [
"top_left" => $topLeftLat.','.$topLefiLng,
"bottom_right" => $bottomRightLat.','.$bottomRightLng
],
"field" => "location",
"precision" => $p,
"size" => 65535,
"shard_size" => 65535
],
'aggs' => [
'gridCentroid' => [
'geo_centroid' => [
'field' => 'location'
]
]
]
]);
$query->query($params);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$aggregations = $dataProvider->getAggregations();
SELECT s.* ,st.`name` AS type_name , group_concat(DISTINCT benefits.name SEPARATOR ' ') as concat_bn, st.alias as spot_type_alias, benefits.alias as benefit_alias, CONCAT(" ", group_concat(DISTINCT benefits.id SEPARATOR ' ') ," ") as concat_bn_id,
// для полей s.name , s.track, st.name , st.alias ,benefits.name , benefits.alias в каждой таблице создаем полнотекстовый индекс.
//
// тут считаем релевантность запроса
MATCH(s.name , s.track) AGAINST('+$query') as score,
MATCH(st.name , st.alias) AGAINST('+$query') as stcore,
MATCH(benefits.name , benefits.alias) AGAINST('+$query') as bncore,
( // тут считаем расстояние до точки (тк я ищу точки ) (опционально)
6371 *
acos(cos(radians($lat)) *
cos(radians(s.lat)) *
cos(radians(s.lng) -
radians($lng)) +
sin(radians($lat)) *
sin(radians(s.lat)))
) AS distance
FROM `spots` s
// прикручиваем связь один к одному для поиска по типу из другой таблицы
JOIN `spot_type` st ON s.id_spot_type = st.id
// прикручиваем сводную таблицу для связи многие ко многим для поиска по типам плюшек на точке
join spots_benefits
on spots_benefits.spot = s.id
join benefits
on benefits.id = spots_benefits.benefit
where
//собственно сам поиск
MATCH(s.name, s.track) AGAINST('+$query')
OR MATCH(st.name, st.alias) AGAINST('+$query')
OR MATCH(benefits.name, benefits.alias) AGAINST('+$query')
// групируем элементы из сводных таблиц в одно поле груп_конкат
group by s.id
// ищем по только те что были добавлены в фильтр (опционально) типов
HAVING concat_bn_id like "% 1 %" AND concat_bn_id like '% 2 %' AND s.id_spot_type = 2
// сортируем сначала по релевантности, а потом уже по расстоянию
ORDER BY (score + stcore + bncore) DESC, distance ASC
SET @home = ST_GeomFromText('LINESTRING(
//Список наших точек через которые идет маршрут
53.862263 27.483486,
53.871521 27.493636,
53.875594 27.496447,
53.880938 27.500744,
53.882699 27.505121,
53.884246 27.504435,
53.891446 27.500293,
53.896630 27.497375,
53.905348 27.496302,
53.912531 27.495487,
53.918726 27.496882)');
SELECT *, ST_AsText(geo) as Coord,
// Дистанция считается странно получается вроде правильно , но не уверен насчет точности .
// В оригинале в доках написано умножать ее на .001 для км и .00067... для миль
// но у меня так не работало и показывало до объекта 0,003км хотя по факту до него 300м вот я решил
умножать ее на 100 (хотя хз может оно там сантиметрах считает)
ST_DISTANCE(@home, geo) * 100 AS dist
FROM dots
// дистанция от маршрута в радиусе которой нам нужны точки (в км )
HAVING dist < 1
ORDER BY dist
LIMIT 30
class TimerService extends ChangeNotifier {
Stopwatch _watch = Stopwatch();
var _timer;
Duration get currentDuration => _currentDuration;
Duration _currentDuration = Duration.zero;
bool get isRunning => _timer != null;
TimerService() {
_watch = Stopwatch();
}
String get getTime => getDisplayTime(_currentDuration.inMilliseconds);
static String getDisplayTime(){
//перевод человеко читаемый вид(если кому надо пишите скину код)
}
void _onTick(Timer timer) {
_currentDuration = _watch.elapsed;
print(_currentDuration);
// notify all listening widgets
notifyListeners();
}
void start() {
if (_timer != null) return;
_timer = null;
_timer = Timer.periodic(Duration(seconds: 1), _onTick);
_watch.start();
notifyListeners();
}
void stop() {
_timer?.cancel();
_watch.stop();
_currentDuration = _watch.elapsed;
notifyListeners();
}
void reset() {
stop();
_watch.reset();
_currentDuration = Duration.zero;
notifyListeners();
}
}
class TimerServiceProvider extends InheritedWidget {
const TimerServiceProvider({Key? key, required this.service, required Widget
child})
: super(key: key, child: child);
final TimerService service;
@override
bool updateShouldNotify(TimerServiceProvider old) => service != old.service;
}
AnimatedBuilder(
animation: globalsVars.timerServ,
builder: (context, child) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 5 , left: 12),
decoration: (selectedButton == key)
? BoxDecoration(
border: Border.all(
color: Colors.white10,
width: 2,
),
borderRadius: BorderRadius.circular(5),
)
: null,
child: Text(
'${globalsVars.timerServ.getTime}',
style: GoogleFonts.roboto(
textStyle: TextStyle(
color: Colors.red,
fontWeight: FontWeight.w700,
fontSize: 16.sp,
)),
))
],
);
},
),