Limit languages in cms - silverstripe

I use silverstripe 3.1
I would like to limit the languages (To only German and English) which are available in the drop down in the CMS. Therefore I put
the following code in my mysite/_config.php
i18n::set_locale('de_DE');
$allowed_locales = array(
'de_DE' => array('Deutsch', 'Deutsch'),
'en_EN' => array('English', 'English')
);
i18n::$common_locales = $allowed_locales;
Afer a flush=1 i get the following error:
Fatal error: Cannot access private property i18n::$common_locales in ... _config.php
Any ideas what goes wrong?
Thank you

as of 3.1 most of the static php variables are private. this means you can no longer access those.
the reason for this api change is that they are now cached by the config layer (this is also why you have to ?flush=1 now after changing private statics in classes like for example with private static $db)
if you want to update something in the config layer, you can do this with:
Config::inst()->update('CLASS', 'FIELD', $value);
you could use use the config update to overwrite the common locales (class would be 'i18n', and field would be 'common_locales'):
Config::inst()->update('i18n', 'common_locales', $array);
Note: if you want to completely overwrite an existing configuration, you have to do a remove() first.
Config::inst()->remove('i18n', 'common_locales');
Config::inst()->update('i18n', 'common_locales', $array);
however, if you are using the translatable module and you want to limit the number of translatable languages, there is a much better way already built in:
// in your _config.php
i18n::set_locale('en_US');
Translatable::set_allowed_locales(array(
'de_DE',
'en_US',
));

Config it through YAML:
i18n:
common_locales:
nl_BE:
name: Dutch (Belgium)
native: Nederlands
fr_BE:
name: French (Belgium)
native: Francais

Related

phpunit testable livewire fails with Undefined array key "fingerprint"

