ShopBundle
Shop Bundle for eCommerce with Symfony, (*1)
BUNDLE UNDER DEVELOPMENT, USE AT YOUR OWN RISKS, (*2)
With is bundle, you'll be able to manage a shop + crowdfunding., (*3)
 Installation
First, launch composer require c975l/shop-bundle
to install the bundle., (*4)
Create database tables : php bin/console make:migration
and php bin/console doctrine:migrations:migrate
., (*5)
Crreate a private
at your root level and add it to your .gitignore
file., (*6)
Configuration
The bundle relies on the use of App\Entity\User
. If you haven't, create it with php bin/console make:user
. Then add one and give it ROLE_ADMIN
. You can use php bin/console security:hash-password
to hash the password., (*7)
Create a login form/logout route: php bin/console make:security:form-login
. Then adapt `` to your needs., (*8)
Add the following configuration in the different files:, (*9)
# config/packages/security.yaml
security:
firewalls:
main:
logout:
path: app_logout
access_control:
- { path: ^/shop/management, roles: ROLE_ADMIN }
# config/packages/vich_uploader.yaml
vich_uploader:
db_driver: orm
metadata:
type: attribute
mappings:
products:
uri_prefix: '' # path added in ShopMediaNamer
upload_destination: '%kernel.project_dir%/public/medias/shop/products'
namer: c975L\ShopBundle\Namer\ShopMediaNamer
inject_on_load: false
delete_on_update: true
delete_on_remove: true
productItems:
uri_prefix: '' # path added in ShopMediaNamer
upload_destination: '%kernel.project_dir%/public/medias/shop/items'
namer: c975L\ShopBundle\Namer\ShopMediaNamer
inject_on_load: false
delete_on_update: true
delete_on_remove: true
crowdfundings:
uri_prefix: '' # path added in ShopMediaNamer
upload_destination: '%kernel.project_dir%/public/medias/shop/crowdfundings'
namer: c975L\ShopBundle\Namer\ShopMediaNamer
inject_on_load: false
delete_on_update: true
delete_on_remove: true
crowdfundingsCounterparts:
uri_prefix: '' # path added in ShopMediaNamer
upload_destination: '%kernel.project_dir%/public/medias/shop/counterparts'
namer: c975L\ShopBundle\Namer\ShopMediaNamer
inject_on_load: false
delete_on_update: true
delete_on_remove: true
# config/routes.yaml
c975_l_shop:
resource: "@c975LShopBundle/"
type: attribute
prefix: /
Create a Stripe account if not: https://stripe.com, (*10)
- Sign in to your Stripe Dashboard
- Navigate to Developers > Webhooks
- Click "Add endpoint"
- Enter your webhook URL (https://your-website.com/shop/stripe/webhook)
- Select the event
checkout.session.completed
- Copy the webhook signing secret and add it to your environment variables
config/config_bundles.yaml
-> stripeWebhookSecret
- Test the endpoint to ensure proper configuration
This webhook allows Stripe to notify your application when payments are completed, ensuring order processing even if customers close their browser after payment., (*11)
Create the configuration file config/config_bundles.yaml
with these settings:, (*12)
c975LShop:
name: 'My Shop' # Name of the shop
roleNeeded: 'ROLE_ADMIN' # Role needed to access shop management
from: 'contactp@example.com' # Email address for sending emails
fromName: 'My Shop' # Sender name
replyTo: 'contact@example.com' # Reply-to email address
replyToName: 'My Shop' # Reply-to name
currency: 'eur' # ISO currency code
shipping: 500 # Shipping cost in cents (5.00)
shippingFree: 10000 # Free shipping threshold (100.00)
sitemapBaseUrl: 'https://example.com' # Base URL for sitemap
stripeSecret: 'STRIPE_SECRET' # Stripe secret key
stripeWebhookSecret: 'STRIPE_WEBHOOK_SECRET' # Stripe webhook secret
touUrl: 'https://example.com/terms-of-use' # Terms of use URL
tosUrl: 'https://example.com/terms-of-sales' # Terms of sales URL
In assets/bootstrap.js
, add the following code:, (*13)
import c975lShopBasket from '/bundles/c975lshop/js/basket.js';
app.register('basket', c975lShopBasket);
Launch configuration process php bin/console config:create
., (*14)
CSP
Adapts your CSP to allow:, (*15)
script-src: 'unsafe-inline'
et form-action '*'
, (*16)
CSS
Add @import url("/bundles/c975lshop/css/styles.min.css");
to your assets/app.css
file., (*17)
Urls
You should be able to use your shop + Management with the following urls:, (*18)
- Shop https://example.com/shop
- Management: https://example.com/shop/management
Useful Commands
The basket.contentflags
has 3 values: 1 (digital), 2 (both) and 3 (physical)., (*19)
The basket.status
are the following: new, validated, paid, downloaded, shipped, finished, (*20)
Run this Command php bin/console shop:downloads:delete
once a day to delete files made available at download., (*21)
Run this Command php bin/console shop:products:position
once a day to correct position and keep a 5 gap between them., (*22)
Run this Command php bin/console shop:baskets:delete
once a day to delete unvalidated baskets (status new and creation > 14 days)., (*23)
For creating the sitemap, you can run php bin/console shop:sitemaps:create
thath will give a public/sitemap-shop.xml
that you can add to your sitemap-index.xml
file or run the following:, (*24)
//Creates the sitemap for pages managed by Shop
public function createSitemapShop($output)
{
$command = $this->getApplication()->find('shop:sitemaps:create');
$inputArray = new ArrayInput([]);
$command->run($inputArray, $output);
}
Entities structure and nesting
- Product [Collection]
- ProductMedia [Collection]
- ProductItem [Collection]
- ProductItemMedia [One]
- ProductItemFile [One]
, (*25)
TODO
In src/Listener/ProductItemListener.php
we need to create an empty ProductItemMedia|ProductItemFile
if none is added, otherwise we can't add one afterwards. The physical ProdutItemMedia is not deleted when the ProductItem is deleted, but the link is removed. See ProductItemListener->prePersist()
. Furthermoe, need to create ProductItem without Meida/File first., (*26)
A Command has been made to remove those files, simply run (and/or add incrontab) php bin/console shop:media:delete
., (*27)