| Topic | Snippet |
|---|---|
|
Create Project
If inside Docker/Devilbox, run composer inside the php container to match PHP version.
|
composer create-project laravel/laravel myapp cd myapp |
|
Run Dev Server (local)
In Docker/Devilbox you usually browse via vhost instead.
|
php artisan serve |
|
Environment (.env)
Fixes “No application encryption key has been specified.”
|
cp .env.example .env php artisan key:generate |
|
Caches (common fix)
If routes/config/views behaving oddly.
|
php artisan optimize:clear php artisan config:clear php artisan route:clear php artisan view:clear |
|
Migrations
Use migrate:fresh on dev only (drops tables).
|
php artisan migrate php artisan migrate:fresh --seed |
|
Seeder
Run a specific seeder class.
|
php artisan db:seed php artisan db:seed --class=UserSeeder |
|
Tinker
Interactive REPL. Great for quick checks.
|
php artisan tinker |
|
Queue
For async jobs; configure queue driver in .env
|
php artisan queue:work php artisan queue:listen |
|
Storage link
Needed when serving user files from storage/app/public.
|
php artisan storage:link |
|
Logs
In Devilbox run in container or map volume.
|
tail -f storage/logs/laravel.log |
|
Common permissions fix
Exact user depends on container. In Devilbox often “devilbox” user owns files.
|
chmod -R ug+rw storage bootstrap/cache # If needed: chown -R www-data:www-data storage bootstrap/cache |
| Topic | Snippet |
|---|---|
|
Routes
Remember api routes are typically stateless + prefixed /api.
|
// routes/web.php
Route::get('/dashboard', fn() => view('dashboard'));
// routes/api.php
Route::get('/status', fn() => ['ok'=>true]); |
|
Controller
Use resource controllers for CRUD.
|
php artisan make:controller UserController
// web.php
Route::get('/users', [UserController::class, 'index']); |
|
Form Request Validation
Keeps validation clean.
|
php artisan make:request StoreUserRequest
public function rules(): array {
return ['email'=>'required|email'];
}
public function store(StoreUserRequest ){
= ();
} |
|
Eloquent basics
Use fillable/guarded properly.
|
User::query()->where('active',1)->latest()->paginate(25);
User::create([...]);
([...]);
(); |
|
Relationships
Eager load with with(): User::with('posts')->get().
|
class User extends Model {
public function posts(){ return $this->hasMany(Post::class); }
}
$user->posts()->create([...]); |
| Topic | Snippet |
|---|---|
|
Laravel Mix (older Laravel 5/6/7)
Creates public/mix-manifest.json. Missing file = you haven’t built assets.
|
npm install npm run dev # or npm run production |
|
Vite (Laravel 9/10/11)
Vite uses /public/build/manifest.json.
|
npm install npm run dev # build npm run build |
|
If node deps missing
Useful if weird webpack/mix errors.
|
rm -rf node_modules package-lock.json npm cache clean --force npm install |
|
OpenSSL legacy (older webpack)
Sometimes needed with older build tooling.
|
export NODE_OPTIONS=--openssl-legacy-provider npm run dev |
| Topic | Snippet |
|---|---|
|
Vue 3 component (SFC)
Script setup is the cleanest modern pattern.
|
<script setup>
import { ref, computed, onMounted } from 'vue'
const count = ref(0)
const doubled = computed(() => count.value * 2)
onMounted(() => console.log('mounted'))
</script>
<template>
<button @click="count++">Count: {{ count }} ({{ doubled }})</button>
</template> |
|
Props + Emits
Keeps components predictable.
|
<script setup>
const props = defineProps({ name: String })
const emit = defineEmits(['save'])
</script>
<template>
<button @click="emit('save')">Save {{ name }}</button>
</template> |
|
API calls (fetch)
Add error handling + abort controllers for production.
|
const loading = ref(false)
const data = ref(null)
async function load(){
loading.value = true
try {
const res = await fetch('/api/status')
data.value = await res.json()
} finally {
loading.value = false
}
} |
|
Vue Router (conceptual)
In SPAs you’ll typically serve the same Laravel view + router handles routes.
|
const routes = [
{ path: '/', component: Home },
{ path: '/users', component: Users }
] |
| Topic | Snippet |
|---|---|
|
Create component
Creates class + blade view.
|
php artisan make:livewire UsersTable |
|
Basic component (class)
For large tables use pagination + debounced search.
|
use Livewire\Component;
class UsersTable extends Component
{
public string $search = '';
public function render(){
$users = User::query()
->when($this->search, fn($q)=>$q->where('name','like','%'.$this->search.'%'))
->limit(50)->get();
return view('livewire.users-table', compact('users'));
}
} |
|
Blade view
wire:model binds state, debounce reduces requests.
|
<div>
<input type="text" wire:model.debounce.300ms="search" placeholder="Search..." />
<ul>
@foreach($users as $u)
<li>{{ $u->name }}</li>
@endforeach
</ul>
</div> |
|
Actions
Use authorisation + confirm dialogs.
|
<button wire:click="delete({{ $u->id }})">Delete</button>
public function delete(int $id){
User::whereKey($id)->delete();
} |
|
Validation
Great for “live” form validation.
|
protected $rules = ['search' => 'max:50'];
public function updated($field){
$this->validateOnly($field);
} |
| Topic | Snippet |
|---|---|
|
Include (CDN)
For production you might bundle instead.
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> |
|
Grid
Use g-* for spacing.
|
<div class="container">
<div class="row g-3">
<div class="col-12 col-md-6">Left</div>
<div class="col-12 col-md-6">Right</div>
</div>
</div> |
|
Form validation (client-side)
Works nicely with Livewire/Vue too (but avoid double-validation confusion).
|
<form class="needs-validation" novalidate>
<input class="form-control" required>
<div class="invalid-feedback">Required</div>
</form>
<script>
(() => {
const forms = document.querySelectorAll('.needs-validation')
Array.from(forms).forEach(form => {
form.addEventListener('submit', e => {
if (!form.checkValidity()) { e.preventDefault(); e.stopPropagation(); }
form.classList.add('was-validated')
}, false)
})
})()
</script> |
|
Modal (quick)
For Livewire, sometimes use wire:ignore on complex JS components.
|
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#m">Open</button> <div class="modal fade" id="m" tabindex="-1"> <div class="modal-dialog"><div class="modal-content"> <div class="modal-header"><h5 class="modal-title">Title</h5></div> <div class="modal-body">Body</div> </div></div> </div> |
| Topic | Snippet |
|---|---|
|
Clone / Fetch / Pull (safe defaults)
Use --ff-only to avoid accidental merge commits when pulling.
|
git clone <repo> cd <repo> git fetch --all --prune git pull --ff-only |
|
Hard reset to remote (nukes local changes)
Danger: deletes uncommitted changes and untracked files. Great for broken working trees.
|
git fetch --all --prune git reset --hard origin/master git clean -fd |
|
Create branch + push upstream
The -u flag sets upstream so future git push/pull works without specifying branch.
|
git checkout -b feature/my-change # edit files git add -A git commit -m "Explain change" git push -u origin feature/my-change |
|
Stash (quick context switch)
If stash pop conflicts, resolve then commit.
|
git status git stash push -m "WIP: before switching" # switch branch # later... git stash list git stash pop |
|
Undo last commit (keep changes)
Soft reset is great if you committed too early or with the wrong message.
|
git reset --soft HEAD~1 # changes remain staged # or keep changes unstaged: git reset HEAD~1 |
| Topic | Snippet |
|---|---|
|
Project structure
Devilbox expects an htdocs directory per project.
|
~/projects/MyApp/ htdocs -> should point to /public for Laravel .devilbox/ (optional configs) |
|
Fix missing htdocs for Laravel
If you get “Missing htdocs directory”, recreate and symlink to public.
|
cd ~/projects/MyApp rm -rf htdocs ln -s public htdocs |
|
If symlink permission denied (WSL/Windows mount)
WSL2 + Windows mounts can block symlinks. Prefer Linux path for dev projects.
|
rm -rf htdocs mkdir -p htdocs # fallback: copy (not ideal) rsync -a public/ htdocs/ # Better: keep projects inside Linux filesystem (e.g. /home/you/projects) |
|
Exec into PHP container
Run composer/npm/artisan inside container for correct PHP/node libs.
|
cd ~/code/devilbox docker compose exec php bash |
|
Run composer install inside Devilbox
Use -lc to ensure shell env loads and commands run with login shell.
|
docker compose exec php bash -lc 'cd /shared/httpd/MyApp && composer install' |
|
Run npm in Devilbox
Some setups use a separate node container; adjust if your Devilbox has one.
|
docker compose exec php bash -lc 'cd /shared/httpd/MyApp && npm install && npm run dev' |
|
Common Laravel permissions (Devilbox)
If logs can’t be written, fix ownership/permissions.
|
docker compose exec php bash -lc ' cd /shared/httpd/MyApp chmod -R ug+rw storage bootstrap/cache || true ' |
|
Missing htdocs directory in
How to fix: Missing htdocs directory in:XXX
|
cd ~/projects/XXX <--- XXX is the project folders name mkdir -p htdocs rm -rf htdocs/* ln -s ../public htdocs/public cd ~/code/devilbox docker compose restart httpd |
| Topic | Snippet |
|---|---|
|
Connect (local + docker service)
In Devilbox, DB host often equals the service name (mysql).
|
mysql -h localhost -u root -p # in docker networks (service name): mysql -h mysql -P 3306 -u root -p |
|
Create DB + user (basic)
For local dev you can keep root/no-pass depending on setup, but users are cleaner.
|
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'myapp'@'%' IDENTIFIED BY 'strongpassword'; GRANT ALL PRIVILEGES ON myapp.* TO 'myapp'@'%'; FLUSH PRIVILEGES; |
|
Quick inspect: tables + size
Great for spotting runaway logs/session tables.
|
SHOW TABLES;
SELECT table_name,
ROUND((data_length+index_length)/1024/1024,2) AS size_mb
FROM information_schema.TABLES
WHERE table_schema = DATABASE()
ORDER BY size_mb DESC; |
|
Dump / restore (fast dev migrations)
If restore fails on FK order, temporarily disable checks during import.
|
# dump mysqldump -h mysql -u root -p myapp > myapp.sql # restore mysql -h mysql -u root -p myapp < myapp.sql |
|
FK checks (use carefully)
Use for dev resets/imports. Avoid in production workflows.
|
SET FOREIGN_KEY_CHECKS=0; -- import / delete / reseed SET FOREIGN_KEY_CHECKS=1; |
| Topic | Snippet |
|---|---|
|
Containers
List running / all containers.
|
docker ps docker ps -a |
|
Logs
Follow logs to catch errors.
|
docker logs -f <container> |
|
Exec shell
Most day-to-day debugging starts here.
|
docker exec -it <container> bash # or sh if alpine |
|
Compose up/down
Bring environment up/down.
|
docker compose up -d docker compose down |
|
Rebuild after Dockerfile changes
Use when dependencies change.
|
docker compose build --no-cache docker compose up -d |
|
Prune (careful)
Frees space; volumes removal can delete DB data.
|
docker system df docker system prune -f # remove volumes too (careful): docker system prune --volumes -f |
|
Networks
Useful for “can’t connect to mysql/redis” issues.
|
docker network ls docker network inspect <name> |
| Topic | Snippet |
|---|---|
|
Find what is using a port
Useful when Vite/Node/NGINX won’t start due to port already in use.
|
sudo lsof -i :80 sudo lsof -i :5173 # or: sudo ss -lntp | grep -E ':80|:5173' |
|
Fix Laravel write permissions (generic)
Container user may differ. In Devilbox often files are owned by devilbox user.
|
chmod -R ug+rw storage bootstrap/cache # if ownership is wrong: chown -R www-data:www-data storage bootstrap/cache |
|
Symlink issues on Windows mounts (WSL)
If you see 'Permission denied' on ln -s, move project into WSL filesystem.
|
# Prefer projects in Linux FS: # /home/<you>/projects instead of /mnt/c/... # If you must use /mnt/c, symlinks may fail depending on Windows policy. |
|
Quick disk usage + largest folders
Handy for Docker eating disk space.
|
df -h # largest directories: du -h --max-depth=1 | sort -hr | head -n 20 |
|
Edit / open from terminal
If VS Code + WSL has permission issues, ensure you’re using the WSL extension + not mixing elevated Windows VS Code.
|
code . code path/to/file.php # nano fallback: nano path/to/file.php |
| Topic | Snippet |
|---|---|
|
Composer install/update
Install uses composer.lock; update changes it.
|
composer install composer update composer dump-autoload |
|
Platform/PHP version mismatch
Better solution: run composer in container with correct PHP.
|
php -v composer why-not php 8.2 # If you MUST (not ideal): composer install --ignore-platform-req=php |
|
NPM basics
Build assets for Mix/Vite.
|
node -v npm -v npm install npm run dev npm run build |
|
Git hard reset to remote
Wipes local uncommitted changes.
|
git fetch --all git reset --hard origin/master git clean -fd |
| Topic | Snippet |
|---|---|
|
Run tests (PHPUnit)
artisan test uses Laravel’s runner; both work.
|
php artisan test # or: ./vendor/bin/phpunit |
|
Create a test
Feature tests hit HTTP + DB. Unit tests are smaller and faster.
|
php artisan make:test UserApiTest # feature test by default php artisan make:test UserModelTest --unit |
|
Database reset between tests
RefreshDatabase migrates and wraps tests to keep a clean DB state.
|
use Illuminate\Foundation\Testing\RefreshDatabase;
class UserApiTest extends TestCase
{
use RefreshDatabase;
} |
|
Example HTTP test (Laravel)
Great sanity test when wiring a SPA to an API.
|
public function test_status_endpoint_returns_ok(): void
{
$this->getJson('/api/status')
->assertOk()
->assertJson(['ok' => true]);
} |
|
Factories + seeding in tests
Factories are the best way to generate realistic data fast.
|
use App\Models\User;
public function test_user_can_be_created(): void
{
$user = User::factory()->create();
$this->assertNotNull($user->id);
} |
| Topic | Snippet |
|---|---|
|
.env sanity (DB)
In docker/Devilbox the host is often the service name (e.g. mysql).
|
DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=your_db DB_USERNAME=root DB_PASSWORD= |
|
CORS (API)
If SPA can’t call API, check CORS + cookies/sanctum.
|
# config/cors.php # or middleware # Debug quickly: curl -i https://yourhost/api/status |
|
PHP info quick check
Confirm loaded extensions, INI, upload limits. Remove afterwards.
|
<?php phpinfo(); |
|
Upload limits
Set in php.ini or container config, then restart.
|
upload_max_filesize=50M post_max_size=50M max_execution_time=120 |
|
Host File Location
Modify the host file on windows
|
"C:\Windows\System32\drivers\etc\hosts" |
| Topic | Snippet |
|---|---|
|
Generate APP_KEY + clear caches
Fixes encryption/session issues and clears stale config/routes/views.
|
php artisan key:generate php artisan optimize:clear |
|
CSRF token (Blade) + AJAX header
If you see 419 Page Expired, it’s almost always CSRF/session mismatch.
|
@csrf
// JS (axios/fetch) include X-CSRF-TOKEN
// meta tag:
<meta name="csrf-token" content="{{ csrf_token() }}"> |
|
Rate limiting (routes)
Stops brute force. Tune per route and include username/email key if needed.
|
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Cache\RateLimiting\Limit;
RateLimiter::for('login', function ($request) {
return Limit::perMinute(10)->by($request->ip());
});
Route::post('/login', ...)->middleware('throttle:login'); |
|
Password hashing (never store plain)
Laravel uses bcrypt/argon depending on config. Always Hash::make().
|
use Illuminate\Support\Facades\Hash;
$hash = Hash::make($password);
if (Hash::check($password, $hash)) {
// ok
} |
|
Secure .env + config caching
Caching boosts performance but remember to clear when env/config changes.
|
# Never expose .env in web root. # For prod: php artisan config:cache php artisan route:cache php artisan view:cache |
| Topic | Snippet |
|---|---|
|
Tail Laravel logs
If logs won’t write: fix storage permissions/ownership.
|
tail -f storage/logs/laravel.log # if daily logs: ls -la storage/logs/ |
|
Enable query logging (quick dev)
Use in local only; this can be noisy and slow on big traffic.
|
DB::listen(function ($query) {
logger()->info('SQL', [
'sql' => $query->sql,
'bindings' => $query->bindings,
'time_ms' => $query->time,
]);
}); |
|
Common “it’s broken” reset
Clears stale cached bootstrap artifacts and refreshes autoload.
|
php artisan optimize:clear rm -rf bootstrap/cache/*.php composer dump-autoload |
|
Slow page checklist
Most real-world slowness is N+1 queries or missing DB indexes.
|
- Check N+1: use ->with() - Add indexes to WHERE/JOIN columns - Cache expensive results - Queue slow jobs - Profile SQL timings |
|
PHP limits and timeouts
If large imports fail: increase memory/time + web server timeouts.
|
php -i | grep -E "memory_limit|max_execution_time|upload_max_filesize|post_max_size" # typical: memory_limit=512M max_execution_time=120 |
| Topic | Snippet |
|---|---|
|
Laravel deploy basics (safe order)
Avoid caching before .env changes are final. Use --force for migrations in prod.
|
composer install --no-dev --optimize-autoloader php artisan migrate --force php artisan optimize php artisan config:cache php artisan route:cache php artisan view:cache |
|
Nginx root for Laravel
Root must point to /public, not project root.
|
server {
root /var/www/myapp/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
} |
|
Certbot quick renew check
Dry-run confirms renew works before expiry.
|
sudo certbot certificates sudo certbot renew --dry-run |
|
Force HTTPS redirect (Nginx idea)
Best handled at the web server level rather than inside Laravel.
|
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
} |
|
Reload services
Always run nginx -t before reload to avoid taking the site down.
|
sudo nginx -t && sudo systemctl reload nginx sudo systemctl restart php8.3-fpm sudo systemctl status nginx --no-pager |
| Topic | Snippet |
|---|---|
|
cURL basics (GET/POST JSON)
Add -H "Accept: application/json" for Laravel API responses.
|
curl -i https://example.com/api/status
curl -i -X POST https://example.com/api/login \
-H "Content-Type: application/json" \
-d '{"email":"a@b.com","password":"secret"}' |
|
Pagination (Laravel API)
Laravel returns meta/links automatically for paginate().
|
return User::query()
->orderByDesc('id')
->paginate(25); |
|
API Resource wrapper
Keeps API responses stable even if DB schema changes.
|
php artisan make:resource UserResource return UserResource::collection( User::paginate(25) ); |
|
API auth header example
Use Bearer tokens or cookie-based auth (Sanctum) depending on setup.
|
curl -i https://example.com/api/me \ -H "Authorization: Bearer <token>" \ -H "Accept: application/json" |
|
HTTP status codes cheat
In Laravel validation errors commonly return 422 for JSON requests.
|
200 OK 201 Created 204 No Content 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 422 Validation Error 429 Too Many Requests 500 Server Error |