Currently, my symfony 1.4 app is using the myUser class. But I need to override the behaviour of this class to work with a single plugin. As it is not the proper way to change the base code, I would like to know whether there is a way to extend the myUser class and use it with my plugin?
What I am trying to achieve is, keeping a separate session timeout for my plugin. In order to do so, I have to separate the http requests of other plugins from the http requests of my plugin. If there is another way of achieving this, it is even better. Thanks!
Look to see if there is a myUser.class.php file in the lib folder of your app. If there isn't create one and in it add:
<?php
class myUser extends sfBasicSecurityUser
{
}
?>
Or if you are using sfGuardPlugin:
<?php
class myUser extends sfGuardSecurityUser
{
}
?>
Then clear the cache.
You will be able to use it with your plugin.
As far as the session expiration goes. It's not clear what kind of information your plugin is managing. Can't you just expire the information at a certain point? Symfony allows you to save session data to different namespaces. (The example below uses 'plugin_info'.) Can't that namespace have an expiration time?
Example:
$this->setAttribute('plugin_expiration', time() + 1000, 'plugin_info');
$expiration = $this->getAttribute('plugin-plugin_expiration', time() + 1000, 'plugin_info');
if ($expiration > time())
{
$this->getAttributeHolder()->removeNamespace('plugin_info');
// then restart the session here.
}
Related
I'm using the elasticsearch connector module for Drupal 8 to manage indexes. https://www.drupal.org/project/elasticsearch_connector
One thing I need to happen on index creation time is to add some analyzers and filters to the elasticsearch index mapping.
I've tracked down the place that's happening here in the create() method for one of their classes:
modules\contrib\elasticsearch_connector\src\ElasticSearch\Parameters\Factory\IndexFactory.php
I have a custom module that I'm trying to extend that method and add to it but can't seem to get it to fire. I have the module enabled properly as it shows up on the extend page. So far my folder structure for my custom module looks like this:
modules\custom\elasticsearch_analyzer\src\elasticsearch_analyzer.php
<?php
namespace Drupal\elasticsearch_analyzer;
use Drupal\search_api\IndexInterface;
use Drupal\elasticsearch_connector\ElasticSearch\Parameters\Factory\IndexFactory;
class elasticsearch_analyzer extends IndexFactory {
/**
* {#inheritdoc}
*/
public static function create(IndexInterface $index) {
die('does this work?');
return [
'index' => IndexFactory::getIndexName($index),
'body' => [
'settings' => [
'number_of_shards' => $index->getOption('number_of_shards', 5),
'number_of_replicas' => $index->getOption('number_of_replicas', 1),
],
],
];
}
}
I've tried a bunch of different combinations surrounding the PSR-4 standard, but can't seem to get it to run. Is this how we'd normally go about extending things in Drupal 8? Should I just be putting this class in the .module file at the root of my module? Should I be registering this as a service?
Based on the tutorials I've read, I haven't been able to see any examples of extending contributed modules or core outside of creating block plugins or simple route pages. I thought now that we're out of the hook world I should be able to examine code within an existing class and override it using OOP inheritance. Or is that not the case?
You cannot just extend a class. How is the module supposed to call this new class? How to you communicate its existence to other modules so they are able to call it? Your class in isolation does not do anything.
I was reading through the source code of this module. This IndexFactory class is used in the SearchApiElasticsearchBackend class which is registered as a backend to the Search API module (i.e. the search api knows that this backend exists and calls it).
Sadly this IndexManager class is just hardcoded into the backend and there is no way to inject your own. The class has static methods only so they are called directly. Even if you would create your own search backend and extend SearchApiElasticsearchBackend you would have to replace IndexManager with YourCustomIndexManager everywhere.
You will have to change the create() method directly in module to do what you want.
I'm trying to do tdd with my WordPress plugins. The problem is that using WP_UnitTestCase is way way to slow and despite the name provides integration tests rather than unit tests. So instead of using WP_UnitTestCase I have been working on creating truly isolated tests for my plugins but the problem is that I find myself using a lot of WordPress global functions such as wp_get_current_user() or wp_signon().
Currently I have a file of the functions I've used that are basically stubbed out.
What is the best way to go about mocking these functions? Ultimately I'd like to be able to mock these functions the same way as I would other methods with the ability to control their output and test that they're called. Is there a more OO way to set the current user or check for authentication that I'm missing?
You can create a class for invoking global WordPress functions. This can have a map of methods to global functions or even invoking whatever method is called that starts with wp_ using __call or any other way you come up with.
Then you would use this class from inside your plugin to call the functions. I suppose plugins are instantiated by WordPress so you won't be able to inject this class on production code. So you can make it externally settable to allow injecting a mock but if none is provided, use the real one.
Like this:
<?php
class Plugin
{
private $invoker;
public function getWpInvoker()
{
if (!isset($this->invoker)) {
$this->invoker = new WordPressGlobalFunctionsInvoker();
}
}
public function setWpInvoker(WordPressGlobalFunctionsInvoker $invoker)
{
$this->wp_invoker = $invoker;
}
public function foo()
{
$current_user = $this->getWpInvoker()->wp_get_current_user();
}
}
In the test you would mock the WordPressGlobalFunctionsInvoker class and inject the mock to the plugin so you take control over the functions being called.
I have a package checking function that needs to check if the logged in user has a valid package. This functionality is identical across all modules but is not needed in every module action.
protected function checkPackage()
{
if($this->MscdbProject->getCurrentPackage()){
return;
}
$this->getUser()->setFlash('error',"Your package has expired, to restore access to your project please contact us to renew it.");
$this->redirect('project/index');
}
I need to access this function in most module actions across multiple modules but it relies on the MscdbProject variable which is pulled in the individual actions, this is sllightly different in different modules so cannot be standardised.
Currently I have this function duplicated in every module and I call it from every action where it is needed.
How can I refactor this to avoid this duplication?
It feels like a filter should be able to do this but I have to have pulled the MscdbProject instance before I can check the package status.
Thanks
Change the base class for your action classes to your own:
class myAction extends sfAction {
abstract protected function getMscdbProject();
protected function checkPackage()
{
if($this->getMscdbProject()->getCurrentPackage()){
return;
}
$this->getUser()->setFlash('error',"Your package has expired, to restore access to your project please contact us to renew it.");
$this->redirect('project/index');
}
}
Now your module action have to implement getMscdbProject() using their own logic.
If you are using generated modules, change this key in generator.yml:
generator:
param:
actions_base_class: myAction
I'm searching for a solution how I can implement a bundle into my base-template so that it will be visible on every page of my project without including it into every single Template/Bundle.
Is this possible? It's a language switch and I thought about building a bundle for it, so that it can interact directly to set the locale for all links etc...
Edit: Maybe I need to set it up as a service??
My problem is; how to get the language Selector into the base Template without any route ?
So at least I figured out how to handle this. Maybe its not a beauty, but for now its working so that I can checkout a better solution
public function localize_route($locale = NULL) {
// Merge query parameters and route attributes
$attributes = array_merge($this->request->query->all(), $this->request->attributes->get('_route_params'));
// Set/override locale
$attributes['_locale'] = $locale ?: \Locale::getDefault();
return $this->router->generate($this->request->attributes->get('_route'), $attributes);
}
as it's described here http://blog.viison.com/post/15619033835/symfony2-twig-extension-switch-locale-current-route
So that it works
I try to create an Admin User with FOsUserBundle from command windows with the following command:
php app/console fos:user:create
In my project the Admin User extends other user with mandatory propriety. So, when I choose my username, mail and password, it tells me:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'latitude' cannot be null
How can I set the value "latitude" in my AdminUser? I also use PUGXMultiUserBundle.
Only possibile way to reach that to me is
1 - override the cli command of FOSUserBundle placed into Command/CreateUserCommand.php
2 - override the user create method of FOSUserBundle placed into Util/UserManipulator.php
// Command/CreateUserCommand.php
protected function execute(InputInterface $input, OutputInterface $output)
{
$username = $input->getArgument('username');
$email = $input->getArgument('email');
$password = $input->getArgument('password');
$inactive = $input->getOption('inactive');
$superadmin = $input->getOption('super-admin');
$latitude = $input->getOption('latitude'); //this will be your own logic add
$manipulator = $this->getContainer()->get('fos_user.util.user_manipulator');
$manipulator->create($username, $password, $email, $latitude, !$inactive, $superadmin);
$output->writeln(sprintf('Created user <comment>%s</comment>', $username));
}
and
// Util/UserManipulator.php
public function create($username, $password, $email, $latitude, $active, $superadmin)
{
$user = $this->userManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
$user->setEnabled((Boolean) $active);
$user->setSuperAdmin((Boolean) $superadmin);
$user->setLatitude($latitude);
$this->userManager->updateUser($user);
return $user;
}
Of course when I say override i mean ... override :P So you haven't to modify FOSUserBundle original files (you know, it's dangerous for many reasons) but make your own files by making your bundle extended by FOSUserBundle
Are you wondering how to make your bundle extended by FOSUserBundle?
Into your bundle "mainfile" - is the one you use to register your bundle - just add this lines
public function getParent()
{
return 'FOSUserBundle';
}
Then you simply recreate the tree structure where your ovverride files lives into original bundle, into your custom bundle's Resources/ directory (same position, same file name, same annotations if any) and .... the magic can start :) (this is valid only for views, please pay attention!)
What "override" means?
Override means that you take an existent function, "shadow" it by redefining elsewhere (declare a function with the same name, no matter how many parameters it accept, no matter the type of paramenters since php doesn't support method overloading [except if you do some "hack"]) and then you can use it instead of the original one. This is a common technique for add extra functionalities to a function or to change the function itself.
Say that we have two classes, A and B with B that is a child class of A. Say also that A have a method called myMethod().
In B we can do something like
public function myMethod() {
parent::myMethod();
//add extra functionalities here
}
in that way we're adding extra functionalities as we're calling the parent ("original") method and then execute some extra functionalities
Whereas if in B we make something like
public function myMethod() {
//some code here, but not calling parent method
}
we're redefining the behaviour of myMethod()
How Symfony2 let me override methods?
As I said previously in my answer, you have to make your bundle a child of the bundle that containts the function(s) you're trying to override (in that case FOSUserBundle). Once you did it, use the Resources directory of your bundle to accomplish what you need. reproduce the "tree-folder-structure" of the original bundle (ie.: same names of the folders) until you reach the class that contains the function you need to override.
Follow your real example: you need to override execute() function contained in Command/CreateUserCommand.php. You have to create, into your bundle folder that path:
PathTo/YourCostumBundle/Command/
and place inside the file CreateUserCommand.php with the content I show you above.
If you don't understand where I find that path, please take a look to FOSUserBundle code and it will be absolutely clear!
Why is dangerous to modify the FOSUserBundle code directly?
Well, there's a lot of answer an critic point that I can show you. Choosing the main (not ordered for importance):
What if you need to update FOSUserBundle? You'll use composer and lost every modify that you made to FOSUserBundle code
What if you have more than one bundle into your project that need to use FOSUserBundle? Maybe the custom behaviour makes sense for a bundle but not for the other one. Costumizing the behaviour at local bundle level helps you to keep FOSUserBundle logic intact
What if you're developing a bundle that you want to share with other user? You need to force them to "take" your own costumized FOSUserBundle version and warn them about updating it
Finally: I perfeclty know that your entity isn't into FOSUserBundle, but I can bet that they extend FOSUserBundle base user so what I told above is applicable to your case.
Hope it's less fuzzy now :)
Documentation: http://symfony.com/doc/current/cookbook/bundles/inheritance.html#overriding-controllers
I always follow the pattern I learned in the symfony documentation itself:
php bin/console fos:user:create usertest mail#domain.com password
and sometimes I need change the "roles" on the table "fos_user"
then
a:0:{}
to
a:1:{i:0;s:10:"ROLE_ADMIN";}
After creating a user with:
bash-5.1# bin/console fos:user:create admin admin#mydomain.com password123
Promote the user with the ROLE_ADMIN role:
bash-5.1# bin/console fos:user:promote
Please choose a username:admin
Please choose a role:ROLE_ADMIN
Role "ROLE_ADMIN" has been added to user "admin". This change will not
apply until the user logs out and back in again.