Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Addressing Laravel Package

sylius/addressing

Sylius Addressing component provides models and services to manage addresses, countries, and provinces (states). Includes a flexible zones system to group regions and match addresses to zones—useful for shipping and tax calculations in PHP eCommerce apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require sylius/addressing
    

    Add the bundle to config/bundles.php (if using Symfony) or register the service provider in config/app.php (Laravel).

  2. Database Migrations Run the migrations provided in vendor/sylius/addressing/migrations/ to create tables for:

    • country
    • province (optional, if using provinces/states)
    • zone (for grouping countries/provinces)
    • address (core model)
  3. First Use Case: Basic Address Storage

    use Sylius\Component\Addressing\Model\AddressInterface;
    use Sylius\Component\Addressing\Model\CountryInterface;
    
    // Create and persist an address
    $address = new Address();
    $address->setStreet('123 Main St');
    $address->setCity('New York');
    $address->setPostcode('10001');
    $address->setCountry($countryRepository->findOneBy(['code' => 'US']));
    $addressRepository->add($address);
    
  4. Where to Look First

    • Models: Sylius\Component\Addressing\Model\ for Address, Country, Province, and Zone.
    • Repositories: Sylius\Component\Addressing\Repository\ for CRUD operations.
    • Services: Sylius\Component\Addressing\Resolver\ for zone resolution (e.g., ZoneResolverInterface).
    • Fixtures: Predefined country/province data in vendor/sylius/addressing/Resources/fixtures/.

Implementation Patterns

Core Workflows

1. Address Management

  • Validation: Use Sylius\Component\Addressing\Validator\Constraints\ (e.g., ValidCountry, ValidPostcode).
    use Sylius\Component\Addressing\Validator\Constraints as AddressAssert;
    
    class AddressRequest {
        #[AddressAssert\ValidCountry]
        public string $countryCode;
    }
    
  • Serialization: Leverage Sylius\Component\Addressing\Serializer\ for JSON/API responses.
    $serializer = new AddressSerializer($addressRepository);
    $data = $serializer->serialize($address, 'json');
    

2. Zone-Based Logic

  • Zone Resolution: Check if an address belongs to a zone (e.g., for shipping/tax rules).
    $zoneResolver = $container->get('sylius.addressing.zone_resolver');
    $zones = $zoneResolver->getZonesForAddress($address);
    
  • Zone Membership: Define zones in YAML/DB (e.g., "US Shipping Zone" grouping US and CA).
    # config/packages/sylius_addressing.yaml
    sylius_addressing:
        zones:
            us_shipping:
                name: 'US Shipping Zone'
                members: ['US', 'CA']
    

3. Country/Province Hierarchy

  • Province Handling: Attach provinces to countries (e.g., US states).
    $country = $countryRepository->findOneBy(['code' => 'US']);
    $province = new Province();
    $province->setName('California');
    $province->setCode('CA');
    $province->setCountry($country);
    $provinceRepository->add($province);
    
  • Autocomplete: Use Sylius\Component\Addressing\Provider\CountryProviderInterface for dropdowns.
    $countries = $countryProvider->getAll();
    

4. Integration with Laravel

  • Service Binding: Bind Sylius services in AppServiceProvider.
    public function register() {
        $this->app->bind(
            \Sylius\Component\Addressing\Repository\CountryRepositoryInterface::class,
            \Sylius\Component\Addressing\Doctrine\ORM\CountryRepository::class
        );
    }
    
  • Eloquent Models: Extend Sylius models with Laravel traits (e.g., HasFactory).
    use Sylius\Component\Addressing\Model\Address as BaseAddress;
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    
    class Address extends BaseAddress {
        use HasFactory;
    }
    

5. API/Controller Layer

  • Resource Controllers: Use sylius/resource-bundle patterns for RESTful endpoints.
    class AddressController extends AbstractController {
        public function index(AddressRepository $repository): JsonResponse {
            return $this->json($repository->findAll());
        }
    }
    
  • Form Types: Reuse Sylius form types for validation.
    use Sylius\Component\Addressing\Form\Type\AddressType;
    
    $form = $this->createForm(AddressType::class, $address);
    

Gotchas and Tips

Pitfalls

  1. Zone Resolution Performance

    • Issue: Querying zones for every address can be slow if zones are complex.
    • Fix: Cache resolved zones or use a dedicated service to preload zones.
      $cachedZones = Cache::remember("address_zones_{$address->getId()}", now()->addHours(1), fn() =>
          $zoneResolver->getZonesForAddress($address)
      );
      
  2. Province-Only Countries

    • Issue: Some countries (e.g., US) require provinces, while others (e.g., Japan) don’t.
    • Fix: Use hasProvinces flag in Country model or validate dynamically.
      if ($country->hasProvinces() && !$address->getProvince()) {
          throw new \InvalidArgumentException('Province is required for this country.');
      }
      
  3. Postcode Validation

    • Issue: Postcode formats vary globally (e.g., 12345 vs. SW1A 1AA).
    • Fix: Use ValidPostcode constraint with country-specific rules or extend the validator.
      class CustomPostcodeValidator extends AbstractPostcodeValidator {
          protected function validatePostcode(string $postcode, CountryInterface $country): bool {
              // Custom logic for country-specific formats
          }
      }
      
  4. Zone Membership Ambiguity

    • Issue: Overlapping zones (e.g., an address in CA might belong to both US Shipping and North America zones).
    • Fix: Define explicit zone priorities or use a ZonePriorityResolver.
  5. Database Schema Conflicts

    • Issue: Custom address table columns may clash with Sylius migrations.
    • Fix: Extend the Address entity instead of overriding migrations.
      class Address extends BaseAddress {
          protected $customField;
      }
      

Debugging Tips

  1. Zone Debugging

    • Dump zone memberships for an address:
      dd($zoneResolver->getZonesForAddress($address)->map(fn($zone) => $zone->getName()));
      
  2. Country/Province Fixtures

    • Reset fixtures during development:
      php bin/console sylius:fixtures:load -e=dev
      
  3. Validation Errors

    • Check constraint violations:
      $validator = $this->validator;
      $errors = $validator->validate($address);
      dd($errors);
      

Extension Points

  1. Custom Zone Resolvers

    • Implement ZoneResolverInterface for business-specific logic (e.g., "Free Shipping Zone").
      class CustomZoneResolver implements ZoneResolverInterface {
          public function getZonesForAddress(AddressInterface $address): array {
              // Custom resolution logic
          }
      }
      
  2. Address Events

    • Listen to address.pre_persist or address.post_remove events for side effects.
      $dispatcher->addListener(
          AddressEvents::PRE_PERSIST,
          fn(AddressEvent $event) => $this->logAddressCreation($event->getAddress())
      );
      
  3. Provider Extensions

    • Override CountryProvider or ProvinceProvider to fetch data from an external API.
      class ApiCountryProvider implements CountryProviderInterface {
          public function getAll(): array {
              return $this->apiClient->fetchCountries();
          }
      }
      
  4. Serializer Normalization

    • Extend AddressSerializer to include custom fields.
      class CustomAddressSerializer extends AddressSerializer {
          public function normalize($address, $format = null, array $context = []): array {
              $data = parent::normalize($address, $format, $context);
              $data['custom_field'] = $address->getCustomField();
              return $data;
          }
      }
      
  5. Zone Membership Strategies

    • Replace the default ZoneMember logic (e.g., for IP-based zones).
      class IpZoneMember implements ZoneMemberInterface {
          public function isMemberOfZone(AddressInterface $address
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
craftcms/url-validator
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony