Skip to content

Instantly share code, notes, and snippets.

@phillipsharring
Last active January 5, 2017 17:34
Show Gist options
  • Save phillipsharring/36396b49b3dd612846aa517f9e6d734a to your computer and use it in GitHub Desktop.
Save phillipsharring/36396b49b3dd612846aa517f9e6d734a to your computer and use it in GitHub Desktop.
A function swapping back and forth between collections and arrays that I'm sure could be refactored #laravel #collections
@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
}
@phillipsharring
Copy link
Author

This uses Chart.js

@phillipsharring
Copy link
Author

$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
]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment