Sylius: Multi-channel on same host with different path

Created on 19 Aug 2016  ·  39Comments  ·  Source: Sylius/Sylius

Hi guys!

As always, thank you for your amazing work. Today, i have a strange request for a project. :)

For a customer, our company has to set multi-channel on same host but with different path.

For example, with an e-commerce platform host ecommerce.com, our customer needs:

Store EN -> ecommerce.com/en/....
Store IT -> ecommerce.com/it/....
Store PL -> ecommerce.com/pl/

My question is:
It is possible to discriminate more channel on the same host, but with different initial path?

Thank you,
Dan

DX Do not stale Documentation

Most helpful comment

@CoderMaggie The need is to have this work:

website.nl/directory -> channel 1
website.nl/another-directory -> channel 2

All 39 comments

Hi all (Hi @pjedrzejewski :) ),

our company can't get this feature done, could you give us some advices on that?

We found this old issue: https://github.com/Sylius/Sylius/issues/3929
it seems that someone has used to set channel by url prefix (instead of hostname).

I'm looking for a setChannel method somewhere but i can't find it.

Some idea? :)

Thank you,
Dan

Hi @DanPhyxius,

it is simple 😉 there is request based channel context where HostnameBasedRequestResolver is used to find channel based on hostname. All you have to do is implement your own RequestBasedResolver that will resolve the channel based on url prefix and use it instead of the default one 🎉

Hi @michalmarcinkowski,

great answer, thank you! I'll try tomorrow morning this way! :)

Hi @michalmarcinkowski,

it seems that override HostnameBasedRequestResolver (create our own) is not the right way.

Actually, i override sylius.context.channel.request_based.resolver.hostname_based.class parameter in my app/config/config.yml with a custom HostnameBasedRequestResolver and i put right hostname value in sylius_channel table.

When i go to my host/subdirectory, for example:

myhost.com/fr

this resolver class is not automatically called and Sylius doesn't get right channel.

Any idea? What am i wrong? :)

Thank you for your help,
Dan

Edit. It seems that problem is class CachedPerRequestChannelContext that returns everytime the default class.

I resolve in this way:

in routing.yml add a prefix

my_sylius_web:
    resource: "@MySyliusWebBundle/Resources/config/routing.xml"
    prefix:   /{_locale}
    requirements:
        _locale: |uk|fr|pl|es

in parameters.yml redefine my class

sylius.context.channel.request_based.resolver.hostname_based.class: My\Sylius\Component\Channel\Context\RequestBased\HostnameBasedRequestResolver

in my-bundle-services.xml redefine the service

<service id="sylius.context.channel.request_based.resolver.hostname_based" class="%sylius.context.channel.request_based.resolver.hostname_based.class%">
    <argument type="service" id="sylius.repository.channel" />
    <tag name="sylius.context.channel.request_based.resolver" />
</service>

and create my own logic

final class HostnameBasedRequestResolver implements RequestResolverInterface
{
    /**
     * @var ChannelRepositoryInterface
     */
    private $channelRepository;

    /**
     * @param ChannelRepositoryInterface $channelRepository
     */
    public function __construct(ChannelRepositoryInterface $channelRepository)
    {
        $this->channelRepository = $channelRepository;
    }

    /**
     * {@inheritdoc}
     */
    public function findChannel(Request $request)
    {
        $requestRule = ....

        return $this->channelRepository->findOneByHostname($requestRule);
    }
}

Of course the hostname in the channel have to fit with the login implemented to check $requestRule

My hostnames are mysylius.dev/, mysylius.dev/uk, mysylius.dev/es ....

I am working on a multi tenant store. evalutaed magento, open cart and find that some limitations would cause issues in long run. came across with sylius. need an expert feedback on the followings;

  1. What should I do on sylius to let merchants to sign in, manage their inventories?
  2. Would that be possible to aggregate products from individual merchants and create one global catalog, store?
  3. Do we have an option to let merchants to create offers or deals (using one or more products)?
  4. Is there a feature where I can manage related products?
  5. What API features available to support queries from Android and iOS native apps? Can I query a product from my mobile app and finish the transaction flow?

