Skip to main content
Customers are users who have the customer role and can place orders in your store. Shopper extends your Laravel User model with e-commerce specific fields and relationships.

User Model Integration

Shopper doesn’t create a separate Customer model. Instead, it extends your existing App\Models\User model with the ShopperUser trait and contract.
namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Shopper\Core\Models\Contracts\ShopperUser;
use Shopper\Core\Traits\ShopperUser as ShopperUserTrait;

class User extends Authenticatable implements ShopperUser
{
    use ShopperUserTrait;

    // Your customizations
}
The ShopperUser trait provides:
  • HasRoles (Spatie Permission)
  • HasDiscounts
  • HasProfilePhoto
  • TwoFactorAuthenticatable

Database Schema

User Table Modifications

Shopper modifies the standard Laravel users table:
ColumnTypeNullableDefaultDescription
idbigintnoautoPrimary key
first_namestringyesnullFirst name
last_namestringno-Last name
emailstringno-Email address (unique)
passwordstringyesnullPassword (nullable for social auth)
email_verified_attimestampyesnullEmail verification date
genderstringno-Gender enum value
phone_numberstringyesnullPhone number
birth_datedateyesnullBirth date
avatar_typestringnoavatar_uiAvatar source type
avatar_locationstringyesnullAvatar file path
timezonestringyesnullUser timezone
opt_inbooleannofalseMarketing email consent
last_login_attimestampyesnullLast login timestamp
last_login_ipstringyesnullLast login IP address

Address Table

ColumnTypeNullableDefaultDescription
idbigintnoautoPrimary key
first_namestringno-First name
last_namestringno-Last name
company_namestringyesnullCompany name
street_addressstringno-Street address
street_address_plusstringyesnullAdditional address line
postal_codestringno-Postal/ZIP code
citystringno-City
statestringyesnullState/province/region
phone_numberstringyesnullPhone number
shipping_defaultbooleannofalseDefault shipping address
billing_defaultbooleannofalseDefault billing address
typestringyesnullAddress type enum
country_idbigintyesnullFK to countries
user_idbigintno-FK to users

Gender Type

The GenderType enum defines available gender options:
use Shopper\Core\Enum\GenderType;

GenderType::Male    // male
GenderType::Female  // female

Address Type

The AddressType enum defines address categories:
use Shopper\Core\Enum\AddressType;

AddressType::Billing   // billing
AddressType::Shipping  // shipping

Relationships

Orders

// Get all customer orders
$customer->orders; // Collection of Order models

// Get recent orders
$customer->orders()
    ->latest()
    ->take(5)
    ->get();

Addresses

// Get all customer addresses
$customer->addresses; // Collection of Address models

// Get default shipping address
$customer->addresses()
    ->where('shipping_default', true)
    ->first();

// Get default billing address
$customer->addresses()
    ->where('billing_default', true)
    ->first();

Query Scopes

use App\Models\User;

// Get only customers (users with 'user' role)
User::query()->customers()->get();

// Get administrators (admin or manager roles)
User::query()->administrators()->get();

Role Checking

// Check if user is an admin
$user->isAdmin();

// Check if user is a manager
$user->isManager();

// Check if email is verified
$user->isVerified();

Computed Attributes

// Get full name
$customer->full_name; // "John Doe"

// Get formatted birth date
$customer->birth_date_formatted; // "15, January 1990"

// Get roles as comma-separated string
$customer->roles_label; // "User, VIP"

// Get profile picture URL
$customer->picture; // Avatar URL (ui-avatars or uploaded)

Address Model

use Shopper\Core\Models\Address;

// The model implements
- Shopper\Core\Models\Contracts\Address

Extending the Address Model

namespace App\Models;

use Shopper\Core\Models\Address as BaseAddress;

class Address extends BaseAddress
{
    // Add your customizations here
}
Update config/shopper/models.php:
return [
    'address' => \App\Models\Address::class,
];

Address Methods

// Check if default shipping address
$address->isShippingDefault();

// Check if default billing address
$address->isBillingDefault();

// Get full name
$address->full_name; // "John Doe"

// Get country
$address->country;

Creating Customers

Basic Customer

use App\Models\User;
use Shopper\Core\Enum\GenderType;
use Illuminate\Support\Facades\Hash;

$customer = User::query()->create([
    'first_name' => 'John',
    'last_name' => 'Doe',
    'email' => 'john@example.com',
    'password' => Hash::make('password'),
    'gender' => GenderType::Male,
    'email_verified_at' => now(),
]);

// Assign customer role
$customer->assignRole(config('shopper.core.roles.user'));

Customer with Address

use Shopper\Core\Models\Address;
use Shopper\Core\Enum\AddressType;

