Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ We welcome contributions from the community and look forward to working with you
* **Feature Requests:** If you have a feature request, please open an issue with a clear description of the feature and its benefits.
* **Priority:** Bug fixes will take priority over feature requests.

[//]: # (## Contributors)
## Contributors

[//]: # ()
[//]: # (<a href="https://github.com/ntoufoudis/LaravelCommerce/graphs/contributors">)

[//]: # ( <img src="https://contrib.rocks/image?repo=ntoufoudis/LaravelCommerce" />)
<a href="https://github.com/ntoufoudis/LaravelCommerce/graphs/contributors">

[//]: # (</a>)
<img src="https://contrib.rocks/image?repo=ntoufoudis/LaravelCommerce" alt="contributors"/>

</a>


Thank you for your contributions!
80 changes: 80 additions & 0 deletions api.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON:API paints my bikeshed!"
},
"relationships": {
"author": {
"links": {
"self": "http://example.com/articles/1/relationships/author",
"related": "http://example.com/articles/1/author"
},
"data": {
"type": "people",
"id": "9"
}
},
"comments": {
"links": {
"self": "http://example.com/articles/1/relationships/comments",
"related": "http://example.com/articles/1/comments"
},
"data": [
{
"type": "comments",
"id": "5"
},
{
"type": "comments",
"id": "12"
}
]
}
},
"links": {
"self": "http://example.com/articles/1"
}
}],
"included": [{
"type": "people",
"id": "9",
"attributes": {
"firstName": "Dan",
"lastName": "Geb",
"twitter": "geb"
},
"links": {
"self": "http://example.com/people/9"
}
}, {
"type": "comments",
"id": "5",
"attributes": {
"body": "First!"
},
"relationships": {
"author": {
"data": { "type": "people", "id": "2" }
}
},
"links": {
"self": "http://example.com/comments/5"
}
}, {
"type": "comments",
"id": "12",
"attributes": {
"body": "Second!"
},
"relationships": {
"author": {
"data": { "type": "people", "id": "9" }
}
},
"links": {
"self": "http://example.com/comments/12"
}
}]
}
72 changes: 72 additions & 0 deletions app/Http/Controllers/Api/V1/ProductController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Requests\Api\V1\StoreProductRequest;
use App\Http\Requests\Api\V1\UpdateProductRequest;
use App\Http\Resources\ProductResource;
use App\Models\Product;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Http\Request;

class ProductController extends Controller
{
use AuthorizesRequests;

/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$this->authorize('viewAny', Product::class);

$perPage = $request->query('per_page', 10);

return ProductResource::collection(Product::paginate($perPage));
}

/**
* Store a newly created resource in storage.
*/
public function store(StoreProductRequest $request)
{
$this->authorize('create', Product::class);

return new ProductResource(Product::create($request->validated()));
}

/**
* Display the specified resource.
*/
public function show(Product $product)
{
$this->authorize('view', $product);

return new ProductResource($product);
}

/**
* Update the specified resource in storage.
*/
public function update(UpdateProductRequest $request, Product $product)
{
$this->authorize('update', $product);

$product->update($request->validated());

return new ProductResource($product);
}

/**
* Remove the specified resource from storage.
*/
public function destroy(Product $product)
{
$this->authorize('delete', $product);

$product->delete();

return response()->json();
}
}
38 changes: 38 additions & 0 deletions app/Http/Requests/Api/V1/StoreProductRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace App\Http\Requests\Api\V1;

use App\Models\User;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules;

class StoreProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array<string, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'slug' => ['nullable', 'string', 'max:255', 'unique:products,slug'],
'description' => ['nullable', 'string'],
'short_description' => ['nullable', 'string'],
'price' => ['required', 'numeric'],
'featured' => ['nullable', 'boolean'],
'status' => ['nullable', 'in:draft, pending, private, publish'],
'sku' => ['required', 'string'],
];
}
}
38 changes: 38 additions & 0 deletions app/Http/Requests/Api/V1/UpdateProductRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace App\Http\Requests\Api\V1;

use App\Models\User;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules;

class UpdateProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array<string, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'name' => ['sometimes', 'required', 'string', 'max:255'],
'slug' => ['nullable', 'string', 'max:255', 'unique:products,slug'],
'description' => ['nullable', 'string'],
'short_description' => ['nullable', 'string'],
'price' => ['sometimes', 'required', 'numeric'],
'featured' => ['nullable', 'boolean'],
'status' => ['nullable', 'in:draft, pending, private, publish'],
'sku' => ['sometimes', 'required', 'string'],
];
}
}
25 changes: 25 additions & 0 deletions app/Http/Resources/ProductResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace App\Http\Resources;

use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

/** @mixin Product */
class ProductResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'slug' => $this->slug,
'description' => $this->description,
'short_description' => $this->short_description,
'price' => $this->price,
'featured' => $this->featured,
'status' => $this->status,
];
}
}
1 change: 1 addition & 0 deletions app/Http/Resources/TagResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public function toArray(Request $request): array
'name' => $this->name,
'slug' => $this->slug,
'description' => $this->description,
'count' => $this->products()->where('status', 'publish')->count(),
];
}
}
16 changes: 16 additions & 0 deletions app/Imports/FileImport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Imports;

use Vitorccs\LaravelCsv\Concerns\Importables\FromFile;
use Vitorccs\LaravelCsv\Concerns\Importables\Importable;

class FileImport implements FromFile
{
use Importable;

public function fileName(): string
{
return storage_path().'/products.csv';
}
}
6 changes: 6 additions & 0 deletions app/Models/Category.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

Expand All @@ -28,4 +29,9 @@ public function getSlugOptions(): SlugOptions
->generateSlugsFrom('name')
->saveSlugsTo('slug');
}

public function products(): BelongsToMany
{
return $this->belongsToMany(Product::class);
}
}
45 changes: 45 additions & 0 deletions app/Models/Product.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

class Product extends Model
{
use HasFactory, HasSlug;

protected $fillable = [
'name',
'slug',
'description',
'short_description',
'price',
'sku',
'featured',
'status',
];

public function categories(): BelongsToMany
{
return $this->belongsToMany(Category::class);
}

public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}

/**
* Get the options for generating the slug.
*/
public function getSlugOptions(): SlugOptions
{
return SlugOptions::create()
->generateSlugsFrom('name')
->saveSlugsTo('slug');
}
}
6 changes: 6 additions & 0 deletions app/Models/Tag.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

Expand All @@ -26,4 +27,9 @@ public function getSlugOptions(): SlugOptions
->generateSlugsFrom('name')
->saveSlugsTo('slug');
}

public function products(): BelongsToMany
{
return $this->belongsToMany(Product::class);
}
}
Loading