Laravel 8 from scratch - Notes
It's good to learn the foundation and this is it
It's good to learn the foundation and this is it
title: Post title
slug: post-title
excerpt: Lorem ipsum
date: 2021-05-21
<p> Lorem Ipsum</p>
Parsing
$document = YamlFrontMatter::parseFile(
resource_path('post/post.html')
)
new post
class Post {
public function __construct($title, $excerpt, $date, $body, $slug) {
$this->title = $title;
$this->excerpt = $excerpt;
$this->date = $date;
$this->body = $body;
$this->slug = $slug;
}
}
$post = new Post(
$document->title,
$document->excerpt,
$document->date,
$document->body(),
$document->slug,
);
Problem : If you looping and opening up a new array use array_map.
//Example problem :
foreach ($posts as $post) {
$newpost[] = $post;
}
//Example solution 1
$newpost = array_map(function($file) {
$document = YamlFrontMatter::parseFile(
resource_path('post/post.html')
)
return new Post(
$document->title,
$document->excerpt,
$document->date,
$document->body(),
$document->slug,
);
}
// Example solution 2 - using collection
$newpost = collect($files)
->map(function($file) {
$document = YamlFrontMatter::parseFile(
resource_path($file)
)
return new Post(
$document->title,
$document->excerpt,
$document->date,
$document->body(),
$document->slug,
);
})
public static function all() {
return collect(File::files(resource_path("posts")))
->map(fn($file) => YamlFrontMatter::parseFile($file))
->map(fn($document) => new Post(
$document->title,
$document->excerpt,
$document->date,
$document->body(),
$document->slug,
))
->sortByDesc('date')
)
}
# php artisan tinker
cache()->forget('post.all'); # to forget cache
cache('post.all');
cache()->get('post.all');
cache(['foo' => 'buzz'], now()->addSeconds(3)); # cache for 3 seconds
cache('foo');
# make a components folder called layout
# to call this use <x-layout></x-layout>
# layout.blade.php
<body>
{{ $slot }}
</body>
# post.blade.php
<x-layout>
hello
</x-layout>
$users->pluck('name')
# is the same as
$users->map(function($user) { $user->name; });
// this will ignore manually input id
protected $guarded = ['id'];
DB::listen(function($query){
logger($query->sql, $query->bindings); //Log::info($query);
});
tools : laravel clockwork (debug tools)
With in model
protected $with = ['category', 'author']; // put in model to add it globally
Post::without(['category', 'author'])->first(); // after globally but dont want
New tricks
// eloquent
$currentCategory->is($category); // compare
$category->latest(); // will get the latest
Post::with('category')->get(); // use with to fix n+1 fix
$query->when($filter['search'] ?? false, fn($query, $search) =>
$query->where('title', 'like', '%'.$search.'%')
$query->orWhere('body', 'like', '%'.$search.'%')
); // using when eloquent
Category::firstWhere('slug', request('category'));
// php
if (auth()->user()?->username == 'madindo') {
abort(Response::HTTP_FORBIDDEN);
}
// alpine
<a href="#" x-data="{}" @click.prevent="document.querySelector('#logout-form').submit()">
Log Out</a>
<form id="logout-form" method="POST" action="/logout" class="hidden">
@csrf
</form>
// function
array_filter($numbers, function($number) {
return $number <= self::MAX_NUMBER_ALLOWED;
});
array_filter(
$numbers, fn($number) => $number <= self::MAX_NUMBER_ALLOWED
);
Routes
request()→routeIs(’home’)
$request->only('search') // get only search result using array
Blades
php artisan make:component CategoryDropdown
return view('components.category-dropdown', [
'categories' => Category::all(),
'currentCategory' => Category::firstWhere('slug', request('category')),
]);
<x-category-dropdown />
Foreign key migration
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
Mailchimp adding to the newsletter
$mailchimp = new \MailchimpMarketing\ApiClient();
$mailchimp->setConfig([
'apiKey' => config('services.mailchimp.key'),
'server' => 'us6'
]);
try {
$response = $mailchimp->lists->addListMember('123123', [
'email_address' => request('email'),
'status' => 'subscribed'
])
} catch (\Exception $e) {
throw \Illuminate\Validation\ValidationExeption::withmessages([
'email' => 'This email could not be added to our newsletter
])
}
return redirect('/')->with('success', 'You are now signed up');
Invoke
a common pattern when you’re creating a single-function controller
class NewsletterController extends Controller {
public function __invoke(Newsletter $newsletter) {
...
}
}
Service container
// AppServiceProvider.php
public function register() {
app()->bind(Newsletter::class, function() {
$client = (new ApiClient)->setConfig([
'apiKey' => config('services.mailchimp.key'),
'server' => 'us6'
]);
return new MailChimpNewsletter($client)
});
}
Services/Newsletter.php -> interface
interface Newsletter {
public function subscribe(string $email, string $list = null);
}
//
class MailchimpNewsletter implements Newsletter {
public function __construct(protected ApiClient $client) {
...
}
public function subscribe(string$email, $string $list = null) {
...
}
}
class ConvertKitNewsletter implements Newsletter {
public function subscribe(string $email, string $list = null) {
...
}
}
good example
$tenant = Tenant::findByDomain($request->hostName());
switch ($newsletterProvider = $tenant->newsletter_provider) {
case 'campaign_monitor':
$this->app->register(NewsletterService::class, function () {
return new CampaignMonitorNewsletterService($tenant->createsend_api_key);
});
break;
case 'mailchimp':
$this->app->register(NewsletterService::class, function () {
return new MailchimpNewsletterService(
$tenant->mailchimp_api_key,
$tenant->mailchimp_server_prefix
);
});
break;
default:
throw new InvalidArgumentException(
sprintf('Unsupported newsletter service [%s]', $newsletterProvider)
);
}