$customer = User::query()->create([
    'first_name' => 'Jane',
    'last_name' => 'Doe',
    'email' => 'jane@example.com',
    'gender' => GenderType::Female,
    'phone_number' => '+1234567890',
    'opt_in' => true,
]);

$customer->assignRole(config('shopper.core.roles.user'));

// Add shipping address
$customer->addresses()->create([
    'first_name' => 'Jane',
    'last_name' => 'Doe',
    'street_address' => '123 Main Street',
    'city' => 'New York',
    'postal_code' => '10001',
    'country_id' => $countryId,
    'type' => AddressType::Shipping,
    'shipping_default' => true,
]);

Retrieving Customers

use App\Models\User;

// Get all customers
$customers = User::query()
    ->customers()
    ->latest()
    ->get();

// Search customers
$customers = User::query()
    ->customers()
    ->where(function ($query) use ($search) {
        $query->where('first_name', 'like', "%{$search}%")
            ->orWhere('last_name', 'like', "%{$search}%")
            ->orWhere('email', 'like', "%{$search}%");
    })
    ->get();

// Get customer with addresses and orders
$customer = User::query()
    ->with(['addresses', 'orders'])
    ->findOrFail($id);

// Get customers who opted in for marketing
$marketingList = User::query()
    ->customers()
    ->where('opt_in', true)
    ->get();

// Get verified customers only
$verified = User::query()
    ->customers()
    ->whereNotNull('email_verified_at')
    ->get();

Managing Addresses

use Shopper\Core\Models\Address;

// Create address for customer
$address = Address::query()->create([
    'user_id' => $customer->id,
    'first_name' => 'John',
    'last_name' => 'Doe',
    'street_address' => '456 Oak Avenue',
    'city' => 'Los Angeles',
    'postal_code' => '90001',
    'country_id' => $countryId,
    'type' => AddressType::Billing,
    'billing_default' => true,
]);

// Update default address
Address::query()
    ->where('user_id', $customer->id)
    ->where('type', AddressType::Shipping)
    ->update(['shipping_default' => false]);

$newDefault = Address::query()->find($addressId);
$newDefault->update(['shipping_default' => true]);

Observer Behavior

When a user is deleted, the ShopperUser trait automatically:
  • Detaches all roles
  • Deletes all addresses
// When deleting a user:
$customer->delete();
// Roles are detached and addresses are deleted automatically

Role Configuration

Roles are defined in config/shopper/core.php:
return [
    'roles' => [
        'admin' => 'administrator',
        'manager' => 'manager',
        'user' => 'user',
    ],
];

Components

php artisan shopper:component:publish customer
Creates config/shopper/components/customer.php:
use Shopper\Livewire;
use Shopper\Livewire\Components;

return [
    'pages' => [
        'customer-index' => Livewire\Pages\Customers\Index::class,
        'customer-create' => Livewire\Pages\Customers\Create::class,
        'customer-show' => Livewire\Pages\Customers\Show::class,
    ],
    'components' => [
        'customers.addresses' => Components\Customers\Addresses::class,
        'customers.orders' => Components\Customers\Orders::class,
        'customers.profile' => Components\Customers\Profile::class,
    ],
];

Storefront Example

namespace App\Http\Controllers;

use App\Models\User;
use Shopper\Core\Models\Address;
use Shopper\Core\Enum\GenderType;
use Shopper\Core\Enum\AddressType;
use Illuminate\Support\Facades\Hash;

class AccountController extends Controller
{
    public function show()
    {
        $customer = auth()->user();

        return view('account.show', [
            'customer' => $customer,
            'orders' => $customer->orders()->latest()->paginate(10),
            'addresses' => $customer->addresses,
        ]);
    }

    public function updateProfile(Request $request)
    {
        $validated = $request->validate([
            'first_name' => 'required|string|max:255',
            'last_name' => 'required|string|max:255',
            'phone_number' => 'nullable|string|max:20',
            'birth_date' => 'nullable|date',
            'opt_in' => 'boolean',
        ]);

        auth()->user()->update($validated);

        return back()->with('success', 'Profile updated successfully');
    }

    public function storeAddress(Request $request)
    {
        $validated = $request->validate([
            'first_name' => 'required|string',
            'last_name' => 'required|string',
            'street_address' => 'required|string',
            'city' => 'required|string',
            'postal_code' => 'required|string',
            'country_id' => 'required|exists:countries,id',
            'type' => 'required|in:billing,shipping',
        ]);

        auth()->user()->addresses()->create([
            ...$validated,
            'type' => AddressType::from($validated['type']),
        ]);

        return back()->with('success', 'Address added successfully');
    }
}

Use Cases

ScopeDescription
customers()Users with ‘user’ role
administrators()Users with ‘admin’ or ‘manager’ role
MethodDescription
isAdmin()Check if user has admin role
isManager()Check if user has manager role
isVerified()Check if email is verified