-
-
Save phillipsharring/36396b49b3dd612846aa517f9e6d734a to your computer and use it in GitHub Desktop.
@extends('layouts.app') | |
@section('content') | |
<!-- a bunch of other blade/html... --> | |
<!-- placeholder for the chart --> | |
<div class="col-xs-6"> | |
<h3>Technology Focus</h3> | |
<canvas id="myChart2" style="width: 400px; height: 200px;"></canvas> | |
</div> | |
<!-- more blade/html --> | |
@endsection | |
@section('js-foot') | |
<script type="text/javascript"> | |
// other scripts | |
var ctx2 = document.getElementById("myChart2"); | |
// we're using this with chart js | |
var myChart2 = new Chart(ctx2, { | |
type: 'pie', | |
data: { | |
// the keys for $technologyFocus are here, as the labels | |
// this becomes [ "Technology", "Another Technology", "Others Below 7%" ], | |
labels: [ "{!! $technologyFocus->keys()->implode('","') !!}" ], | |
datasets: [ | |
{ | |
// the values for $technologyfocus are here, as the data | |
// this becomes [ 1500, 1489, 400 ], | |
data: [ {{ $technologyFocus->values()->implode(',')}} ], | |
backgroundColor: [ | |
<?php | |
// a lame random RGB color function I found and modified | |
$colors = $technologyFocus->map(function(){ | |
$color = function() { | |
return str_pad( dechex( mt_rand( 0, 255 ) ), 2, '0', STR_PAD_LEFT); | |
}; | |
$rgb = function() use($color) { | |
return $color() . $color() . $color(); | |
}; | |
return '#' . $rgb(); | |
}); | |
echo '"' . $colors->implode('","') . '"'; | |
?> | |
] | |
}] | |
}, | |
options: { | |
scales: { | |
yAxes: [{ | |
ticks: { | |
beginAtZero: true | |
} | |
}] | |
} | |
} | |
}); | |
</script> | |
@endsection |
<?php | |
namespace App\Http\Controllers; | |
use Illuminate\Support\Facades\Auth; | |
use App\Services\ReportService; | |
use App\Models\User; | |
class LearnerProfileController extends Controller | |
{ | |
// route is /learner-profile/{userId} where userId is optional. | |
// we get auth::user if it's null | |
public function index($userId = null) | |
{ | |
$user = (null == $userId) | |
? Auth::user() | |
: User::find($userId); | |
// get the service in ReportService.php | |
$reportService = new ReportService(); | |
// a bunch of other reports grabbed here... | |
$technologyFocus = $reportService->getTechnologyFocus($user->id); | |
return view('learner-profile.index', compact( | |
'user', | |
// the other report results. | |
'technologyFocus' | |
)); | |
} | |
} |
<?php | |
// ReportService.php | |
namespace App\Services; | |
// various use statements go here | |
class ReportService | |
{ | |
// other methods... | |
/** | |
* @param integer $userId | |
* | |
* @return Collection; | |
*/ | |
public function getTechnologyFocus($userId) | |
{ | |
// get all the reported events from reporting table | |
$views = Report::where('report', 'content-titles-viewed') | |
->where('user_id', $userId) | |
->get(); | |
// reportable_type & reportable_id are a polymorphic relationship | |
// reportable_id in this case is a Catalog_title id (yes, the model naming is messed up) | |
$titleIds = $views->pluck('reportable_id')->unique(); | |
// query for the technology names and counts | |
$technologies = Catalog_titles_lov_product_technologies::select(DB::raw('COUNT(*) AS `total`'), 'lov_product_technologies.name') | |
->join('lov_product_technologies', 'catalog_titles_lov_product_technologies.lov_product_technology_id', '=', 'lov_product_technologies.id') | |
->whereIn('catalog_titles_lov_product_technologies.catalog_title_id', $titleIds->toArray()) | |
->where('lov_product_technologies.name', '!=', '') | |
->whereNotNull('lov_product_technologies.name') | |
->groupBy('lov_product_technologies.name') | |
->orderBy('total', 'DESC') | |
->get(); | |
$percentage = 7; | |
$total = $technologies->sum('total'); | |
$threshold = floor($total * ($percentage * .01)); | |
// get counts above the threshold | |
$counts = $technologies->filter(function($item) use ($threshold) | |
{ | |
return ($threshold < $item['total']); | |
})->toArray(); | |
// right above here ^^^ I'm making this into an array because | |
// a) I don't need all of the Report objects, just selected values | |
// b) I want to append to it later | |
// find all the "others" below the threshold, then sum them to a single number | |
$othersTotal = $technologies->filter(function($item) use ($threshold) | |
{ | |
return ($threshold >= $item['total']); | |
})->reduce(function($carry, $item) | |
{ | |
return $carry + $item['total']; | |
}); | |
// append the "others" count to the $counts array | |
$counts[] = [ | |
'total' => $othersTotal, | |
'name' => 'Others (Below ' . $percentage . '%)', | |
]; | |
$result = []; | |
// make the result a key => value array (name => total) | |
collect($counts)->map(function($item) use (&$result) | |
{ | |
$result[$item['name']] = $item['total']; | |
}); | |
// this too ^^^ seems like something that could be done more smoothly. | |
// is there a better way to make $counts into a key => value array? | |
/* | |
// output | |
// $result is like this now... | |
[ | |
"Technology" => 1500, | |
"Another Technology" => 1489, | |
// ... etc. | |
"Others Below 7%" => 400, | |
]; | |
// */ | |
return collect($result); | |
} | |
// other methods | |
} |
$technologies query output
Collection {#2916 ▼
#items: array:28 [▼
0 => Catalog_titles_lov_product_technologies {#2915 ▼
#table: "catalog_titles_lov_product_technologies"
#connection: null
#primaryKey: "id"
#keyType: "int"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:2 [▼
"total" => 472
"name" => "Technology 1"
]
#original: array:2 [▶]
#relations: []
#hidden: []
#visible: []
#appends: []
#fillable: []
#guarded: array:1 [▶]
#dates: []
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
+exists: true
+wasRecentlyCreated: false
}
1 => Catalog_titles_lov_product_technologies {#2914 ▶}
2 => Catalog_titles_lov_product_technologies {#2913 ▶}
etc.
$result should be something like
Collection {#2947 ▼
#items: array:5 [▼
"Technology 1" => 472
"Technology 2" => 438
"Another Technology" => 249
"Yet Another Technology" => 232
"Others (Below 7%)" => 1407
]
}
This uses Chart.js