I am building a multi-tenant SaaS application which I am trying to write tests for with Behat, using Mink and the Behat Laravel Extension
When you register for an account, you get your own subdomain on the site {account}.tenancy.dev
my behat.yml file looks like so:
default:
extensions:
Laracasts\Behat:
# env_path: .env.behat
Behat\MinkExtension:
default_session: laravel
base_url: http://tenancy.dev
laravel: ~
I am having problems straight off the bat as when I try to test my registration flow, I am getting a 404 error testing that the new subdomain is accessible, all of the data has been saved correctly, manually testing the process works and the subdomain routing works.
I was wondering if there was any way to do this using Behat and how I would go about setting Behat / Mink to use wildcard subdomains to test SaaS applications?
I am running the test inside the Homestead VM.
The base_url: http://tenancy.dev configuration is used to generate a fully qualified domain URL when you utilize relative path URL's in your mink steps (IE "/home").
When you want to hit a domain different from the domain specified in base_url, all you have to do is use the fully qualified domain URL in your step like "http://test.tenancy.dev/fully/qualified".
So use the base_url configuration to set what you will be using for the majority of your steps as relative url's and then explicitly specify the full domain for the exceptions.
When I create an account named foo
And GET "http://foo.tenancy.dev/ping"
Then I get a 200 response code
When I GET "/home"
Then the response contains "Sign Up"
If the majority of your testing will be against the sub domain, set that as your base_url and explicitly specify your top level domain when necessary.
You may resolve subdomains using xip.io, which is especially useful if you cannot access the /etc/hosts file on a CI server, for example.
To route {account}.tenancy.dev to your local webserver, you can use account.tenancy.dev.127.0.0.1.xip.io which resolves to 127.0.0.1.
After a short while I revisited this problem and found a rather simple solution to be used in my FeatureContext.php:
$this->setMinkParameter('base_url', $url);
This changes the base url for any scenario it is used in:
/**
* #Given I visit the url :url
*/
public function visitDomain($url)
{
$this->setMinkParameter('base_url', $url);
$this->visit('/');
}
Which is used in the following way:
Scenario: Test Multi Tenancy
Given I have a business "mttest"
When I visit the url "http://mttest.example.com"
Then I should see "mttest"
Obviously this is slightly contrived but does show that what I was intending to do is possible.
Related
I'm using absolute_url function defined here in my twig email template that is triggered via symfony command but the path only returns localhost/route instead of the complete URL http://abc.local/route.
download
What am I missing here ?
Solution with Symfony-5.4
Generating URLs in commands works the same as generating URLs in services. The only difference is that commands are not executed in the HTTP context. Therefore, if you generate absolute URLs, you'll get http://localhost/ as the host name instead of your real host name.
The solution is to configure the default_uri option to define the "request context" used by commands when they generate URLs:
On config/packages/routing.yaml add the URL of the real host.
# config/packages/routing.yaml
framework:
router:
# ...
default_uri: 'https://example.org/my/path/'
The default_uri option was introduced in Symfony 5.1.
For reference please see the official documentation.
https://symfony.com/doc/5.4/routing.html#generating-urls-in-commands
In my Symfony2 project, I send email with a link to connect to my website, like
LOGIN
When I use this template in a controller, the link is good.
LOGIN
But if I use this template for my mail in a ContainerAwareCommand with a cron, it looks like
LOGIN
It's not good. How am I suppose to do to make it work ?
You should Configure the Request Context Globally, as described in the doc How to Generate URLs from the Console:
you can redefine the parameters it uses as default values to change
the default host (localhost) and scheme (http). You can also configure
the base path if Symfony is not running in the root directory.
Note that this does not impact URLs generated via normal web requests,
since those will override the defaults.
# app/config/parameters.yml
parameters:
router.request_context.host: example.org
router.request_context.scheme: https
router.request_context.base_url: my/path
hope this help
I have a Yii2 app but no ability to edit the config files to utilize setAlias.
If my domain is example.com, and my Yii application is in /my-app directory, then what would be the Yii command to return the following string:
http://example.com/my-app/
Yii::getAlias('#app') returns
/httpdocs/my-app
Many posts exist but all I've found is suggestions either based on Yii1 or using setAlias in application config.
Yuo can use a simple urlHelper (for absolute url)
use yii\helpers\Url;
echo Url::to(['/'], true );
I moved all the public images of my website to a folder out of the web folder of symfony so it can be shared with other web applications.
I created a symbolic link to this folder so it can be accessed from the web folder of the symfony application.
ln -s /absolute/path/to/images /path/to/symfony/application_01/web/images
ln -s /absolute/path/to/images /path/to/symfony/application_02/web/images
Etc... for all applications.
I'm looking for a method that would allow me to retrieve the images URI in my development environment on localhost as well as in my production environment on the remote web server.
I would like to be able to retrieve this URI from the twig template AND from the controller.
Basically (for my application_01 for instance):
In the development environment it would return:
http://localhost/images/my_image.jpg
In the production environment, it would return:
http://www.application_01.com/images/my_image.jpg
My problem is that I found lots of different ways to get URIs but I'm not totally clear about how Symfony manages them and what functions to use to have a global solution working in all cases.
What is the best way to achieve my goal?
EDIT
Specifically I found some SO answers to quite similar questions proposing to use the following functions:
$request->getScheme();
$request->getHttpHost();
That seems to correspond to the values or superglobals $_SERVER['REQUEST_SCHEME'] and $_SERVER['HTTP_HOST']
And I don't know if this is the proper way to get this information since this is linked to the current request received by the server.
Isn't there another way to get this info independently from the request currently processed by the server?
Define the following url
image_url:
path: /images/{image}
Then use it like this
/** #var Router $router */
$router = $this->get('router');
$url = $router->generate('image_url', ['image' => 'my_image.jpg'], Router::ABSOLUTE_URL);
$url now contains the absolute url to your image. And of course it's the best practice you can think of :)
----- Answer to your comment about app_dev.php
We used this solution in our company months ago.
preg_replace('#/(.+?)\.php)', '', $router->generate('my_url');
http://techimho.com/index.php/2015/10/15/generate-production-url-in-dev-environment/
I have a multisite aplication with a log system depends on each site and I want that each of them has its own log file so I did that :
1) I use a dynamic variable in config.yml with depends on $_SERVER['HTTP_HOST'].
config.yml:
imports:
- { resource: param.php }
...
monolog:
handlers:
user:
type: stream
path: %kernel.logs_dir%/%domain_name%.%log_filename%
channels: [user]
=> %domain_name% is my dynamic variable
2) I set it in app/config/param.php:
<?php
$url = $_SERVER['HTTP_HOST'];
$domain = preg_replace('/^www./', '', $url);
$container->setParameter('domain_name', $domain); // this set my variable `%domain_name%` with the current domain (ex: site1.com)
Problem :
This code works fine but when I switch to an other site, the value of %domain_name% remains equal to its initial value.
Exemple :
I am in www.site1.com => %domain_name% value is "site1.com" so it works
fine
I switch to www.site2.com => %domain_name% value is always "site1.com" and
not "site2.com"
Why ?
Cache issue. Indeed, Symfony load in cache config.yml so it keeps the first value of %domain_name%
To delete this value I have to execute this command: rm -rf app/cache/* but it is not a solution.
So nobody has a solution for this problem ? Thanks
We had the same problem in our multi-site CMS environment. Symfony is primarily designed to run a single site, so the config.yml gets run once, and then cached. That means if you inject dynamic parameters into the config.yml (by any means: Globals, Constants, Apache Environment, etc), after the first run they are cached for each subsequent request :( So the next unique domain site request, will be using the cached values from the first site. In most cases, this creates problems.
Some people have suggested creating different environments for each site. But that's not practical when you host hundreds, thousands or millions of sites.
Alternative Cache Location
At the moment, the best solution we can conceive is to specify a different cache folder for each site. So you extend the app/appKernel.php and customize the getCacheDir function.
//app/appKernel.php
class AppKernel extends Kernel
{
public function getCacheDir()
{
return $this->rootDir.'/cache/'.$this->environment.'/'.$_SERVER['HTTP_HOST'];
}
}
See API Reference for Kernel.
I am not quite sure, if you are using the parameter file/configuration as intended.
For me there is information missing, to answer your question directly, so here are the two possible scenarios:
1) Site www.site1.com and www.site2.com is pointing at the SAME source (same server):
In this case I wouldn't define the domain_name as an configuration value, course it is not an distinct configuration parameter it is more like a variable. Build a service or think about defining an additional environment.
2) www.site1.com and www.site2.com are two distinct projects:
In that case you shouldn't deploy the contents of the cache directory (which you should do anyway; but in this case it would be the issue ;)).
EDIT
You could implement different configuration files to solve:
config_site1.yml # Configuration for www.site1.com
config_site2.yml # Configuration for www.site2.com
Controller in your /web directory:
app_site1.php
app_site2.php
initialize the AppKernel with the requested environment, and point to the controller in your vhost config or your htaccess file.
I think you could change the app.php controller even to something like:
[...]
require_once __DIR__.'/../app/AppKernel.php';
$request = Request::createFromGlobals();
$kernel = new AppKernel($request->giveMeMyHostEnvironmentMappingShizzle(), false);
$kernel->loadClassCache();
[...]
kind regards