Organ

🥕🌿Project: Website bán thực phẩm Organic🌿🥕

📚 Mục lục


👤 Thông Tin Cá Nhân


📈 Mục Đích Dự Án


🛠️ Công Nghệ Sử Dụng

Công nghệ Vai trò chính
Laravel Framework PHP backend chính
Laravel Breeze Xác thực người dùng, session
Blade + Tailwind CSS Giao diện frontend nhẹ, đẹp
MySQL (Aiven) Cơ sở dữ liệu chính
Eloquent ORM Xử lý dữ liệu dạng hướng đối tượng
Middleware Bảo mật & kiểm soát truy cập

⚙️ Kiến Trúc Hệ Thống & Sơ Đồ

🔹 Sơ đồ khối

Sơ đồ khối

🔹 Sơ đồ chức năng


📊 Sơ Đồ Tuần Tự


💻Một Số Code Minh Họa

📦Model

User Model

class User extends Authenticatable
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }
}
 

Order Model

class Order extends Model
{
    protected $fillable = [
        'user_id', 'name', 'email', 'phone', 'address',
        'order_notes', 'subtotal', 'total', 'payment_method', 'status'
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function orderDetails()
    {
        return $this->hasMany(OrderDetail::class);
    }
    
       
}

OrderDetail Model

class OrderDetail extends Model
{
    protected $fillable = ['order_id', 'product_id', 'quantity', 'price', 'total'];

    public function order()
    {
        return $this->belongsTo(Order::class);
    }

    public function product()
    {
        return $this->belongsTo(Product::class);
    }
}

Product Model

class Product extends Model
{
    protected $fillable = [
        'name', 'slug', 'description', 'price', 'discount_price', 'stock', 'image', 'category_id'
    ];

    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function cartItems()
    {
        return $this->hasMany(CartItem::class);
    }

    public function orderItems()
    {
        return $this->hasMany(OrderItem::class);
    }

    public function reviews()
    {
        return $this->hasMany(Review::class);
    }
}

Category Model

class Category extends Model
{
    protected $fillable = ['name', 'slug','image'];

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

Contact Model

class Contact extends Model
{
    protected $fillable = [
        'name',
        'email',
        'phone',
        'message',
        'is_read',
        'user_id', 
    ];

    /**
     * Lấy các phản hồi của admin.
     */
    public function replies(): HasMany
    {
        return $this->hasMany(ContactReply::class);
    }

