Project Structure
Understanding the ApnaPHP project structure will help you organize your application effectively. The boilerplate comes with everything pre-configured!
Directory Structure
my-app/
├── app/ # Application files (Next.js App Router style)
│ └── page.apna.php # Your main page (like Next.js pages)
├── config/ # Configuration files (pre-configured)
│ ├── app.php # App configuration
│ └── database.php # Multi-database configuration
├── models/ # Your models directory
│ └── User.php # Sample User model with auto-migration
├── public/ # Public assets and entry point
│ ├── index.php # Main entry point (handles all requests)
│ ├── apnaphp.png # Framework logo
│ ├── file.svg # Sample icons
│ ├── globe.svg
│ └── window.svg
├── storage/ # Application storage (organized)
│ ├── cache/ # Cache files
│ │ └── views/
│ ├── database/ # SQLite database files
│ ├── logs/ # Log files
│ │ └── console.log
│ └── uploads/ # User uploaded files
├── vendor/ # Composer dependencies (framework auto-installed)
├── .env.example # Environment variables template
├── apna # CLI executable
├── composer.json # Dependencies (everything included)
├── LICENSE # MIT License
└── README.md # Project documentation
File Types
Pages (page.apna.php)
Regular pages that render HTML content:
<?php
// app/page.apna.php
metadata([
'title' => 'Welcome to ApnaPHP',
'description' => 'Your first ApnaPHP page'
]);
?>
<h1>Hello, ApnaPHP!</h1>
<p>Welcome to your first ApnaPHP application.</p>
API Routes (route.apna.php)
API endpoints that return JSON responses:
<?php
// app/api/users/route.apna.php
use ApnaPHP\Routing\Request;
use ApnaPHP\Routing\Response;
class UsersHandler
{
public function GET(Request $request)
{
$users = User::all();
return Response::json(['users' => $users]);
}
public function POST(Request $request)
{
$user = User::create($request->all());
return Response::json($user, 201);
}
}
Models (models/User.php)
Eloquent-inspired models with auto-migration:
<?php
namespace App\Models;
use ApnaPHP\Database\Model;
class User extends Model
{
protected string $table = 'users';
protected bool $autoMigrate = true; // ✅ Auto-creates table on first use
protected array $schema = [
'name' => 'required|type:string|length:255',
'email' => 'required|unique|type:string|length:255',
'phone' => 'required|unique|type:string|length:20',
'password' => 'required|type:string',
'role' => 'type:string|default:user|length:50',
'status' => 'type:string|default:active|length:50',
];
protected array $fillable = [
'name', 'email', 'password', 'phone', 'role', 'status'
];
protected array $hidden = ['password'];
}
File Types
Pages (page.apna.php)
Regular pages that render HTML content:
<?php
// app/page.apna.php - Home page (/)
metadata([
'title' => 'Welcome',
'description' => 'Welcome to our site'
]);
?>
<h1>Welcome to ApnaPHP</h1>
<p>This is the home page.</p>
API Routes (route.apna.php)
API endpoints that return JSON or other data:
<?php
// app/api/users/route.apna.php - /api/users endpoint
class UsersAPI {
public function GET() {
return json([
'users' => [
['id' => 1, 'name' => 'John Doe'],
['id' => 2, 'name' => 'Jane Smith']
]
]);
}
public function POST() {
$data = request()->json();
// Create user logic here
return json(['message' => 'User created successfully'], 201);
}
}
Layouts (layout.apna.php)
Layout files that wrap pages:
<?php
// app/layout.apna.php - Root layout
metadata([
'title' => 'My App',
'description' => 'My ApnaPHP Application'
]);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= metadata('title') ?></title>
<meta name="description" content="<?= metadata('description') ?>">
</head>
<body>
<header>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<main>
<?= $content ?? '' ?>
</main>
<footer>
<p>© 2024 My App</p>
</footer>
</body>
</html>
Middleware (middleware.apna.php)
Middleware files that run before page rendering:
<?php
// app/middleware.apna.php - Global middleware
// Check authentication
if (!auth()->check() && request()->path() !== '/login') {
return redirect('/login');
}
// Add security headers
response()->headers([
'X-Frame-Options' => 'DENY',
'X-XSS-Protection' => '1; mode=block'
]);
Error Pages
404 Page (not-found.apna.php)
<?php
// app/not-found.apna.php
metadata([
'title' => 'Page Not Found'
]);
?>
<h1>404 - Page Not Found</h1>
<p>The page you're looking for doesn't exist.</p>
<a href="/">Go Home</a>
500 Page (500.apna.php)
<?php
// app/500.apna.php
metadata([
'title' => 'Server Error'
]);
?>
<h1>500 - Server Error</h1>
<p>Something went wrong on our end.</p>
Dynamic Routes
Single Parameter
<?php
// app/blog/[slug]/page.apna.php
$slug = request()->param('slug');
$post = Post::where('slug', $slug)->first();
if (!$post) {
return notFound();
}
metadata([
'title' => $post->title,
'description' => $post->excerpt
]);
?>
<h1><?= htmlspecialchars($post->title) ?></h1>
<div><?= $post->content ?></div>
Multiple Parameters
<?php
// app/blog/[year]/[month]/[slug]/page.apna.php
$year = request()->param('year');
$month = request()->param('month');
$slug = request()->param('slug');
$post = Post::where('year', $year)
->where('month', $month)
->where('slug', $slug)
->first();
?>
Catch-All Routes
<?php
// app/docs/[...slug]/page.apna.php
$segments = request()->params();
$docPath = implode('/', $segments);
// Load documentation page
$content = loadDocContent($docPath);
?>
Route Groups
Route groups allow you to organize related routes without affecting the URL:
app/
├── (admin)/
│ ├── dashboard/
│ │ └── page.apna.php # /dashboard (not /admin/dashboard)
│ └── users/
│ └── page.apna.php # /users (not /admin/users)
└── (public)/
├── about/
│ └── page.apna.php # /about
└── contact/
└── page.apna.php # /contact
Configuration Files
Application Config (config/app.php)
<?php
return [
'name' => env('APP_NAME', 'ApnaPHP Application'),
'url' => env('APP_URL', 'http://localhost:3000'),
'env' => env('APP_ENV', 'production'),
'debug' => env('APP_DEBUG', false),
'timezone' => 'UTC',
];
Database Config (config/database.php)
<?php
return [
'default' => env('DB_DRIVER', 'mysql'),
'connections' => [
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
// ... other database settings
],
],
];
Storage Directories
Logs (storage/logs/)
Application logs are stored here:
storage/logs/
├── apnaphp.log # Main application log
├── error.log # Error log
└── access.log # Access log
Cache (storage/cache/)
Temporary cache files:
storage/cache/
├── views/ # Compiled views
├── routes/ # Route cache
└── config/ # Config cache
Uploads (storage/uploads/)
User uploaded files:
storage/uploads/
├── images/ # Image uploads
├── documents/ # Document uploads
└── avatars/ # User avatars
Best Practices
File Organization
- Keep related files together - Group pages, layouts, and middleware by feature
- Use descriptive names - Make file names clear and meaningful
- Follow conventions - Use the
.apna.phpextension consistently - Separate concerns - Keep business logic in separate classes when possible
Directory Structure Tips
- Flat structure for simple apps - Don't over-nest directories
- Group by feature - Organize by business logic, not technical concerns
- Consistent naming - Use kebab-case for directories, camelCase for files
- Public assets - Keep static files in the
public/directory
Environment Management
- Use
.envfiles - Store environment-specific configuration - Never commit secrets - Add
.envto.gitignore - Provide examples - Include
.env.examplefor other developers - Validate configuration - Check required environment variables on startup
