Skip to content

CRUD Operations in Slim Framework

CRUD is an acronym for Create, Read, Update, and Delete. It is a set of operations that are used to manage data in a database.

This guide walks you through creating a new resource with complete CRUD operations in your Slim MVC application.

  • Familiar with MVC pattern and the provided Slim Skeleton Project-
  • Understand the BaseController methods (render() and redirect())
  • Understand the BaseModel methods
  • Familiar with PSR-7 Request/Response objects

  1. Create a new controller class in app/Controllers/ (if it doesn’t exist)
  2. Name it using PascalCase with “Controller” suffix (e.g., ProductController.php)
  3. Extend BaseController and add constructor with proper parent call
  4. Implement these standard callback methods:
    • index() → Display a list of items (GET request).
    • show() → Show details of a single item (GET request).
    • create() → Display a form to create a new item (GET request).
    • store() → Handle a request to save a new item to the database (POST request).
    • edit() → Display a form to edit an item (GET request).
    • update() → Handle a request to save changes to an item (POST request).
    • delete() → Handle a request to delete an item (GET request).

Controller Constructor and Callback Methods Signatures

Section titled “Controller Constructor and Callback Methods Signatures”
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class YourController extends BaseController // e.g., ProductsController
{
// Constructor
public function __construct(Container $container, private YourModel $model) // inject your model into the controller constructor
{
parent::__construct($container);
}
// Signatures of controller methods: (callback methods)
public function index(Request $request, Response $response, array $args): Response // GET request
public function show(Request $request, Response $response, array $args): Response // GET request
public function create(Request $request, Response $response, array $args): Response // GET request
public function store(Request $request, Response $response, array $args): Response // POST request
public function edit(Request $request, Response $response, array $args): Response // GET request
public function update(Request $request, Response $response, array $args): Response // POST request
public function delete(Request $request, Response $response, array $args): Response // GET request
}

  1. Create a folder in app/Views/ matching your resource (e.g., products) name (lowercase) (if it doesn’t exist)
  2. Create these view files:
    • resource-name.IndexView.php => List view
    • resource-name.ShowView.php => Detail view
    • resource-name.CreateView.php => Creation form
    • resource-name.EditView.php => Edit form

  1. Open app/Routes/web-routes.php
  2. Import your controller at the top with other use statements
  3. Add routes inside the return function using this pattern:

Follow the pattern: [controller_name].[method_name]


Understanding URI Design and Resource Identification

Section titled “Understanding URI Design and Resource Identification”

URIs (Uniform Resource Identifiers) serve as unique addresses for your application’s resources. Think of them like street addresses - each resource needs a clear, predictable location.

Key Benefits:

  • Predictability: Users and developers can guess URIs
  • SEO-friendly: Search engines prefer meaningful URIs
  • Maintainability: Consistent patterns make code easier to maintain
  • REST Compliance: Follows web standards and best practices

Using RESTful URI Principles in your application

Section titled “Using RESTful URI Principles in your application”

Good: /products (noun - represents the resource) ❌ Bad: /getProducts (verb - describes the action)

Good: /products (collection of products) ❌ Bad: /product (ambiguous - single or multiple?)

Good: /products/123/reviews (reviews for product 123) ❌ Bad: /reviews?product_id=123 (less intuitive)

Good: /products/categories (all lowercase) ❌ Bad: /Products/Categories (mixed case)


ActionHTTP MethodURI PatternExample
List allGET/resources/products
Show oneGET/resources/{id}/products/123
Create formGET/resources/create/products/create
Store newPOST/resources/products
Edit formGET/resources/{id}/edit/products/123/edit
UpdatePOST/resources/{id}/products/123
DeleteGET/resources/{id}/delete/products/123/delete

Add these routes to your web-routes.php file for complete CRUD functionality:

// 1) List all resources (GET /resource-name) e.g., GET /products
$app->get('/resource-name', [YourController::class, 'index'])
->setName('resource.index');
// 2) Show single resource (GET /resource-name/{id}) e.g., GET /products/1
$app->get('/resource-name/{id}', [YourController::class, 'show'])
->setName('resource.show');
// 3) Show a form to create a new resource (GET /resource-name/create) e.g., GET /products/create
$app->get('/resource-name/create', [YourController::class, 'create'])
->setName('resource.create');
// 4) Handle a request to save a new item to the database (POST /resource-name) e.g., POST /products
$app->post('/resource-name', [YourController::class, 'store']);
// 5) Show a form to edit an existing resource (GET /resource-name/{id}/edit) e.g., GET /products/1/edit
$app->get('/resource-name/{id}/edit', [YourController::class, 'edit'])
->setName('resource.edit');
// 6) Handle a request to save changes to an existing resource (POST /resource-name/{id}) e.g., POST /products/1
$app->post('/resource-name/{id}', [YourController::class, 'update']);
// 7) Handle a request to delete an existing resource (GET /resource-name/{id}/delete) e.g., GET /products/1/delete
$app->get('/resource-name/{id}/delete', [YourController::class, 'delete'])
->setName('resource.delete');

  1. Create a model class in app/Domain/Models/ (e.g., ProductsModel.php) (if it doesn’t exist)
  2. Implement methods for data operations in the model:
    • getAll() => Retrieve all records (SELECT query)
    • getById($id) => Get a single record (SELECT query)
    • create($data) => Insert a new record (INSERT query)
    • update($id, $data) => Update an existing record (UPDATE query)
    • delete($id) => Remove an existing record (DELETE query)
  3. Follow the MVC pattern - models handle data, controllers coordinate, views display

  1. Inject your model into the controller constructor (if not already done)
  2. Use the model methods for all data operations
  3. Use $this->render() to display views with data from models
  4. Use $this->redirect() for navigation after form submissions
  5. Extract route parameters using $args['parameter_name']
  6. Get form data using $request->getParsedBody()
  7. Validate input data before passing to model methods
  8. Handle errors gracefully with appropriate redirects

  1. Start your development server
  2. Visit each route in your browser
  3. Test form submissions
  4. Verify redirects work correctly
  5. Check error handling

  • Route order matters: Place specific routes (like /create) before parametric routes (like /{id})
  • Named routes: Always use ->setName() for routes you’ll redirect to
  • URI args vs query params: Use $args only for routes with {placeholders}, use $request->getQueryParams() for ?key=value
  • POST-Redirect-GET: Always redirect after successful form submissions to prevent duplicate submissions

After following these steps, you should have:

app/
├── Controllers/
│ └── YourController.php 👉 (e.g., ProductsController.php)
├── Models/
│ └── YourModel.php 👉 (e.g., ProductsModel.php)
├── Views/
│ └── your-resource/ 👉 (e.g., products)
│ ├── resource-name.IndexView.php 👉 (e.g., products.IndexView.php)
│ ├── resource-name.ShowView.php 👉 (e.g., products.ShowView.php)
│ ├── resource-name.CreateView.php 👉 (e.g., products.CreateView.php)
│ └── resource-name.EditView.php 👉 (e.g., products.EditView.php)
└── Routes/
└── web-routes.php (updated)

Remember to follow the MVC pattern throughout your implementation:

  • Models: Handle all data operations, database queries, and business logic
  • Views: Display data and handle user interface
  • Controllers: Coordinate between models and views, handle HTTP requests/responses

  • Add validation to your controller methods
  • Implement proper model classes with database operations
  • Add error handling and user feedback
  • Style your views with CSS
  • Add authentication/authorization if needed
  • Consider implementing advanced search features (autocomplete, faceted search)
  • Add export functionality for filtered results