comsa / sulu-shopping-cart
Requires
- php: ^8.0
- dantleech/phpcr-migrations-bundle: ^1.2
- doctrine/orm: >=2.0
- mollie/mollie-api-php: ^2.0
- phpoffice/phpspreadsheet: ^1.21
- sulu/sulu: ^2.0
- symfony/config: ^4.3 || ^5.0
- symfony/dependency-injection: ^4.3 || ^5.0
- symfony/event-dispatcher: ^4.3 || ^5.0
- symfony/form: ^4.3 || ^5.0
- symfony/http-foundation: ^4.3 || ^5.0
- symfony/http-kernel: ^4.3 || ^5.0
- symfony/mailer: ^4.3 || ^5.0
- twig/twig: >=2.0 || ^3.0
Requires (Dev)
- jackalope/jackalope-doctrine-dbal: ^1.3.4
- jackalope/jackalope-jackrabbit: ^1.3
- phpcr/phpcr-shell: ^1.1
- dev-master
- 4.3.1
- 4.3.0
- 4.2.2
- 4.2.1
- 4.2.0
- 4.1.1
- 4.1.0
- 4.0.0
- 3.3.1
- 3.3.0
- 3.2.11
- 3.2.10
- 3.2.9
- 3.2.8
- 3.2.7
- 3.2.6
- 3.2.5
- 3.2.4
- 3.2.3
- 3.2.2
- 3.2.1
- 3.2.0
- 3.1.17
- 3.1.16
- 3.1.15
- 3.1.14
- 3.1.13
- 3.1.12
- 3.1.11
- 3.1.10
- 3.1.9
- 3.1.8
- 3.1.7
- 3.1.6
- 3.1.5
- 3.1.4
- 3.1.3
- 3.1.2
- 3.1.1
- 3.1.0
- 3.0.2
- 3.0.1
- 3.0.0
- 2.4.8
- 2.4.7
- 2.4.6
- 2.4.5
- 2.4.4
- 2.4.3
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.1
- 2.3.0
- 2.2.1
- 2.2.0
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.0
- 1.1.1
- 1.1.0
- 1.0.0
This package is auto-updated.
Last update: 2024-12-19 19:40:54 UTC
README
composer req comsa/sulu-shopping-cart
Add to assets/admin/package.json
:
"sulu-shopping-cart-bundle": "file:node_modules/@sulu/vendor/comsa/sulu-shopping-cart/Resources/js"
Run npm install
Add it to assets/admin/app.js
:
import 'sulu-shopping-cart-bundle/admin'
And build it using npm run build
, this might take a while :)
Setup the frontend js: Add it to package.json:
"sulu-shopping-cart-bundle": "file:../../vendor/comsa/sulu-shopping-cart/Resources/js"
Add it to index.js:
import 'sulu-shopping-cart-bundle/website';
And build it using npm run build
or use npm run dev
in development
Add routes to both routes_admin.yaml
and routes_website.yaml
In: config/packages/doctrine.yaml
doctrine:
orm:
mappings:
SuluShoppingCartBundle:
is_bundle: true
type: attribute
dir: '/Entity'
prefix: 'Comsa\SuluShoppingCart\Entity'
alias: SuluShoppingCart
In: config/routes_admin.yaml
sulu_shopping_cart_admin:
type: rest
resource: "@SuluShoppingCartBundle/Resources/config/routes/admin.yaml"
prefix: /admin/api
sulu_shopping_cart_admin_controller:
resource: "@SuluShoppingCartBundle/Resources/config/routes/adminController.yaml"
In: config/routes_website.yaml
sulu_shopping_cart_website:
resource: "@SuluShoppingCartBundle/Resources/config/routes/website.yaml"
Default configuration
Adjust to your wishes
parameters:
#Configure the correct value in the .env file
comsa_sulu_shopping_mollie_api_key: '%env(COMSA_SC_MOLLIE_API_KEY)%'
Make sure your product template is called "comsa_product".
<property name="product" type="single_product_selection">
<meta>
<title lang="en">Product</title>
<title lang="nl">Product</title>
</meta>
</property>
Add the following to your product template, this will render the add to cart part:
{{ render(controller('Comsa\\SuluShoppingCart\\Controller\\CartController::addToCart', {'uuid': id})) }}
To add the cart somewhere, use the following, you can overwrite this template from within your own templates:
{% include '@SuluShoppingCart/cart-small.html.twig' %}
Extending Entities
Create an CartItem.php class in src/entity.
<?php
declare(strict_types=1);
namespace App\Entity;
use Comsa\SuluShoppingCart\Entity\CartItem as BaseCartItem;
use Doctrine\ORM\Mapping\Entity;
#[Entity()]
class CartItem extends BaseCartItem
{
}
Create an Order.php in src/entity:
<?php
namespace App\Entity;
use Comsa\SuluShoppingCart\Entity\Order as BaseOrder;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Order extends BaseOrder
{
}
Here you can define custom properties.
For example:
<?php
namespace App\Entity;
use Comsa\SuluShoppingCart\Entity\CartItem as BaseCartItem;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class CartItem extends BaseCartItem
{
/**
* @ORM\Column(type="text", length=6000, nullable=true)
*/
private $accessoryText;
public function getAccessoryText(): ?string
{
return $this->accessoryText;
}
public function setAccessoryText(?string $accessoryText)
{
$this->accessoryText = $accessoryText;
}
}
Make sure to apply the Symfony coding standards and the namespaces are correct as shown above.
After extending your entities update your database:
php bin/console doctrine:schema:update -f
Extending Forms
Extend the basic forms with your custom properties by extending the forms.
For example:
<?php
namespace App\Form\Extension;
use Comsa\SuluShoppingCart\Form\AddToCartType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
class AddToCartTypeExtension extends AbstractTypeExtension
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add("accessoryText", TextType::class);
}
public static function getExtendedTypes(): iterable
{
return [
AddToCartType::class
];
}
}
Make sure the namespaces are correct as shown above.
Loading Settings
To configure paymentmethods and shipmentmethods, settings need to be loaded.
Copy and paste the following inside AppFixtures.php in App\DataFixtures
<?php
namespace App\DataFixtures;
use Comsa\SuluShoppingCart\DataFixtures\AppSeed;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class AppFixtures extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager)
{
}
public function getDependencies(): array
{
return [
AppSeed::class
];
}
}
Run the following command to load in the settings:
php bin/console doctrine:fixtures:load --append
Make sure they are configured correctly to your needs.
Translations
Extended properties are automatically rendered in the order summary.
Translations can be made inside the translations/sulu
folder in the root of the app. Name of the file should be admin.{locale}.yaml
.
For Example:
properties:
accessoryText: "Tekst op kaart"
Make sure to enter all custom properties under the properties
namespace as shown above.
Templates (optional)
Product overview XML:
<?xml version="1.0" ?>
<type name="product_overview" xmlns="http://schemas.sulu.io/template/template"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xi="http://www.w3.org/2001/XInclude"
xsi:schemaLocation="http://schemas.sulu.io/template/template http://schemas.sulu.io/template/template-1.0.xsd">
<meta>
<title lang="en">Product Overview</title>
<title lang="nl">Product Overzicht</title>
</meta>
<properties>
<property name="products" type="smart_content">
<meta>
<title lang="en">Products</title>
<title lang="nl">Producten</title>
</meta>
<params>
<param name="provider" value="pages"/>
<param name="max_per_page" value="16"/>
<param name="page_parameter" value="page"/>
<param name="properties" type="collection">
<param name="title" value="title"/>
<param name="text" value="text"/>
<param name="product" value="product"/>
<param name="images" value="images"/>
<param name="rating" value="rating"/>
<param name="description" value="description"/>
<param name="imageFormat" value="imageFormat"/>
<param name="location" value="location"/>
<param name="sold" value="sold"/>
<param name="licence" value="licence"/>
<param name="price" value="price"/>
<param name="btntext" value="btntext"/>
<param name="status" value="status"/>
</param>
</params>
</property>
</properties>
</type>
Product overview TWIG
<section class="product-overview">
<div class="row gx-5">
{% for page in block.products %}
{% set product = page.product %}
{% if product.thumbnail %}
{% set thumbnail = sulu_resolve_media(product.thumbnail, app.request.locale) %}
{% else %}
{% set thumbnail = false %}
{% endif %}
<article class="col-12 col-sm-6 col-xl-3">
<div class="card mx-auto my-2">
<div class="image-wrapper">
{% if thumbnail %}
<img src="{{ thumbnail.formats['x380_default'] }}" class="card-img-top" alt="{{ product.title }}" title="{{ product.title }}">
{% else %}
<p>{{ 'comsa_sulu_shopping_cart.no_thumbnail'|trans }}</p>
{% endif %}
</div>
<div class="card-body">
<h5 class="card-title">{{ product.title }}</h5>
<h6 class="card-title">€{{ product.price|number_format(2) }}</h6>
<a href="{{ sulu_content_path(page.url) }}" class="btn btn-primary">Bekijk product</a>
</div>
</div>
</article>
{% endfor %}
{% if pagination is defined and pagination == true %}
<nav class="mt-3" aria-label="{{ 'label.paginering'|trans|capitalize }} ">
{% set page = viewLink.page %}
<ul class="pagination {% if page -1 < 1 %} justify-content-end {% endif %}">
{% if page-1 >= 1 %}
<li class="page-item">
<a class="page-link" href="{{ sulu_content_path(content.url) }}?page={{ page-1 }}" aria-label="Previous">
<span aria-hidden="true">«</span>
<span>{{ 'label.previous'|trans|capitalize }}</span>
</a>
</li>
{% endif %}
{% if viewLink.hasNextPage %}
<li class="page-item">
<a class="page-link" href="{{ sulu_content_path(content.url) }}?page={{ page+1 }}" aria-label="Next">
<span>{{ 'label.next'|trans|capitalize }}</span>
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</section>
Product Page HTML
{% extends "base.html.twig" %}
{% block content %}
{% set product = content.product %}
<div class="product-details-wrapper">
<div class="container">
<div class="row py-5">
{% if product.thumbnail %}
<div class="col-md-6">
{% set thumbnail = sulu_resolve_media(product.thumbnail, app.request.locale) %}
<div class="product-thumbnail-wrapper">
<img class="product-thumbnail" src="{{ thumbnail.formats['default'] }}" alt="{{ product.title }}"
title="{{ product.title }}">
</div>
</div>
{% else %}
<div class="col-md-6">
<div class="product-thumbnail-wrapper img-thumbnail d-flex align-items-center justify-content-center">
<p>Geen foto beschikbaar</p>
</div>
</div>
{% endif %}
<div class="col-md-6 mt-3 d-flex">
<div class="mx-auto product-info">
<h1>{{ product.title }}</h1>
{% if product.code %}
<p class="text-muted " style="font-size: 0.8rem;"> {{ 'comsa_sulu_shopping_cart.code'|trans }}
: {{ product.code }}</p>
{% endif %}
{% if product.description %}
{{ product.description|raw }}
{% else %}
{{ 'comsa_sulu_shopping_cart.no_description'|trans }}
{% endif %}
<div class="products">
<p class="price">
<span>€{{ product.price|number_format(2) }}</span>
</p>
</div>
{% if product.followStock %}
{% if product.stock > 0 %}
{{ render(controller('Comsa\\SuluShoppingCart\\Controller\\CartController::addToCart', {'uuid': id})) }}
{% else %}
<div class="alert alert-danger" role="alert">
{{ 'comsa_sulu_shopping_cart.not_available'|trans }}
</div>
{% endif %}
{% else %}
{{ render(controller('Comsa\\SuluShoppingCart\\Controller\\CartController::addToCart', {'uuid': id})) }}
{% endif %}
</div>
</div>
{% include 'blocks/all.html.twig' with { 'blocks': content.extendedBlocks } %}
</div>
</div>
</div>
{% endblock %}
Importing Products
Products can be imported with the following command:
comsa:shopping:import-products <inputfile> <parent-page-id> <webspace-key> <locale>
The arguments represent the following:
InputFile Requirements
- File must be an Xlsx file.
- Inputfile argument must have the full path to file (eg. public/uploads/files/products.xlsx).
- Products must start on the second row.
- File must have the following structure:
A | B | C | D | E | F | G | H | |
---|---|---|---|---|---|---|---|---|
1 | Product Code | Category | Title | Description | Price | Unit | Follow Stock | Stock |
2 | PRODUCTS START |
InputFile Field Requirements
Field | Required | Requirements |
---|---|---|
Product Code | False | Max length: 255 |
Category | True | / |
Title | True | Max length: 255 |
Description | False | Max length: 65534 |
Price | True | Must be in euro (eg. €22,70) |
Unit | True |
Must be:
|
Follow Stock | True | Must be "yes" or "no" |
Stock | False | Only integers |