bitbag / vuestorefront-plugin
BitBag VueStorefront bridge for Sylius.
Installs: 8 210
Dependents: 0
Suggesters: 0
Security: 0
Stars: 45
Watchers: 18
Forks: 24
Open Issues: 0
Type:sylius-plugin
Requires
- php: ^7.3
- ext-json: *
- friendsofsymfony/elastica-bundle: ^5.1
- gesdinet/jwt-refresh-token-bundle: ^0.8
- imagine/imagine: ^1.2
- lexik/jwt-authentication-bundle: ^2.6
- nelmio/cors-bundle: ^1.5
- ruflin/elastica: ^6.1
- sylius/sylius: ^1.8
- symfony/messenger: ^4.4
- symfony/property-info: ^4.4
- symfony/serializer: ^4.4 || ^5.0
Requires (Dev)
- lchrusciel/api-test-case: ^4.1
- phpspec/phpspec: ^6.1
- phpstan/phpstan: ^0.12
- phpstan/phpstan-doctrine: ^0.12
- phpstan/phpstan-symfony: ^0.12
- phpstan/phpstan-webmozart-assert: ^0.12
- phpunit/phpunit: ^8.5
- roave/security-advisories: dev-master
- sensiolabs/security-checker: ^5.0
- sylius-labs/coding-standard: ^2.0
- symfony/browser-kit: ^4.4
- symfony/debug-bundle: ^4.4
- symfony/dotenv: ^4.4
- symfony/intl: ^4.4
- symfony/web-profiler-bundle: ^4.4
- symfony/web-server-bundle: ^4.4
Suggests
- nelmio/cors-bundle: Allows you to send Cross-Origin Ajax API requests
Conflicts
- symfony/browser-kit: 4.1.8
- symfony/dependency-injection: 4.1.8
- symfony/dom-crawler: 4.1.8
- symfony/routing: 4.1.8
- symfony/symfony: 4.1.8
This package is auto-updated.
Last update: 2024-10-10 15:07:50 UTC
README
⚠️ BEWARE! The current solution is deprecated as it was created for Vue Storefront v1. For Vue Storefront 2 integration check out our GraphQL-based integration, which could be found here:
https://github.com/BitBagCommerce/SyliusGraphQLPlugin
https://github.com/vuestorefront-community/sylius
If you want to know more about the new integration, read our blog -> https://bitbag.io/blog/introduction-to-vue-storefront-2sylius-integration-technical-aspects
BitBag SyliusVueStorefrontPlugin
At BitBag we do believe in open source. However, we are able to do it just because of our awesome clients, who are kind enough to share some parts of our work with the community. Therefore, if you feel like there is a possibility for us working together, feel free to reach us out. You will find out more about our professional services, technologies and contact details at https://bitbag.io/.
Table of Content
- Overview
- Support
- Installation
- Using the plugin within Sylius Standard app, with VSF
- Known issues
- Extending the plugin
- About us
- Demo Sylius shop
- Additional Sylius resources for developers
- License
- Contact
Overview
This document assumes that you are already familiar with Vue Storefront and its technology stack.
If that's not the case please check VSF Documentation and GitHub repository.
Please also check Sylius Documentation and Sylius-Standard if you are new to Sylius.
Depending on your preferences, the plugin can also fully replace VSF API - you will only need VSF front app if you choose so.
Sylius ShopBundle is also no longer needed as Vue Storefront will be your new ... Storefront. :)
We are here to help
This open-source plugin was developed to help the Sylius community. If you have any additional questions, would like help with installing or configuring the plugin or need any assistance with your Sylius project - let us know!
Installation
Supported versions
Requirements
We work on stable, supported and up-to-date versions of packages. We recommend you to do the same.
Please also check Vue Storefront requirements.
Important note
Please inspect files stored in tests/Application
directory (especially config
subdirectory)
to make sure that you fully understand installation steps written below.
We recommend you to disable Sylius ShopBundle as you will no longer need it.
Please refer to Sylius Documentation - How to disable Sylius shop? for details.
First, add this plugin as dependency to your Sylius project.
$ composer require bitbag/vuestorefront-plugin:v2.1.1
Add the plugin to config/bundles.php
(if it's not there already):
return [
...
FOS\ElasticaBundle\FOSElasticaBundle::class => ['all' => true],
BitBag\SyliusVueStorefrontPlugin\SyliusVueStorefrontPlugin::class => ['all' => true],
Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
Gesdinet\JWTRefreshTokenBundle\GesdinetJWTRefreshTokenBundle::class => ['all' => true],
// Optional, for handling CORS (Cross-Origin Resource Sharing) requests
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
];
Add few variables to your .env file:
APP_CHANNEL_CODE="<code of Sylius channel you want to use>"
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=bitbag
ELASTICSEARCH_HOST=localhost
ELASTICSEARCH_PORT=9200
ELASTICSEARCH_INDEX=vue_storefront_catalog
// Set transport value to "https" and ssl to "true" when using an ssl connection
ELASTICSEARCH_TRANSPORT=http
ELASTICSEARCH_SSL=false
// Leave blank if authentication is not required
ELASTICSEARCH_USERNAME=
ELASTICSEARCH_PASSWORD=
// Optionally, when using Nelmio CORS Bundle
CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$
To generate JWT public and secret keys please run commands below in Sylius' project directory:
$ mkdir -p config/jwt
$ openssl genpkey -out config/jwt/private.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096
$ openssl pkey -in config/jwt/private.pem -out config/jwt/public.pem -pubout
Then set value of JWT_PASSPHRASE
environment variable with passphrase that you've entered during running commands above.
Next step is to add a following line to the end of the imports
section in your config/packages/_sylius.yaml
:
- { resource: "@SyliusVueStorefrontPlugin/Resources/config/config.yaml" }
It's needed to load some plugin configuration.
Now it is needed to edit config/packages/security.yaml
file.
Add a line below to parameters
key at the top of the file:
bitbag.vue_storefront.security.regex: "^/vsbridge"
Add a code below to the top of security -> firewalls
key (an order is really important there):
vs_bridge_user_login:
pattern: "%bitbag.vue_storefront.security.regex%/user/login"
stateless: true
anonymous: true
provider: sylius_shop_user_provider
json_login:
provider: sylius_shop_user_provider
check_path: /vsbridge/user/login
password_path: password
success_handler: bitbag_sylius_vue_storefront_plugin.lexik_jwt_authentication.handler.authentication_success
failure_handler: bitbag_sylius_vue_storefront_plugin.lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
vs_bridge:
pattern: "%bitbag.vue_storefront.security.regex%"
stateless: true
anonymous: true
provider: sylius_shop_user_provider
guard:
provider: sylius_shop_user_provider
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
So it should look like this:
firewalls:
vs_bridge_user_login:
pattern: "%bitbag.vue_storefront.security.regex%/user/login"
stateless: true
anonymous: true
provider: sylius_shop_user_provider
json_login:
provider: sylius_shop_user_provider
check_path: /vsbridge/user/login
password_path: password
success_handler: bitbag_sylius_vue_storefront_plugin.lexik_jwt_authentication.handler.authentication_success
failure_handler: bitbag_sylius_vue_storefront_plugin.lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
vs_bridge:
pattern: "%bitbag.vue_storefront.security.regex%"
stateless: true
anonymous: true
provider: sylius_shop_user_provider
guard:
provider: sylius_shop_user_provider
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
Afterwards add a line below to security -> access_control
part:
- { path: "%bitbag.vue_storefront.security.regex%/user/login", role: IS_AUTHENTICATED_ANONYMOUSLY }
Now go to config/routes.yaml
file in your Sylius app and paste there:
sylius_vue_storefront_plugin:
resource: "@SyliusVueStorefrontPlugin/Resources/config/routing.yaml"
to load configuration of all routes for API endpoints.
Create new file gesdinet_jwt_refresh_token.yaml
(or name it however you like) inside config/packages
directory and paste inside it:
gesdinet_jwt_refresh_token:
firewall: vs_bridge
token_parameter_name: refreshToken
user_provider: sylius_shop_user_provider
Replace content of your config/packages/lexik_jwt_authentication.yaml
file with the following configuration:
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_extractors:
query_parameter:
enabled: true
name: token
Afterwards add:
translator: { fallbacks: ["%locale%"] }
under your framework
key in config/packages/framework.yaml
so it should look like this afterwards:
framework:
translator: { fallbacks: ["%locale%"] }
secret: '%env(APP_SECRET)%'
form: true
csrf_protection: true
templating: { engines: ["twig"] }
session:
handler_id: ~
Set content of your config/fos_elastica.yaml
to the following:
imports:
- { resource: "@SyliusVueStorefrontPlugin/Resources/config/indexes/attribute.yaml" }
- { resource: "@SyliusVueStorefrontPlugin/Resources/config/indexes/category.yaml" }
- { resource: "@SyliusVueStorefrontPlugin/Resources/config/indexes/product.yaml" }
fos_elastica:
clients:
default: { host: '%env(ELASTICSEARCH_HOST)%', port: '%env(ELASTICSEARCH_PORT)%' }
Add a following rule to fos_rest.format_listener.rules
in your config/packages/fos_rest.yaml
- { path: '^/vsbridge/.*', priorities: ['json', 'xml'], fallback_format: json, prefer_extension: true }
For example the file should look like this afterwards:
fos_rest:
exception: true
view:
formats:
json: true
xml: true
empty_content: 204
format_listener:
rules:
- { path: '^/api/.*', priorities: ['json', 'xml'], fallback_format: json, prefer_extension: true }
- { path: '^/vsbridge/.*', priorities: ['json', 'xml'], fallback_format: json, prefer_extension: true }
- { path: '^/', stop: true }
Go to your src/Entity/Order/OrderItem.php
file and make it to extend the OrderItem
entity from our plugin.
Change:
use Sylius\Component\Core\Model\OrderItem as BaseOrderItem;
to:
use BitBag\SyliusVueStorefrontPlugin\Sylius\Entity\Order\OrderItem as BaseOrderItem;
Copy etc/vsf-config/local.json
file from this repository to config/local.json
of Vue Storefront project directory.
In that file you only need to replace every occurence of <insert-your-hostname>
with URL of your store.
You don't have to change anything else as sensible defaults are provided by us, that are proven to work in Vue Storefront v1.12.
If your configuration settings differ from defaults provided with the plugin and you run into problems don't hesitate to create issue on GitHub or contact us directly at hello@bitbag.io.
Architecture
VueStorefront fetches data in two ways - statically and dynamically.
Less frequently updated data is stored in Elasticsearch:
- Products
- Categories (Sylius taxons)
- Attributes (Sylius product options)
Everything else is fetched dynamically using provided API, including:
- customers' accounts (Sylius Customer, ShopUser)
- carts, orders (Sylius Order)
- shipping methods
- payment methods
- and more ...
Elasticsearch
Everything related to Elasticsearch is contained within Elastisearch
with the exception of FOS Elastica Bundle configuration which can be found in src/Resources/config/indexes
directory.
To have the data from Sylius mapped in ES, we have created Transformer
s providing object translations to ES indexes.
Schema of indexes is described in files stored in Document
directory.
It's important to note once again that only Elasticsearch 6 is fully supported currently.
Support for ES 7 is on the way - once ruflin/elastica and FOSElasticaBundle start supporting it, we will as well.
Using the plugin within Sylius Standard app, with VSF
It is no surprise that you must have products, taxons etc. within your Sylius instance to benefit from VSF.
Therefore we assume that you have a shop already running.
If it's not the case you might want to run commands below on freshly cloned Sylius Standard repository:
$ composer install
$ yarn install
$ yarn build
$ php bin/console doctrine:database:create
$ php bin/console doctrine:schema:update --force
$ php bin/console sylius:fixtures:load
.. to add all needed entities from fixtures to database.
Only then you can run
$ php bin/console fos:elastica:populate
to populate Elasticsearch indexes and let refresher contained within the plugin to automatically update the data in ES in real time.
Known issues
Translatable trait error during loading fixtures
In case of this error - to be able to load the fixtures, go to the vendor/bitbag/vuestorefront-plugin/src/Resources/config/indexes/product.yaml
file and comment last line in there (the defer:true
one).
Then clear the cache, load fixtures and uncomment this line afterwards.
Getting 500 error related to taxa (taxons
)
If you see something like this for example in your admin panel:
{
"result": "Variable \"taxons\" does not exist.",
"code": 500
}
it means you are using invalid version of doctrine/inflector
package.
To fix it add a following block into your composer.json
file:
"conflict": {
"doctrine/inflector": "^1.4"
},
Make sure that
"bitbag/vuestorefront-plugin": "v2.1.1"
is present in require
section in your composer.json
file and then run:
$ composer update
Extending the plugin
Extending requests, commands/queries
The easiest way to extend the existing request classes and add new properties is to inherit from them.
Because of the way we denormalize incoming requests, you don't need constructor in that class.
You must only:
- add public properties to the class
- override
getCommand()
orgetQuery()
method
Optionally you may want to add constraint to your properties that would validate incoming data.
We use separate .xml files for that as you can see in src/Resources/config/validation
directory.
For example let's add locale to the coupon:
use BitBag\SyliusVueStorefrontPlugin\Request\Cart\ApplyCouponRequest;
final class ApplyLocalizedCouponRequest extends ApplyCouponRequest
{
/** @var string */
pubic $locale;
public function getCommand(): CommandInterface
{
return new ApplyCoupon($this->token, $this->cartId, $this->coupon, $this->locale);
}
}
In the same manner the command would need to be created extending the ApplyCoupon class.
Then you only need to change one parameter in the configuration file:
bitbag_sylius_vue_storefront_plugin:
request_classes:
apply_coupon: \AddLocalizedCouponRequest
Extending handlers
The main way to extend a handler is to decorate it. This makes adding functionality before and after the handler easy.
Please check example of extending view below and/or follow Symfony Documentation - How to Decorate Services guide.
However, if you want to change the logic in the handler, you need to overwrite it.
This can be done by registering the new handler with the same service id.
Do not just add it with a new service id otherwise, it will execute both handlers.
Extending views
When extending the views, two places need to be modified - view class and view factory.
ViewFactories should be decorated just like Handlers mentioned above. You can also completely override them if you prefer to do so.
use BitBag\SyliusVueStorefrontPlugin\Factory\Cart\Totals\TotalsViewFactoryInterface;
class NiceTotalViewFactory implements TotalViewFactoryInterface
{
private $innerTotalViewFactory;
public function __construct(TotalsViewFactoryInterface $innerTotalViewFactory)
{
$this->innerTotalViewFactory = $innerTotalViewFactory;
}
public function create(OrderInterface $order): NiceTotalView
{
/** @var NiceTotalView $totalView */
$totalView = $this->innerTotalViewFactory->createNew();
$totalView->nicePersonDiscount = $orderInterface->getNiceDiscount();
return $totalView;
}
}
You need to define this service in xml (or yaml) file:
<service class="NiceTotalView" id="app.factory.nice_total_view_factory"
decorates="bitbag_sylius_vue_storefront_plugin.factory.cart.totals.totals_view_factory">
<argument type="service" id="app.factory.nice_total_view_factory.inner" />
</service>
and change the view class in configuration file:
bitbag_sylius_vue_storefront_plugin:
view_classes:
totals: \NiceTotalView
About us
BitBag is an agency that provides high-quality eCommerce and Digital Experience software. Our main area of expertise includes eCommerce consulting and development for B2C, B2B, and Multi-vendor Marketplaces. The scope of our services related to Sylius includes:
- Consulting in the field of strategy development
- Personalized headless software development
- System maintenance and long-term support
- Outsourcing
- Plugin development
- Data migration
Some numbers regarding Sylius:
- 20+ experts including consultants, UI/UX designers, Sylius trained front-end and back-end developers,
- 100+ projects delivered on top of Sylius,
- Clients from 20+ countries
- 3+ years in the Sylius ecosystem.
If you need some help with Sylius development, don't be hesitate to contact us directly. You can fill the form on this site or send us an e-mail to hello@bitbag.io!
Community
For online communication, we invite you to chat with us & other users on Sylius Slack.
Vue Storefront + Sylius Demo
We've created a demo app that showcases usage of this plugin. Visit vsf.bitbag.shop to check it out!
The Sylius admin panel is accessible at syliusvsf.bitbag.shop/admin. Admin credentials: sylius : sylius
.
If you need an overview of this plugin, schedule a consultation with our expert.
Additional resources for developers
To be able to contribute to the plugin make sure that you familiarize yourself with:
- Vue Storefront Integration SDK
- Vue Storefront
- Vue Storefront API
- Sylius Shop API Plugin
- Sylius Contribution Guide
Additionally you might want to get to know VSF better:
- Vue Storefront Documentation - to learn how to customize VSF frontend part
- Vue Storefront Journal - blog where new ideas are shared and what lies ahead is announced
License
This plugin's source code is completely free and released under the terms of the MIT license.
Contact
If you want to contact us, the best way is to fill the form on our website or send us an e-mail to hello@bitbag.io with your question(s). We guarantee that we answer as soon as we can!