Campaign_Landing_Pages.php
4 days ago
Campaign_UTM_Campaigns.php
4 days ago
Campaign_UTM_Mediums.php
4 days ago
Campaign_UTM_Sources.php
4 days ago
Campaigns.php
4 days ago
Cities.php
4 days ago
Countries.php
4 days ago
Device_Browsers.php
4 days ago
Device_OSS.php
4 days ago
Device_Types.php
4 days ago
Filter.php
5 months ago
Forms.php
5 months ago
Journeys.php
3 months ago
Link_Patterns.php
4 months ago
Links.php
5 months ago
Pages.php
4 days ago
Referrer_Types.php
4 days ago
Referrers.php
4 days ago
Rows.php
4 days ago
Countries.php
89 lines
| 1 | <?php |
| 2 | |
| 3 | namespace IAWP\Rows; |
| 4 | |
| 5 | use IAWP\Form_Submissions\Form; |
| 6 | use IAWP\Illuminate_Builder; |
| 7 | use IAWP\Models\Geo; |
| 8 | use IAWP\Query_Taps; |
| 9 | use IAWP\Tables; |
| 10 | use IAWPSCOPED\Illuminate\Database\Query\Builder; |
| 11 | use IAWPSCOPED\Illuminate\Database\Query\JoinClause; |
| 12 | /** @internal */ |
| 13 | class Countries extends \IAWP\Rows\Rows |
| 14 | { |
| 15 | public function attach_filters(Builder $query) : void |
| 16 | { |
| 17 | $query->joinSub($this->query(\true), 'country_rows', function (JoinClause $join) { |
| 18 | $join->on('country_rows.country_id', '=', 'sessions.country_id'); |
| 19 | }); |
| 20 | } |
| 21 | protected function fetch_rows() : array |
| 22 | { |
| 23 | $rows = $this->query()->get()->all(); |
| 24 | return \array_map(function ($row) { |
| 25 | return new Geo($row); |
| 26 | }, $rows); |
| 27 | } |
| 28 | protected function sort_tie_breaker_column() : string |
| 29 | { |
| 30 | return 'country'; |
| 31 | } |
| 32 | private function query(?bool $skip_pagination = \false) : Builder |
| 33 | { |
| 34 | if ($skip_pagination) { |
| 35 | $this->number_of_rows = null; |
| 36 | } |
| 37 | $clicks_subquery = Illuminate_Builder::new()->select('sessions.country_id')->selectRaw('COUNT(*) AS clicks')->from(Tables::clicks(), 'clicks')->join(Tables::views() . ' AS views', 'clicks.view_id', '=', 'views.id')->join(Tables::sessions() . ' AS sessions', 'views.session_id', '=', 'sessions.session_id')->tap(Query_Taps::tap_authored_content_check())->tap(Query_Taps::tap_related_to_examined_record($this->examiner_config, ['clicks']))->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when($this->is_real_time(), function (Builder $query) { |
| 38 | $query->whereNull('views.next_view_id'); |
| 39 | })->when(!$this->is_real_time(), function (Builder $query) { |
| 40 | $query->whereBetween('sessions.created_at', $this->get_current_period_iso_range()); |
| 41 | })->groupBy('sessions.country_id'); |
| 42 | $orders_subquery = Illuminate_Builder::new()->select('sessions.country_id')->selectRaw('COUNT(*) AS orders')->selectRaw('IFNULL(CAST(SUM(total) AS SIGNED), 0) AS gross_sales')->selectRaw('IFNULL(CAST(SUM(total_refunded) AS SIGNED), 0) AS total_refunded')->selectRaw('IFNULL(CAST(SUM(total_refunds) AS SIGNED), 0) AS total_refunds')->selectRaw('IFNULL(CAST(SUM(total - total_refunded) AS SIGNED), 0) AS net_sales')->from(Tables::orders(), 'orders')->join(Tables::views() . ' AS views', 'orders.initial_view_id', '=', 'views.id')->join(Tables::sessions() . ' AS sessions', 'views.session_id', '=', 'sessions.session_id')->where('is_included_in_analytics', '=', \true)->tap(Query_Taps::tap_authored_content_check())->tap(Query_Taps::tap_related_to_examined_record($this->examiner_config))->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when($this->is_real_time(), function (Builder $query) { |
| 43 | $query->whereNull('views.next_view_id'); |
| 44 | })->when(!$this->is_real_time(), function (Builder $query) { |
| 45 | $query->whereBetween('sessions.created_at', $this->get_current_period_iso_range()); |
| 46 | })->groupBy('sessions.country_id'); |
| 47 | $form_submissions_subquery = Illuminate_Builder::new()->select('sessions.country_id')->selectRaw('COUNT(*) AS form_submissions')->tap(function (Builder $query) { |
| 48 | foreach (Form::get_forms() as $form) { |
| 49 | $query->selectRaw('CAST(SUM(IF(form_id = ?, 1, 0)) AS SIGNED) AS ' . $form->submissions_column(), [$form->id()]); |
| 50 | } |
| 51 | })->from(Tables::form_submissions(), 'form_submissions')->join(Tables::views() . ' AS views', 'form_submissions.view_id', '=', 'views.id')->join(Tables::sessions() . ' AS sessions', 'views.session_id', '=', 'sessions.session_id')->tap(Query_Taps::tap_authored_content_check())->tap(Query_Taps::tap_related_to_examined_record($this->examiner_config))->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when($this->is_real_time(), function (Builder $query) { |
| 52 | $query->whereNull('views.next_view_id'); |
| 53 | })->when(!$this->is_real_time(), function (Builder $query) { |
| 54 | $query->whereBetween('sessions.created_at', $this->get_current_period_iso_range()); |
| 55 | })->groupBy('sessions.country_id'); |
| 56 | $session_duration_query = Illuminate_Builder::new()->select('sessions.country_id')->selectRaw('AVG(TIMESTAMPDIFF(SECOND, sessions.created_at, sessions.ended_at)) AS average_session_duration')->from(Tables::sessions(), 'sessions')->whereIn('sessions.session_id', function ($subquery) { |
| 57 | $subquery->select('views.session_id')->from(Tables::views(), 'views')->join(Tables::sessions() . ' AS sessions', 'views.session_id', '=', 'sessions.session_id')->tap(Query_Taps::tap_authored_content_check())->tap(Query_Taps::tap_related_to_examined_record($this->examiner_config))->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when($this->is_real_time(), function (Builder $query) { |
| 58 | $query->whereNull('views.next_view_id'); |
| 59 | })->when(!$this->is_real_time(), function (Builder $query) { |
| 60 | $query->whereBetween('sessions.created_at', $this->get_current_period_iso_range()); |
| 61 | }); |
| 62 | })->groupBy('sessions.country_id'); |
| 63 | $countries_query = Illuminate_Builder::new()->select('countries.country_id', 'countries.country_code', 'countries.country', 'countries.continent')->selectRaw('COUNT(DISTINCT views.id) AS views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS visitors')->selectRaw('COUNT(DISTINCT sessions.session_id) AS sessions')->selectRaw('MAX(session_durations.average_session_duration) AS average_session_duration')->selectRaw('COUNT(DISTINCT IF(sessions.final_view_id IS NULL, sessions.session_id, NULL)) AS bounces')->from(Tables::sessions() . ' AS sessions')->leftJoin(Tables::views() . ' AS views', 'sessions.session_id', '=', 'views.session_id')->leftJoin(Tables::countries() . ' AS countries', 'sessions.country_id', '=', 'countries.country_id')->leftJoinSub($session_duration_query, 'session_durations', 'sessions.country_id', '=', 'session_durations.country_id')->tap(Query_Taps::tap_authored_content_check())->tap(Query_Taps::tap_related_to_examined_record($this->examiner_config))->whereNotNull('sessions.country_id')->groupBy('sessions.country_id')->having('views', '>', 0)->tap(fn(Builder $query) => $this->apply_record_filters($query))->whereBetween('views.viewed_at', $this->get_current_period_iso_range())->when($this->is_real_time(), function (Builder $query) { |
| 64 | $query->whereNull('views.next_view_id'); |
| 65 | })->when(!$this->is_real_time(), function (Builder $query) { |
| 66 | $query->whereBetween('sessions.created_at', $this->get_current_period_iso_range()); |
| 67 | })->when(\is_int($this->solo_record_id), function (Builder $query) { |
| 68 | $query->where('countries.country_id', '=', $this->solo_record_id); |
| 69 | })->when($this->can_order_and_limit_at_record_level(), function (Builder $query) { |
| 70 | $query->tap(fn(Builder $query) => $this->apply_order_and_limit($query, $this->sort_configuration->column())); |
| 71 | }); |
| 72 | $previous_period_query = Illuminate_Builder::new()->select('sessions.country_id')->selectRaw('COUNT(DISTINCT views.id) AS previous_period_views')->selectRaw('COUNT(DISTINCT sessions.visitor_id) AS previous_period_visitors')->from(Tables::views(), 'views')->leftJoin(Tables::sessions() . ' AS sessions', 'views.session_id', '=', 'sessions.session_id')->tap(Query_Taps::tap_related_to_examined_record_for_previous_period($this->examiner_config, ['views', 'sessions']))->whereNotNull('sessions.country_id')->whereBetween('sessions.created_at', $this->get_previous_period_iso_range())->groupBy('sessions.country_id'); |
| 73 | $outer_query = Illuminate_Builder::new()->selectRaw('countries.*')->selectRaw('IF(sessions = 0, 0, views / sessions) AS views_per_session')->selectRaw('IFNULL((views - previous_period_views) / previous_period_views * 100, 0) AS views_growth')->selectRaw('IFNULL((visitors - previous_period_visitors) / previous_period_visitors * 100, 0) AS visitors_growth')->selectRaw('IFNULL(bounces / sessions * 100, 0) AS bounce_rate')->selectRaw('IFNULL(click_stats.clicks, 0) AS clicks')->selectRaw('IFNULL(order_stats.orders, 0) AS wc_orders')->selectRaw('IFNULL(order_stats.gross_sales, 0) AS wc_gross_sales')->selectRaw('IFNULL(order_stats.total_refunded, 0) AS wc_refunded_amount')->selectRaw('IFNULL(order_stats.total_refunds, 0) AS wc_refunds')->selectRaw('ROUND(CAST(IFNULL(order_stats.gross_sales, 0) - IFNULL(order_stats.total_refunded, 0) AS SIGNED)) AS wc_net_sales')->selectRaw('IF(visitors = 0, 0, (IFNULL(order_stats.orders, 0) / visitors) * 100) AS wc_conversion_rate')->selectRaw('IF(visitors = 0, 0, (IFNULL(order_stats.gross_sales, 0) - IFNULL(order_stats.total_refunded, 0)) / visitors) AS wc_earnings_per_visitor')->selectRaw('IF(IFNULL(order_stats.orders, 0) = 0, 0, ROUND(CAST(IFNULL(order_stats.gross_sales, 0) / order_stats.orders AS SIGNED))) AS wc_average_order_volume')->selectRaw('IFNULL(form_submission_stats.form_submissions, 0) AS form_submissions')->selectRaw('IF(visitors = 0, 0, (IFNULL(form_submission_stats.form_submissions, 0) / visitors) * 100) AS form_conversion_rate')->tap(function (Builder $query) { |
| 74 | foreach (Form::get_forms() as $form) { |
| 75 | $column = $form->submissions_column(); |
| 76 | $query->selectRaw("IFNULL(form_submission_stats.{$column}, 0) AS {$column}"); |
| 77 | $query->selectRaw("IF(visitors = 0, 0, (IFNULL(form_submission_stats.{$column}, 0) / visitors) * 100) AS {$form->conversion_rate_column()}"); |
| 78 | } |
| 79 | })->fromSub($countries_query, 'countries')->leftJoinSub($clicks_subquery, 'click_stats', 'click_stats.country_id', '=', 'countries.country_id')->leftJoinSub($orders_subquery, 'order_stats', 'order_stats.country_id', '=', 'countries.country_id')->leftJoinSub($form_submissions_subquery, 'form_submission_stats', 'form_submission_stats.country_id', '=', 'countries.country_id')->leftJoinSub($previous_period_query, 'previous_period_stats', 'previous_period_stats.country_id', '=', 'countries.country_id')->tap(fn(Builder $query) => $this->apply_aggregate_filters($query))->when(!$this->can_order_and_limit_at_record_level() && !($this->using_logical_or_operator() && $this->filtering_by_mixed_columns()), function (Builder $query) { |
| 80 | $query->tap(fn(Builder $query) => $this->apply_order_and_limit($query, $this->sort_configuration->column())); |
| 81 | }); |
| 82 | if ($this->using_logical_or_operator() && $this->filtering_by_mixed_columns()) { |
| 83 | $og_outer_query = $outer_query; |
| 84 | $outer_query = Illuminate_Builder::new()->select('*')->fromSub($og_outer_query, 'records')->tap(fn(Builder $query) => $this->apply_or_filters($query))->tap(fn(Builder $query) => $this->apply_order_and_limit($query, $this->sort_configuration->column())); |
| 85 | } |
| 86 | return $outer_query; |
| 87 | } |
| 88 | } |
| 89 |