Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/reinink/wants
Source code for my example app used in my Laracon Online 2020 talk
https://github.com/reinink/wants
Last synced: 17 days ago
JSON representation
Source code for my example app used in my Laracon Online 2020 talk
- Host: GitHub
- URL: https://github.com/reinink/wants
- Owner: reinink
- Created: 2020-02-22T15:32:30.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2021-05-11T13:43:25.000Z (over 3 years ago)
- Last Synced: 2024-10-14T20:29:00.316Z (30 days ago)
- Language: PHP
- Homepage: https://laracon.net
- Size: 852 KB
- Stars: 187
- Watchers: 7
- Forks: 38
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Wants
Source code for my example app used in my [Laracon Online](https://laracon.net) 2020 talk.
![](https://raw.githubusercontent.com/reinink/wants/master/screenshot.png)
## Database Schema
- `users`
- `categories`
- `wants`
- `comments`
- `votes`## Install the Laravel Debugbar
- `composer require barryvdh/laravel-debugbar --dev`
- Set `APP_DEBUG=true` in `.env`
- `php artisan vendor:publish` (9)
- Enable `models` in `config/debugbar.php`
- *Goals*
1. Minimize database queries.
2. Minimize hydrated models.
3. Minimize memory usage.## Requirement 1: Show status totals on dashboard
Update `views/wants.blade.php`:
```html
Requested
10
Planned
10
Completed
10
```Update `Controllers/WantsController.php`
```php
$wants = Want::all();
$statuses = (object) [];
$statuses->requested = $wants->where('status', 'Requested')->count();
$statuses->planned = $wants->where('status', 'Planned')->count();
$statuses->completed = $wants->where('status', 'Completed')->count();return View::make('wants', [
'statuses' => $statuses,
'wants' => $wants,
]);
```Update `views/wants.blade.php`:
```php
{{ $statuses->requested }}
{{ $statuses->planned }}
{{ $statuses->completed }}
```Update `Controllers/WantsController.php`
```php
$statuses = (object) [];
$statuses->requested = Want::where('status', 'Requested')->count();
$statuses->planned = Want::where('status', 'Planned')->count();
$statuses->completed = Want::where('status', 'Completed')->count();
```Update `Controllers/WantsController.php`
```php
$statuses = Want::getQuery()
->selectRaw("count(case when status = 'Requested' then 1 end) as requested")
->selectRaw("count(case when status = 'Planned' then 1 end) as planned")
->selectRaw("count(case when status = 'Completed' then 1 end) as completed")
->first();
```## Requirement 2: Add comments links and author label
Update `app/Comment.php`
```php
public function url()
{
return $this->want->url().'#comment-'.$this->id;
}
```Update `views/want.blade.php`:
```html
{{ $comment->created_at->format('M j, Y \a\t g:i a') }}
```Update `Controllers/WantsController.php`
```php
$want->load(['comments' => function ($query) {
$query->with('user', 'want');
}]);
```*Notes:*
- Still making two unnecessary database queries (`Want` and `Want::category()`).
- Let's amplify this problem.Update `views/wants.blade.php`
```html
@if ($comment->isAuthor())
Author
@endif
```Update `app/Comment.php`
```php
public function isAuthor()
{
return $this->want
->comments
->sortBy('created_at')
->first()
->user
->is($this->user);
}
```*What we have:*
- want
- category `(to show at the top)`
- comments `(to list the comments)`
- user `(to show the comment user)`
- **want**
- category `(for the link)`
- comments `(to determine first comment)`
- user `(to get the author)`
*What we want:*
- want
- category
- comments
- userUpdate `Controllers/WantsController.php`
```php
$want->load('comments.user');
$want->comments->each->setRelation('want', $want);
```*Notes:*
- What we're doing is optimizing in the perimeter of our app.
- Let's look at one last example.Update `Controllers/WantsController.php`
```php
$want->load('comments.user:id,name,photo');
```## Requirement 3: Add last comment to dashboard
Update `views/wants.blade.php`
```html
```
```html
Jonathan Reinink
Feb 22, 2020 at 3:52 pm
```
Update `app/Want.php`
```php
public function getLastCommentAttribute()
{
return $this->comments->sortByDesc('created_at')->first();
}
```Update `views/wants.blade.php`
```php
{{ $want->lastComment->user->photo }}
{{ $want->lastComment->user->name }}
{{ $want->lastComment->created_at->format('M j, Y \a\t g:i a') }}
```Update `Controllers/WantsController.php`
```php
$wants = Want::query()
->with('category', 'comments.user')
```*Notes:*
- We're now loading a TON of data.
- We're also loading too many users.
- And this problem becomes much worse if we show more than 15 results per page.
- Try `->paginate(100)`Update `app/Want.php`
```php
public function lastComment()
{
return $this->belongsTo(Comment::class);
}
```*Notes:*
- But `wants.last_comment_id` does not exist.
- How can we make this relationship work?```php
public function scopeWithLastCommentId($query)
{
$query->addSelect(['last_comment_id' => Comment::select('id')
->whereColumn('comments.want_id', 'wants.id')
->latest()
->take(1),
]);
}
```Update `Controllers/WantsController.php`
```php
$wants = Want::query()
->with('category', 'lastComment.user')
```Update `Controllers/WantsController.php`
```php
$wants = Want::query()
->withLastCommentId()
```Update `app/Want.php`
```php
protected static function boot()
{
parent::boot();static::addGlobalScope('with_last_comment_id', function ($query) {
$query->withLastCommentId();
});
}
```Update `Controllers/WantsController.php`
```php
$wants = Want::query()
->with('category', 'lastComment.user')
```## Requirement 4: Add column sorting to dashboard
Update `Controllers/WantsController.php`
```php
->when(Request::input('sort'), function ($query, $sort) {
switch ($sort) {
case 'category': return $query->orderByCategory();
case 'last_comment': return $query->orderByLastCommentDate();
case 'status': return $query->orderByStatus();
case 'activity': return $query->orderByActivity();
}
})
```Update `app/Want.php`
```php
public function scopeOrderByCategory($query)
{
}public function scopeOrderByLastCommentDate($query)
{
}public function scopeOrderByStatus($query)
{
}public function scopeOrderByActivity($query)
{
}
```Update `app/Want.php`
```php
public function scopeOrderByCategory($query)
{
$query->orderBy(
Category::select('name')
->whereColumn('categories.id', 'wants.category_id')
);
}
```Update `app/Want.php`
```php
public function scopeOrderByLastCommentDate($query)
{
$query->orderByDesc(
Comment::select('created_at')
->whereColumn('comments.want_id', 'wants.id')
->latest()
->take(1)
);
}
```Update `app/Want.php`
```php
public function scopeOrderByStatus($query)
{
$query->orderByDesc('status');
}
```Update `app/Want.php`
```php
public function scopeOrderByStatus($query)
{
$query->orderByRaw("
case
when status = 'Requested' then 1
when status = 'Planned' then 2
when status = 'Completed' then 3
end
");
}
```Update `app/Want.php`
```php
public function scopeOrderByActivity($query)
{
$votes = Vote::selectRaw('count(*)')
->whereColumn('votes.want_id', 'wants.id')
->toSql();$comments = Comment::selectRaw('count(*)')
->whereColumn('comments.want_id', 'wants.id')
->toSql();$query->orderByRaw("($votes) + (($comments) * 2) desc");
}
```*Notes:*
- Test it using by adding it as a column:```php
$query->selectRaw("($votes) + (($comments) * 2) as activity");
```