Hello @chathurabandara. Hope it will help:

  1. I would say that there should be a user - product relation in this situation. You could change a role of some admin users and configure a firewall to give them a proper access or create a new user type. The second option would be probably better.
  2. Some PIM like Akeneo and bridge/importer to Sylius?
  3. Sylius promotion system is pretty flexible and should do the job. You can check our promotion stories to see how they work or check our documentation. The catalog promotions are not available yet.
  4. Sylius has a concept of association. You can create your own type of association and add chosen products.
  5. It is possible. Sylius is based on FOSRest, so it mostly doesn't matter how would you make a request. Basic oauth authorization for admin and all crud operation are available. But a shop part would be some how experimental but you can do it with crud.

​Very useful insites!
Akeneo approach would be much useful :)​

On 5 January 2017 at 16:27, Łukasz Chruściel notifications@github.com
wrote:

Hello @chathurabandara https://github.com/chathurabandara. Hope it will
help:

  1. I would say that there should be a user - product relation in this
    situation. You could change a role of some admin users and configure a
    firewall to give them a proper access or create a new user type. The second
    option would be probably better.
  2. Some PIM like Akeneo https://www.akeneo.com/ and bridge/importer
    to Sylius?
  3. Sylius promotion system is pretty flexible and should do the job.
    You can check our promotion stories
    https://github.com/Sylius/Sylius/tree/master/features/promotion to
    see how they work or check our documentation
    http://docs.sylius.com/en/latest/book/orders/promotions.html. The
    catalog promotions are not available yet.
  4. Sylius has a concept of association. You can create your own type
    of association and add chosen products.
  5. It is possible. Sylius is based on FOSRest, so it mostly doesn't
    matter how would you make a request. Basic oauth authorization for admin
    and all crud operation are available. But a shop part would be some how
    experimental but you can do it with crud.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Sylius/Sylius/issues/5846#issuecomment-270618165, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AXuoS6JTJ2beuMXSw-Fv1_3Ai9OzPnXuks5rPMyxgaJpZM4JoYdB
.

I wonder if this behaviour @DanPhyxius describes could be added as out of the box functionality as it's pretty standard nowdays to have multisites under the same domain to benefit SEO
e.g.
making a site like domain.com/b2b will have a lot more organic search results than a newly set up b2b.domain.com

Also sometimes you don't want to show the same stuff on both global/local site because some products you can't ship abroad like perfumes/alcohol etc etc due to strict laws, or products that your supplier won't allow you to sell to other countries. So even if you just want to translate your website for foreign customers, you might still want to be able to hide items so a new channel instead of a second locale in the same channel seems reasonable.

@ioweb-gr @sprik has presented a possible solution for that. If our default channel resolver doesn't suit you, just write a new one and override service definition. It shouldn't be a problem :)

@ioweb-gr @lchrusciel

Yep, me and @sprik solved with a custom channel resolver. After 6 months, we think it was a good solution for our problem :)

Let me know if you need something!

Hi thank you for the replies. I read about the solution @sprik shared and I understand it is not hard to implement. Sorry if I didn't explain correctly. I was just curious if there are plans to implement it out of the box in the future or as an official plugin. As you can see I am assessing Sylius as an alternative to common platforms we are currently using to see what functionality is missing compared to the popular ones and this was one of the first I noticed along with the lack of Downloadable, Virtual products and Services and Attributes for other entities.

I see that everything is customizable by using overrides but it's really important that most configurations can be made simply by the admin panel and the end users too not just developers.

@ioweb-gr at this stage (and I believe that this maybe true for the future) Sylius is geared for developers, not end users. You take Sylius when you need a custom solution and tailor it to your needs. I don't think it's ever going to be "click and install" type of platform. Read the main statement on http://sylius.org/