When trying a test that came with Laravel and Jetstream/Livewire libraries, I get an undefined array key "fingerprint" error message
Undefined array key "fingerprint"
at vendor/livewire/livewire/src/Testing/TestableLivewire.php:181
public function pretendWereSendingAComponentUpdateRequest($message, $payload)
{
$result = $this->callEndpoint('POST', '/livewire/message/'.$this->componentName, [
'fingerprint' => $this->payload['fingerprint'],
'serverMemo' => $this->payload['serverMemo'],
'updates' => [['type' => $message, 'payload' => $payload]],
]);
This happens for any out of the box feature tests that ship with Laravel9 with Jetstream when used against my project.
Here is one example that fails at the Livewire::test.... line.
The user is created and authenticating without issue and confirmed in other phpunit tests.
class BrowserSessionsTest extends TestCase
{
use RefreshDatabase;
public function test_other_browser_sessions_can_be_logged_out(): void
{
$this->actingAs($user = User::factory()->create());
Livewire::test(LogoutOtherBrowserSessionsForm::class)
->set('password', $user->password)
->call('logoutOtherBrowserSessions')
->assertSuccessful();
}
}
I stood up a fresh Laravel 9 project which works and began inserting various areas from my project into the fresh project as a way of hopefully identifying the issue. Session parameters, events, migrations, factories, models, were not the issue as it continued to work in the fresh project.
One thing I noticed is that the generic routes are not accepted in my project within he test cases. I have to insert 'https://realtor.host' in front of every test route (e.g. $response = $this->get('https://realtor.host/register');
I was curious if it was not evaluating the livewire route and I tried to add my domain into the vendor's livewire component in which the test still failed and that did not cause it to work.
Any ideas on where else I can look?

Symfony 3 Translations Custom Domain

I'm trying to add custom domain into the project.
I have regions.locale.yaml file.
I'm trying load it in twig:
{{'united.kingdom'|trans|raw}}
But this doesn't work.
I think it has to be somehow declared that this file exists.
I found this in documentation:
// ...
$translator->addLoader('xlf', new XliffFileLoader());
$translator->addResource('xlf', 'messages.fr.xlf', 'fr_FR');
$translator->addResource('xlf', 'admin.fr.xlf', 'fr_FR', 'admin');
$translator->addResource(
'xlf',
'navigation.fr.xlf',
'fr_FR',
'navigation'
);
But where should I put this to declare my regions.locale.yaml files globally?
Thanks
If you are using Symfony Standard, you don't have to declare your translation files, you just put them in app/Resources/translations.
The key is that when you want to translate using your custom domain, you just specify your domain, like this :
{{'united.kingdom'|trans({}, 'regions')|raw }}
or somewhere else in your code :
$translator->trans('united.kingdom', [], 'regions');

Virtual Filesystem for PHPUnit tests in Laravel 5.4

i'm having a bit of a problem with my PHPUnit integration tests, i have a method which handles a form upload for a video file as well as a preview image for that video.
public function store($request)
{
/** #var Video $resource */
$resource = new $this->model;
// Create a new Content before creating the related Photo
$contentRepo = new ContentRepository();
$content = $contentRepo->store($request);
if($content->isValid()) {
$resource->content_id = $content->id;
$directory = 'frontend/videos/assets/'.date("Y").'/'.date('m').'/'.time();
\File::makeDirectory($directory, 0755, true);
$request->video->move($directory.'/', $request->video->getClientOriginalName());
$resource->video = '/'.$directory.'/'.$request->video->getClientOriginalName();
$request->preview_image->move($directory.'/', $request->preview_image->getClientOriginalName());
$resource->preview_image = '/'.$directory.'/'.$request->preview_image->getClientOriginalName();
$resource->highlighted = intval($request->input('highlighted') == 'on');
$resource->save();
return $resource;
}
else {
return $content;
}
}
The important part to keep is the $request->video->move() call which i probably need to replace in order to use Virtual Filesystem.
and then the test
public function testVideoUpload(){
File::put(__DIR__.'/frontend/videos/assets/image.mp4', 'test');
$file = new UploadedFile(__DIR__.'/frontend/videos/assets/image.mp4', 'foofile.mp4', 'video/mp4', 100023, null, $test=true);
File::put(__DIR__.'/frontend/images/assets/image.jpg', 'test');
$preview = new UploadedFile(__DIR__.'/frontend/images/assets/image.jpg', 'foofile.jpg', 'image/jpeg', 100023, null, $test=true);
$this->post('/admin/videos', [
'title' => 'My Video #12',
'description' => 'This is a description',
'actors' => [$this->actor->id, $this->actor2->id],
'scenes' => [$this->scene->id, $this->scene2->id],
'payment_methods' => [$this->paymentMethod->id],
'video' => $file,
'preview_image' => $preview
])->seeInDatabase('contents', [
'title' => 'My Video #12',
'description' => 'This is a description'
]);
}
As you can see, i need to create a dummy file in some local directory and then use that in the HTTP request to the form's endpoint, then after that, that file would be moved and i need to delete the created folder and the new moved file... it's an authentic mess.
As such i want to use Virtual Filesystem instead, but i have no idea how to set it up in this particular case, i've already downloaded a package and set it up, but the questions are, first, which package have you used/recommend and how would you tweak the class and the test to support the Virtual Filesystem? Would i need to switch over to using the Storage facade instead of the $request->video->move() call? If so how would that be done exactly?
Thank you in advance for your help
I couldn't figure out the VFS system, however i do have somewhat of an alternative that's still kinda messy but gets the job done.
Basically i set up two methods on my PHPUnit base class to setup and teardown the temp folders i need on any test that requires them, because i'm using Database Transactions the files get deleted on every test run and i need to create new dummy files every time i run the test.
So i have two methods setupTempDirectories and teardownTempDirectories which i will call at the beginning and at the end of each test that requires those temporary directories.
I put my temp files in the Storage directory because sometimes i run my tests individually through PHPStorm and the __DIR__ command gets messed up and points to different directories when i do that, i also tried __FILE__ with the same result, so i just resorted to using Laravel's storage_path instead and that works fine.
Then that leaves the problem of my concrete class which tries to move files around and create directories in the public folder for them... so in order to fix that i changed the code to use the Storage facade, then i Mock the Storage facade in my tests
So in my concrete class
$directory = 'frontend/videos/assets/'.date("Y").'/'.date('m').'/'.time();
Storage::makeDirectory($directory, 0755, true);
Storage::move($request->video, $directory . '/' . $request->video->getClientOriginalName());
$resource->video = '/'.$directory.'/'.$request->video->getClientOriginalName();
Storage::move($request->preview_image, $directory . '/' . $request->preview_image->getClientOriginalName());
$resource->preview_image = '/'.$directory.'/'.$request->preview_image->getClientOriginalName();
And then in my test i mock both the makeDirectory and the move methods like such
// Override the Storage facade with a Mock version so that we don't actually try to move files around...
Storage::shouldReceive('makeDirectory')->once()->andReturn(true);
Storage::shouldReceive('move')->twice()->andReturn(true);
That makes my tests work and does not actually leave files behind after it's done...i hope someone has a better solution but for the time being this is what i came up with.
I was actually trying to use VFS but it never worked out... i keep getting errors that the original file in the storage directory is not found even though it's right there...
I'm not even sure the Storage facade was using VFS in the background to begin with even though it should...

Symfony2 - Dynamic Doctrine Database Connections at Runtime

I am looking for a good solution to on-the-fly connection of databases within Symfony utilizing Doctrine for entity management.
The scenario I have is that all inbound users to our service will be visiting *.website.com addresses, like client1.website.com.
We would like to use one Doctrine entity for the Client table to then look up their database credentials based on the URL of their account on the fly.
So far I have found the following topics here on stackoverflow that discuss dynamically changing the database credentials--but no clear workable solutions.
I'd like to propose collaborating to put together a working solution, and I'll put together a blog/tutorial post for other folks looking to modify database connection parameters within Symfony.
Here are some related posts:
Dynamic database connection symfony2
Symfony2, Dynamic DB Connection/Early override of Doctrine Service
Thanks!
If $em is existing entity manager and you want to reuse it's configuration, you can use this:
$conn = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'dbname' => 'foo'
);
$new = \Doctrine\ORM\EntityManager::create(
$conn,
$em->getConfiguration(),
$em->getEventManager()
);
I needed to do something similar - runtime discovery of an available database server. I did it by overriding the doctrine.dbal.connection_factory.class parameter and substituting my own derivation of the Doctrine bundle's ConnectionFactory class
My services.yml provides the parameter, pointing at my custom class
parameters:
doctrine.dbal.connection_factory.class: Path\To\Class\CustomConnectionFactory
Then fill in your discovery logic in Path\To\Class\CustomConnectionFactory.php
<?php
namespace Path\To\Class;
use Doctrine\Bundle\DoctrineBundle\ConnectionFactory;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration;
class CustomConnectionFactory extends ConnectionFactory
{
public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = array())
{
// Discover and override $params array here.
// A real-world example might obtain them from zookeeper,
// consul or etcd for example. You'll probably want to cache
// anything you obtain from such a service too.
$params['driver'] = 'pdo_mysql';
$params['host'] = '10.1.2.3';
$params['port'] = 3306;
$params['dbname'] = 'foo';
$params['user'] = 'myuser';
$params['password'] = 'mypass';
//continue with regular connection creation using new params
return parent::createConnection($params, $config, $eventManager,$mappingTypes);
}
}
Note also that Symfony 3.2 features the ability to use environment variables in container configurations, and to use their values on-demand (rather than fixing them when the container is compiled). See the blog announcement for more details.