    /**
     * Lấy thông tin user gửi tin nhắn.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

ContactReply Model

 class ContactReply extends Model
{
    use HasFactory;

    protected $fillable = [
        'contact_id',
        'replied_by_user_id',
        'reply',
    ];
    public function contact()
    {
        return $this->belongsTo(Contact::class);
    }
    public function repliedBy()
    {
        return $this->belongsTo(User::class, 'replied_by_user_id');
    }
}

### Cart Model

 class Cart extends Model
{
    protected $fillable = ['user_id', 'subtotal', 'total'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function cartItems()
    {
        return $this->hasMany(CartItem::class);
    }
}

CartItem Model

class CartItem extends Model
{
    protected $fillable = ['cart_id', 'product_id', 'quantity', 'price', 'total'];

    public function cart()
    {
        return $this->belongsTo(Cart::class);
    }

    public function product()
    {
        return $this->belongsTo(Product::class);
    }
}

🧠Controller

Contact Controller

public function send(Request $request)
    {
        $validated = $request->validate([
            'name'    => 'required|string|max:255',
            'email'   => 'required|email',
            'phone'   => 'required|string|max:20',
            'message' => 'required|string|max:1000',
        ]);

        // Lưu thông tin liên hệ vào database
        Contact::create([
            'name'    => $validated['name'],
            'email'   => $validated['email'],
            'phone'   => $validated['phone'],
            'message' => $validated['message'],
            'is_read' => false, // tin nhắn mới gửi sẽ chưa đọc
        ]);

        return redirect()->back()->with('success', 'Cảm ơn bạn đã liên hệ!');
    }

AdminOrder Controller

 public function index(Request $request)
    {
        $keyword = $request->input('keyword');

        $orders = Order::when($keyword, function ($query, $keyword) {
                $query->where('name', 'like', "%{$keyword}%");
            })
            ->with('orderDetails.product') 
            ->latest()
            ->paginate(10);

        return view('admin.order', compact('orders'));
    }

    public function update(Request $request, $id)
    {
        $request->validate([
            'name'          => 'required|string|max:50',
            'email'         => 'required|email|max:150',
            'phone'         => 'required|string|max:20',
            'address'       => 'required|string|max:200',
            'order_notes'   => 'nullable|string|max:1000',
            'total'         => 'required|numeric|min:0',
            'status'        => 'required|in:pending,processing,completed,cancelled',
        ]);

        $order = Order::findOrFail($id);

        $order->update([
            'name'          => $request->name,
            'email'         => $request->email,
            'phone'         => $request->phone,
            'address'       => $request->address,
            'order_notes'   => $request->order_notes,
            'total'         => $request->total,
            'status'        => $request->status,
        ]);

        return redirect()->route('admin.order')->with('success', 'Order updated successfully.');
    }

    public function destroy($id)
    {
        $order = Order::findOrFail($id);
        $order->delete();

        return redirect()->route('admin.order')->with('success', 'Order deleted successfully.');
    }

AdminUserController

 // Hiển thị danh sách người dùng với tìm kiếm
    public function index(Request $request)
    {
        $keyword = $request->keyword;

        $users = User::query()
            ->when($keyword, function ($query, $keyword) {
                return $query->where('email', 'like', '%' . $keyword . '%');
            })
            ->orderBy('id','asc')
            ->get();

        return view('admin.user', compact('users'));
    }
    // Cập nhật thông tin người dùng
    public function update(Request $request, $id)
    {
        $request->validate([
            'name'    => 'required|string|max:255',
            'email'   => 'required|email|max:255|unique:users,email,' . $id,
            'phone'   => 'nullable|string|max:20',
            'address' => 'nullable|string|max:255',
            'role'    => 'required|in:admin,user',
        ]);

        $user = User::findOrFail($id);

        $user->update([
            'name'    => $request->name,
            'email'   => $request->email,
            'phone'   => $request->phone,
            'address' => $request->address,
            'role'    => $request->role,
        ]);

        return redirect()->route('admin.user')->with('success', 'Cập nhật người dùng thành công!');
    }

    // Xóa người dùng
    public function destroy($id)
    {
        $user = User::findOrFail($id);
        $user->delete();

        return redirect()->route('admin.user')->with('success', 'Xóa người dùng thành công!');
    }

📄 Blade Template (View)

View


🔐 Bảo Mật

Ví dụ:CSRF & XSS Token bảo vệ form (ví dụ: productdetail.blade)

 <!-- Form thêm vào giỏ -->
            <form action="" method="POST">
                @csrf
                <input type="hidden" name="product_id" value="">
                
                <div class="product__details__quantity">
                    <div class="quantity">
                        <div class="pro-qty">
                            <input name="quantity" value="1" min="1" type="number">
                        </div>
                    </div>
                </div>

                <button type="submit" class="primary-btn">ADD TO CARD</button>
            </form>

📷 Một Số Hình Ảnh Giao Diện

👤 Người Dùng (User)


🛠️Quản Trị Viên (Admin)


🔗 Liên Kết

-🔗 GitHub:https://github.com/PhanThiGiaHan108/Organ

-🥦Readme (web io) :https://phanthigiahan108.github.io/Organ/

-🌐 Public Website: https://organshop-master-uvy5n7.laravel.cloud/

📝 License

This project is built using Laravel, which is open-sourced software licensed under the MIT license.