Laravel Resource Controller Store
October 19, 2024 · AI Conversations
### Example of a `store` method with validation:
namespace AppHttpControllers;
use AppModelsYourModel;
use IlluminateHttpRequest;
class YourModelController extends Controller
{
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
// Validate the request data
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:your_model_table,email',
'age' => 'nullable|integer|min:18'
]);
// Create the new resource
$yourModel = YourModel::create($validatedData);
// Redirect or respond as needed
return redirect()->route('your_model.index')
->with('success', 'Resource created successfully!');
}
}
### Explanation:
– **Validation**: The `$request->validate()` method automatically validates the incoming data based on the rules defined. If validation fails, Laravel will automatically redirect back with error messages.
– **Creating the Model**: After validation, the validated data is passed to the `YourModel::create()` method, which creates the new record in the database.
– **Response**: After storing the resource, you can return a redirect with a success message or any other response as needed.
Make sure that your model uses the `fillable` or `guarded` property to allow mass assignment:
// YourModel.php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class YourModel extends Model
{
protected $fillable = ['name', 'email', 'age'];
}
This will enable mass assignment using the `create` method in the `store` method.
### Example Form in Blade with Validation Error Display:
<form action="{{ route('your_model.store') }}" method="POST">
@csrf
<!-- Name Field -->
<div class="form-group">
<label for="name">Name:</label>
<input type="text" name="name" class="form-control" value="{{ old('name') }}">
<!-- Error for Name -->
@error('name')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<!-- Email Field -->
<div class="form-group">
<label for="email">Email:</label>
<input type="email" name="email" class="form-control" value="{{ old('email') }}">
<!-- Error for Email -->
@error('email')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<!-- Age Field (optional) -->
<div class="form-group">
<label for="age">Age (optional):</label>
<input type="number" name="age" class="form-control" value="{{ old('age') }}">
<!-- Error for Age -->
@error('age')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<!-- Submit Button -->
<button type="submit" class="btn btn-primary">Submit</button>
</form>
### Explanation:
1. **CSRF Token**: Always include the `@csrf` directive for form security in Laravel.
2. **Form Fields**: Each input field is populated with old input values using `old('field_name')` to retain user input after a validation failure.
3. **Error Display**: The `@error('field_name')` directive checks if a validation error exists for the specified field. If it does, the `$message` variable contains the error message.
4. **Styling**: In this example, errors are displayed in a `div` with the `text-danger` class to make them appear in red (assuming Bootstrap is used, or you can define your own CSS class).
### Displaying All Validation Errors (Optional):
If you prefer to display all errors at the top of the form, you can do this:
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
This will display all validation errors at once in a list at the top of the form.
### Step-by-Step:
1. **Flash the Success Message** in your controller:
In your `store` method, after successfully storing the data, use `with()` to flash a success message to the session.
public function store(Request $request)
{
// Validate the request data
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:your_model_table,email',
'age' => 'nullable|integer|min:18'
]);
// Create the new resource
YourModel::create($validatedData);
// Flash success message
return redirect()->route('your_model.index')
->with('success', 'Resource created successfully!');
}
2. **Display the Success Message** in your Blade view:
Now, in your Blade template, check if a success message is present in the session and display it.
@if(session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
### Full Example of Blade Template:
@if(session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('your_model.store') }}" method="POST">
@csrf
<!-- Name Field -->
<div class="form-group">
<label for="name">Name:</label>
<input type="text" name="name" class="form-control" value="{{ old('name') }}">
@error('name')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<!-- Email Field -->
<div class="form-group">
<label for="email">Email:</label>
<input type="email" name="email" class="form-control" value="{{ old('email') }}">
@error('email')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<!-- Age Field (optional) -->
<div class="form-group">
<label for="age">Age (optional):</label>
<input type="number" name="age" class="form-control" value="{{ old('age') }}">
@error('age')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<!-- Submit Button -->
<button type="submit" class="btn btn-primary">Submit</button>
</form>
### Explanation:
– **Session Success Message**: The `session('success')` checks if there is a success message in the session and, if present, displays it inside an alert box styled with the `alert-success` class (assuming Bootstrap).
– **Error Display**: The `@if($errors->any())` block handles the display of validation errors.
Now, when the form is successfully submitted, a success message will be displayed on the next page load.
return custom value for one coloumn
### Approach 1: Using Eloquent Accessor
If you want to customize the output of a specific column, you can define an **accessor** in your model. This method will automatically modify the value whenever it's accessed.
For example, if you have a `Coupon` model and you want to customize the `discount` column, you can do this in your `Coupon` model:
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class Coupon extends Model
{
// Define an accessor for a column, like `discount`
public function getDiscountAttribute($value)
{
// Custom logic to modify the discount column's value
return $value . '%'; // Appending '%' to the discount value
}
}
In this example, if the `discount` column contains `50`, when accessed, it will return `50%`.
### Approach 2: Modify Data in the Controller Before Returning It
You can modify the data in your controller before passing it to the view.
public function index()
{
// Get paginated coupons
$coupons = Coupon::orderByDesc('id')->paginate(100);
// Modify one column (e.g., append '%' to discount column)
foreach ($coupons as $coupon) {
$coupon->custom_discount = $coupon->discount . '%'; // Custom modification
}
// Return the data to the view
return view('coupons.index', compact('coupons'));
}
Then in your Blade view, you can access the `custom_discount` property like this:
@foreach ($coupons as $coupon)
<tr>
<td>{{ $coupon->id }}</td>
<td>{{ $coupon->code }}</td>
<td>{{ $coupon->custom_discount }}</td> <!-- Custom discount -->
</tr>
@endforeach
### Approach 3: Using `map()` to Modify the Collection
Alternatively, you can use the `map()` method to transform the collection returned by the query.
public function index()
{
// Get paginated coupons and modify the discount column
$coupons = Coupon::orderByDesc('id')->paginate(100);
// Modify using map()
$coupons->getCollection()->transform(function ($coupon) {
$coupon->discount = $coupon->discount . '%'; // Custom modification
return $coupon;
});
// Return to the view
return view('coupons.index', compact('coupons'));
}
### Summary
– **Accessors** in the model provide a way to modify the column globally across the app whenever it is accessed.
– You can modify values directly in the **controller** before passing them to the view.
– **Collection mapping** allows you to manipulate the data right after fetching it and before rendering it.
All these methods let you return a custom value for a specific column while keeping the code clean and efficient.
### Example of Resource Controller with `edit` Route:
1. **Define the Resource Route**:
In your `routes/web.php` file, use the `Route::resource()` method to automatically generate all the necessary routes (including `edit`):
Route::resource('coupons', CouponController::class);
This will generate the following routes:
– `GET /coupons` (index)
– `GET /coupons/create` (create)
– **`GET /coupons/{coupon}/edit` (edit)**
– `POST /coupons` (store)
– `PUT/PATCH /coupons/{coupon}` (update)
– `DELETE /coupons/{coupon}` (destroy)
– `GET /coupons/{coupon}` (show)
2. **Controller Method for the `edit` Route**:
In your `CouponController`, define the `edit` method:
namespace AppHttpControllers;
use AppModelsCoupon;
use IlluminateHttpRequest;
class CouponController extends Controller
{
/**
* Show the form for editing the specified resource.
*/
public function edit($id)
{
// Find the coupon by ID
$coupon = Coupon::findOrFail($id);
// Return the edit view with the coupon data
return view('coupons.edit', compact('coupon'));
}
}
3. **Creating the Edit View** (`resources/views/coupons/edit.blade.php`):
You can now create a Blade view for the edit form. For example:
<form action="{{ route('coupons.update', $coupon->id) }}" method="POST">
@csrf
@method('PUT') <!-- Method spoofing for PUT request -->
<!-- Coupon Code Field -->
<div class="form-group">
<label for="code">Coupon Code</label>
<input type="text" name="code" class="form-control" value="{{ old('code', $coupon->code) }}">
@error('code')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<!-- Discount Field -->
<div class="form-group">
<label for="discount">Discount</label>
<input type="number" name="discount" class="form-control" value="{{ old('discount', $coupon->discount) }}">
@error('discount')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<!-- Submit Button -->
<button type="submit" class="btn btn-primary">Update Coupon</button>
</form>
4. **Update Method in the Controller**:
After submitting the form, the `update` method will be called. Define the `update` method in your `CouponController`:
public function update(Request $request, $id)
{
// Validate the request data
$validatedData = $request->validate([
'code' => 'required|string|max:255',
'discount' => 'required|numeric|min:0',
]);
// Find the coupon by ID and update it
$coupon = Coupon::findOrFail($id);
$coupon->update($validatedData);
// Redirect back with a success message
return redirect()->route('coupons.index')->with('success', 'Coupon updated successfully!');
}
### Summary of the `edit` Route Process:
1. **Route**: A `GET` request to `/coupons/{coupon}/edit` will trigger the `edit` method in the `CouponController`.
2. **Controller**: The `edit` method retrieves the resource by its ID and returns the view with the current data to be edited.
3. **View**: The edit form is shown, pre-filled with the current values of the coupon, and the form submits a `PUT` request to update the resource.
By using resource controllers and routes, Laravel streamlines the process of building CRUD operations, including the `edit` route for modifying existing resources.
### Example of Adding an "Edit" Link in Blade:
In your Blade view (e.g., `index.blade.php`), where you're listing all the coupons, you can add an "Edit" link next to each resource like this:
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Code</th>
<th>Discount</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach($coupons as $coupon)
<tr>
<td>{{ $coupon->id }}</td>
<td>{{ $coupon->code }}</td>
<td>{{ $coupon->discount }}</td>
<td>
<!-- Edit link -->
<a href="{{ route('coupons.edit', $coupon->id) }}" class="btn btn-primary">Edit</a>
</td>
</tr>
@endforeach
</tbody>
</table>
### Explanation:
1. **Route to the Edit Page**:
– The `route('coupons.edit', $coupon->id)` generates the URL for the `edit` route of the resource. This corresponds to `GET /coupons/{id}/edit`, which will take you to the form to edit the selected coupon.
– `$coupon->id` is passed as a parameter to the route so Laravel knows which resource (coupon) you want to edit.
2. **"Edit" Button**:
– The “ tag creates a link that points to the `edit` route for each coupon.
– You can style the link as a button using Bootstrap classes (like `btn btn-primary`).
When a user clicks the "Edit" link, they will be taken to the `edit` form for the selected coupon, where they can update its details.
$coupon->encrypted_id = Crypt::encrypt($coupon->id); // Custom modification
return $coupon;
});
if discountype is percentage then add % to value
Here's how you can modify your existing code:
### Updated Code:
use IlluminateSupportFacadesCrypt;
$coupons->getCollection()->transform(function ($coupon) {
// Encrypt the coupon ID
$coupon->encrypted_id = Crypt::encrypt($coupon->id);
// Check if discount_type is 'percentage' and modify the discount value
if ($coupon->discount_type === 'percentage') {
$coupon->discount .= '%'; // Append % symbol to discount value
}
return $coupon;
});
### Explanation:
1. **Encrypting the ID**: The existing line of code is used to encrypt the `id` and store it in the `encrypted_id` attribute.
2. **Checking `discount_type`**:
– We check if `$coupon->discount_type` is equal to `'percentage'`.
– If it's a percentage, we append the `%` symbol to the `discount` value by using `$coupon->discount .= '%'`.
3. **Returning the Modified Coupon**: The transformed coupon object is returned after applying the custom modifications.
Now, when the `discount_type` is `'percentage'`, the discount value will include a `%` symbol. Otherwise, the original value will remain unchanged.
You can then use `{{ $coupon->discount }}` in your Blade view to display the modified discount value.
### Steps to Create a Delete Button in Blade:
1. **Route Setup**:
Make sure your resource routes are defined using `Route::resource` in your `routes/web.php` file.
Route::resource('coupons', CouponController::class);
This will automatically create the `destroy` route for deleting a resource (i.e., `DELETE /coupons/{coupon}`).
2. **Controller Method for Deleting**:
In your `CouponController`, the `destroy` method should look like this:
public function destroy($id)
{
// Find the coupon by its ID
$coupon = Coupon::findOrFail($id);
// Delete the coupon
$coupon->delete();
// Redirect back with a success message
return redirect()->route('coupons.index')->with('success', 'Coupon deleted successfully!');
}
3. **Delete Form in Blade**:
In your Blade view (for example, `index.blade.php` where you're listing all the coupons), create a form for the delete action:
@foreach($coupons as $coupon)
<tr>
<td>{{ $coupon->id }}</td>
<td>{{ $coupon->code }}</td>
<td>{{ $coupon->discount }}</td>
<td>
<!-- Edit link -->
<a href="{{ route('coupons.edit', $coupon->id) }}" class="btn btn-primary">Edit</a>
<!-- Delete form -->
<form action="{{ route('coupons.destroy', $coupon->id) }}" method="POST" style="display:inline;">
@csrf
@method('DELETE') <!-- Spoof the DELETE method -->
<button type="submit" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this coupon?')">Delete</button>
</form>
</td>
</tr>
@endforeach
### Explanation:
1. **Edit Button**: The `Edit` button links to the `edit` route as shown in the previous examples.
2. **Delete Form**:
– The form's `action` attribute uses the `route()` helper to generate the correct URL for deleting the coupon (e.g., `coupons/{coupon}`).
– The `method="POST"` is used, but since HTML forms don't support `DELETE` requests directly, we use `@method('DELETE')` to spoof the `DELETE` HTTP method.
– The `@csrf` directive is included to protect against CSRF attacks.
– The `onclick` event prompts a confirmation dialog before submitting the form, asking the user if they really want to delete the resource.
3. **Styling**: The delete button is styled using Bootstrap classes (`btn btn-danger`), but you can style it as per your requirements.
### Result:
When the user clicks the **Delete** button, the form will send a `DELETE` request to the `destroy` route. After deletion, the user will be redirected back to the index page with a success message.
This approach is a standard way to handle delete functionality in Laravel with resource controllers and Blade templates.
To solve this, you can either:
– Pass the base URL from the server and append the ID in JavaScript.
– Use a data attribute to store the URL template.
### Solution 1: Pass the Base URL from Laravel and Append ID in JavaScript
You can generate the base URL in Blade and append the `id` in JavaScript.
#### Step 1: Pass the Base URL from Blade to JavaScript
In your Blade template, you can pass the base URL (without the `id`) to JavaScript:
<script>
// Pass the base URL to JavaScript
var destroyUrl = "{{ route('admin.coupons.destroy', ':id') }}";
</script>
Here, `:id` is just a placeholder for the actual `id`.
#### Step 2: Replace the Placeholder with the Actual ID in JavaScript
In your JavaScript code, replace `:id` with the actual coupon `id` dynamically:
function deleteCoupon(id) {
// Replace :id with the actual coupon id
var url = destroyUrl.replace(':id', id);
// Now you can use this `url` to make an AJAX request or set it to your form's action
console.log(url); // For debugging purposes, you can remove this line
// Example: setting the action attribute of a form for deletion
document.getElementById('deleteForm').action = url;
}
In this example, when the `deleteCoupon(id)` function is called, it replaces the `:id` placeholder with the actual `id` value passed to the function.
### Solution 2: Using Data Attributes
Another way is to store the URL in a data attribute for each row and dynamically retrieve it in JavaScript.
#### Step 1: Create the Data Attribute with the URL
@foreach($coupons as $coupon)
<tr>
<td>{{ $coupon->id }}</td>
<td>{{ $coupon->code }}</td>
<td>{{ $coupon->discount }}</td>
<td>
<!-- Edit button -->
<a href="{{ route('admin.coupons.edit', $coupon->id) }}" class="btn btn-primary">Edit</a>
<!-- Delete button with data-url -->
<button class="btn btn-danger" onclick="deleteCoupon(this)" data-url="{{ route('admin.coupons.destroy', $coupon->id) }}">Delete</button>
</td>
</tr>
@endforeach
#### Step 2: Use the Data Attribute in JavaScript
Now, in your JavaScript function, retrieve the `data-url` attribute:
function deleteCoupon(button) {
// Get the URL from the button's data attribute
var url = button.getAttribute('data-url');
console.log(url); // For debugging purposes, you can remove this line
// Example: setting the action attribute of a form for deletion
document.getElementById('deleteForm').action = url;
}
### Summary:
– **Solution 1**: Pass a URL with a placeholder from Blade to JavaScript, and replace the placeholder with the actual `id` dynamically in JavaScript.
– **Solution 2**: Use `data-url` attributes in your HTML and dynamically fetch the URL from the button's attribute in JavaScript.
Both approaches work well, but the second approach is often simpler and avoids having to manipulate strings in JavaScript.
var id = jQuery(this).data('clientid');
var that = this;
event.preventDefault();
Swal.fire({
icon: 'warning',
text: "Do you want to delete this?",
showCancelButton: true,
cancelButtonText: "Cancel",
confirmButtonText: "Delete",
confirmButtonColor: '#e3342f',
}).then((result) => {
if (result.isConfirmed) {
jQuery.ajax({
url: "{{route('admin.coupons.destroy',"+id+")}}",
type: "DELETE",
dataType: "json",
data: {
"_token": "{{ csrf_token() }}"
},
beforeSend: function() {
jQuery('.loader-section').show();
},
complete: function() {
jQuery('.loader-section').hide();
},
success: function(data) {
if (data.result == "success") {
jQuery('.row_' + id).remove();
Swal.fire({
title: data.message,
icon: 'success'
});
} else {
Swal.fire({
title: "Error, Please try again later.",
color: '#dc3545',
icon: 'error'
});
}
},
error: function(jqXHR, exception) {
alert(jqXHR.status);
}
});
}
});
});
above code not working
Here’s how to fix your code:
### Step 1: Generate the Base URL in Blade
Instead of trying to dynamically insert `id` in the Blade syntax, you can create the base URL in Blade with a placeholder.
In your Blade view, set up the base URL like this:
<script>
var deleteCouponUrl = "{{ route('admin.coupons.destroy', ':id') }}";
</script>
### Step 2: Update Your jQuery Code
Now, you can use this `deleteCouponUrl` variable in your jQuery code and replace `:id` with the actual ID when the delete confirmation dialog is accepted:
jQuery(document).on('click', '.show-alert-delete-box', function(event) {
var id = jQuery(this).data('clientid');
var that = this;
event.preventDefault();
Swal.fire({
icon: 'warning',
text: "Do you want to delete this?",
showCancelButton: true,
cancelButtonText: "Cancel",
confirmButtonText: "Delete",
confirmButtonColor: '#e3342f',
}).then((result) => {
if (result.isConfirmed) {
// Replace :id with the actual coupon id
var url = deleteCouponUrl.replace(':id', id);
jQuery.ajax({
url: url, // Use the dynamically generated URL
type: "DELETE",
dataType: "json",
data: {
"_token": "{{ csrf_token() }}" // CSRF token for security
},
beforeSend: function() {
jQuery('.loader-section').show();
},
complete: function() {
jQuery('.loader-section').hide();
},
success: function(data) {
if (data.result == "success") {
jQuery('.row_' + id).remove(); // Remove the deleted row
Swal.fire({
title: data.message,
icon: 'success'
});
} else {
Swal.fire({
title: "Error, Please try again later.",
color: '#dc3545',
icon: 'error'
});
}
},
error: function(jqXHR, exception) {
alert(jqXHR.status); // Show an alert with the error status
}
});
}
});
});
### Explanation:
1. **Generating the Base URL**: The base URL for the delete route is generated in Blade with a placeholder (`:id`). This allows you to maintain the Laravel route functionality.
2. **Replacing the Placeholder**: When the user confirms the deletion, you replace `:id` with the actual coupon ID using `var url = deleteCouponUrl.replace(':id', id);`.
3. **Sending the AJAX Request**: You then use this dynamically created URL in your AJAX request to send a `DELETE` request to the server.
### Final Note:
Make sure you have defined the proper routes in your `web.php` file and that your AJAX endpoint returns a JSON response that contains a `result` and `message` key. This structure is crucial for the success and error handling in the success function of your AJAX request.
This approach should resolve the issue and enable the deletion process using SweetAlert and AJAX.