Custom route configuration with Silex

I know that the basis of Silex approach in which all the application logic in a single file. But my application will be possible to have more than twenty controllers. So I want to have a handy map to manage the router.
My question is to search for solutions in which I would be able to make a router to a separate file. In the best case, the file must be of YAML type:
# config/routing.yml
_home:
pattern: /
defaults: { _controller: MyProject\Controller\MyController::index }
But the native is also a good case (for me):
$routes = new RouteCollection();
$routes->add(
'home',
new Route('/', array('controller' => 'MyProject\Controller\MyController::index')
));
return $routes;
Problem of the second case is that I have to use the match() function for each rule of routing. It is not at all clear.
What are the ways to solve this issue? The condition is that I want to use the existing API Silex or components of Symfony2.
Small note:
I don't use a ControllerProviderInterface for my Controller classes. This is an independent classes.
First of all, the basis of Silex is not that you put everything in one file. The basis of Silex is that you create your own 'framework', your own way of organizing applications.
"Use silex if you are comfortable with making all of your own architecture decisions and full stack Symfony2 if not."
-- Dustin Whittle
Read more about this in this blogpost, created by the creator of Silex.
How to solve your problem
What you basically want is to parse a Yaml file and get the pattern and defaults._controller settings from each route that is parsed.
To parse a Yaml file, you can use the Yaml Component of Symfony2. You get an array back which you can use to add the route to Silex:
// parse the yaml file
$routes = ...;
$app = new Silex\Application();
foreach ($routes as $route) {
$app->match($route['pattern'], $route['defaults']['_controller']);
}
// ...
$app->run();
I thought I'd add my method here as, although others may work, there isn't really a simple solution. Adding FileLocator / YamlFileLoader adds a load of bulk that I don't want in my application just to read / parse a yaml file.
Composer
First, you're going to need to include the relevant files. The symfony YAML component, and a really simple and useful config service provider by someone who actively works on Silex.
"require": {
"symfony/yaml": "~2.3",
"igorw/config-service-provider": "1.2.*"
}
File
Let's say that your routes file looks like this (routes.yml):
config.routes:
dashboard:
pattern: /
defaults: { _controller: 'IndexController::indexAction' }
method: GET
Registration
Individually register each yaml file. The first key in the file is the name it will be available under your $app variable (handled by the pimple service locator).
$this->register(new ConfigServiceProvider(__DIR__."/../config/services.yml"));
$this->register(new ConfigServiceProvider(__DIR__."/../config/routes.yml"));
// any more yaml files you like
Routes
You can get these routes using the following:
$routes = $app['config.routes']; // See the first key in the yaml file for this name
foreach ($routes as $name => $route)
{
$app->match($route['pattern'], $route['defaults']['_controller'])->bind($name)->method(isset($route['method'])?$route['method']:'GET');
}
->bind() allows you to 'name' your urls to be used within twig, for example.
->method() allows you to specify POST | GET. You'll note that I defaulted it to 'GET' with a ternary there if the route doesn't specify a method.
Ok, that's how I solved it.
This method is part of my application and called before run():
# /src/Application.php
...
protected function _initRoutes()
{
$locator = new FileLocator(__DIR__.'/config');
$loader = new YamlFileLoader($locator);
$this['routes'] = $loader->load('routes.yml');
}
Application class is my own and it extends Silex\Application.
Configuration file:
# /src/config/routes.yml
home:
pattern: /
defaults: { _controller: '\MyDemoSite\Controllers\DefaultController::indexAction' }
It works fine for me!
UPD:
I think this is the right option to add collections:
$this['routes']->addCollection($loader->load('routes.yml'));
More flexible.
You could extend the routes service (which is a RouteCollection), and load a YAML file with FileLocator and YamlFileLoader:
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
$app->extend('routes', function($routeCollection) {
$locator = new FileLocator([__DIR__ . '/../config']);
$loader = new YamlFileLoader($locator);
$collection = $loader->load('routes.yml');
$routeCollection->addCollection($collection);
return $routeCollection;
});
You will need symfony/config and symfony/yaml dependencies though.

Resources