First eCommerce framework that grows with your business
Sylius is a free, Open Source and exceptionally flexible eCommerce platform. A framework designed for dynamic Start-Up growth. When all out-of-the-box solutions do not fit your innovative business model, Sylius comes to the rescue.

I'm not part of the core team - i'm relatively new to the platform myself (since November-December last year), but as a developer I like it very much despite the learning curve. It's a properly designed system without any legacy slap-dash baggage and it does not encourage half-assed solutions. Basically if you are in for the long run - chances are Sylius is gonna do well.

Well I can see this is getting a bit too broad and this wasn't my original intention. Obviously everyone's aspirations about Sylius will differ :)

@DanPhyxius how did you setted the requestResolver?
and the route structure? i was searching for use /channel/locale

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in a week if no further activity occurs. Thank you for your contributions.

do not stale
This is a pretty common use case

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in a week if no further activity occurs. Thank you for your contributions.

🏓

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in a week if no further activity occurs. Thank you for your contributions.

Is it still an issue? Would you mind describing what is the need here?

From a quick recap a got an impression that these are the docs missing here, correct me if I'm wrong.

It seems possible to me with decorating or adding a resolver, but it's probably worth having that either documented or possible from core.

@CoderMaggie The need is to have this work:

website.nl/directory -> channel 1
website.nl/another-directory -> channel 2

This has just been twitted: https://twitter.com/lukaszchrusciel/status/1068075282639347712

A Sylius Multi Vendor Marketplace :)

@CoderMaggie I think solving this issue could be in the roadmap. It's a pretty common use case and would be very cool to have.
My experience is telling me that this case is more common that the use of subdomains.

❤️

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in a week if no further activity occurs. Thank you for your contributions.

Nope, keep up!
This is a real deal.

Hi guys ! Sorry to dig up this topic, but I'm trying to get two channel as @stefandoorn said

  • domain.com/channel1
  • domain.com/channel2

I tried to use the @sprik 's way to found a solution but it doesn't seems to work without reason...
Overriding HostnameBasedRequestResolver or even ChannelContext, it looks like the router doesn't event get through those service

````
services:
[...]

sylius.context.channel.request_based:
    class: App\Sylius\Component\Channel\Context\RequestBased\ChannelContext

sylius.context.channel.request_based.resolver.hostname_based:
    class: App\Sylius\Component\Channel\Context\RequestBased\HostnameBasedRequestResolver
    arguments: ['@sylius.repository.channel']
    tags: ['sylius.context.channel.request_based.resolver']

````

````
namespace App\Sylius\Component\Channel\Context\RequestBased;

use Sylius\Component\Channel\Context\RequestBased\RequestResolverInterface;
use Sylius\Component\Channel\Model\ChannelInterface;
use Sylius\Component\Channel\Repository\ChannelRepositoryInterface;
use Symfony\Component\HttpFoundation\Request;

final class HostnameBasedRequestResolver implements RequestResolverInterface
{
/**
* @var ChannelRepositoryInterface
*/
private $channelRepository;

/**
 * @param ChannelRepositoryInterface $channelRepository
 */
public function __construct(ChannelRepositoryInterface $channelRepository)
{
    $this->channelRepository = $channelRepository;
}

/**
 * {@inheritdoc}
 */
public function findChannel(Request $request): ?ChannelInterface
{
    die; // HERE TO DEBUG
    return $this->channelRepository->find(1);
}

}
````

And I can see that my config looks right cause I found my class in php bin/console debug:container
Nothing seems to change in dev mode, die doesn't matter.

Did you found any solution for this kind of use case ? Any roadmap with this feature ?

Thanks for help !

@dylanschreier do you use auto-wiring and auto-configuration?

Thanks for replying, actually yes, but does it change something ?

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

Can you please share the result of the following commands:

php bin/console debug:container sylius.context.channel.request_based
php bin/console debug:container sylius.context.channel.request_based.resolver.hostname_based
php bin/console debug:container --tag sylius.context.channel

Sure!

$ php bin/console debug:container sylius.context.channel.request_based

Information for Service "sylius.context.channel.request_based"
==============================================================

 ---------------- ------------------------------------------------------------------
  Option           Value
 ---------------- ------------------------------------------------------------------
  Service ID       sylius.context.channel.request_based
  Class            App\Sylius\Component\Channel\Context\RequestBased\ChannelContext
  Tags             -
  Public           no
  Synthetic        no
  Lazy             no
  Shared           yes
  Abstract         no
  Autowired        yes
  Autoconfigured   yes
 ---------------- ------------------------------------------------------------------

$ php bin/console debug:container sylius.context.channel.request_based.resolver.hostname_based

Information for Service "sylius.context.channel.request_based.resolver.hostname_based"
======================================================================================

 ---------------- --------------------------------------------------------------------------------
  Option           Value
 ---------------- --------------------------------------------------------------------------------
  Service ID       sylius.context.channel.request_based.resolver.hostname_based
  Class            App\Sylius\Component\Channel\Context\RequestBased\HostnameBasedRequestResolver
  Tags             sylius.context.channel.request_based.resolver
  Public           no
  Synthetic        no
  Lazy             no
  Shared           yes
  Abstract         no
  Autowired        yes
  Autoconfigured   yes
 ---------------- --------------------------------------------------------------------------------

$ php bin/console debug:container --tag sylius.context.channel

Symfony Container Services Tagged with "sylius.context.channel" Tag
===================================================================

 --------------------------------------------- ---------- --------------------------------------------------------------------
  Service ID                                    priority   Class name
 --------------------------------------------- ---------- --------------------------------------------------------------------
  sylius.context.channel.fake_channel.context   128        Sylius\Bundle\ChannelBundle\Context\FakeChannel\FakeChannelContext
  sylius.context.channel.single_channel         -128       Sylius\Component\Channel\Context\SingleChannelContext
 --------------------------------------------- ---------- --------------------------------------------------------------------

Did you notice something special ?

Didn't you?
Your context is not used because it's missing the tag.
You probably forgot to implement the Sylius\Component\Channel\Context\ChannelContextInterface

Ohh! We're going forward

I thought I just need to override HostnameBasedRequestResolver, actually I try to override ChannelContext because it wasn't seems to work.

But you're right, it was missing the tag for the ChannelContext, now I can get the die() from ChannelContext but not from HostnameBasedRequestResolver, do I need to manage channel from ChannelContext

What's the output of php bin/console debug:container --tag sylius.context.channel.request_based.resolver?

$ php bin/console debug:container --tag sylius.context.channel.request_based.resolver

Symfony Container Services Tagged with "sylius.context.channel.request_based.resolver" Tag
==========================================================================================

 -------------------------------------------------------------- --------------------------------------------------------------------------------
  Service ID                                                     Class name
 -------------------------------------------------------------- --------------------------------------------------------------------------------
  sylius.context.channel.request_based.resolver.hostname_based   App\Sylius\Component\Channel\Context\RequestBased\HostnameBasedRequestResolver
 -------------------------------------------------------------- --------------------------------------------------------------------------------

This is my file (I kept the architecture of Sylius for all my override)

I guess you removed the die() from the channel context, so I have no more ideas.

Actually yes...I played with the die() last week, and now if I clear the cache I can get the die()so I can override my channel, thanks a lot !

I found the right way !
You only need to override HostnameBasedRequestResolver as @sprik said, my problem came from the toolbar...
I used to switch channel from the Symfony toolbar, which create a cookie _channel_code which himself override everything...
So finally, it's easy to change the channel logic, but the documentation could be a little bit more detailed
Big thanks to @vvasiloi

Was this page helpful?
0 / 5 - 0 ratings