Mediawiki Call hook function from another file - php

Hello I need to save some content to database in MediaWiki when a new page is created.
So I added hook in my LocalSettings.php:
$wgHooks['PageContentSaveComplete'][] ='assign_responsibility';
But I need to call the function assing_responsibility() from a extension php file Responsibility.php not LocalSettings.
I am new at Mediawiki system and I cant find out How to tell MediaWiki where it can find required hook function?
Thank you

Hook values are PHP callables; they can be defined in any file as long as the file gets loaded before the hook gets called (or, if you use a class method instead of a global function, the class is registered via $wgAutoloadClasses).
The convention is that your extension (which I assume is called Responsibility) creates a hook file:
// ResponsibilityHooks.php
class ResponsibilityHooks {
public static function onPageContentSaveComplete(/*...*/) { /*...*/ }
// ...
}
and makes sure it can be autoloaded:
// Responsibility.php
$wgHooks['PageContentSaveComplete'][] = 'ResponsibilityHooks::onPageContentSaveComplete';
$wgAutoloadClasses['ResponsibilityHooks'] = __DIR__ . '/ResponsibilityHooks.php';

Related

PHP: $this is not available in non object context in included PHP file

I have a class with the following structure:
/**
* #property int ticket_id
*/
class Test {
public function __construct( $ticket_id ) {
$this->ticket_id = $ticket_id;
$this->register();
}
/**
* Register all hooks
*/
public function register(): void {
add_action( 'wp_ajax_ping', array( $this, 'ping' ) );
}
public function ping(): void {
require_once('ping.php');
}
}
In my ping.php I've tried using my parameter $this->ticket_id but I got an error that $this is not available in non object context:
error_log($this->ticket_id);
And yes, I'm creating a new object from my class:
new Test('123');
Why? I thought I can use it inside any required file too.
Your problem:
Basically, when the interpreter hits an include 'foo.php'; statement, it opens the specified file, reads all its content, replaces the "include" bit with the code from the other file and continues with interpreting...
reference
This means that the included file is parsed by PHP before being "imported" and as it's not in a class context until it's imported, when it's read, so the $this is out of place.
Possible Work arounds:
1) Put the included details in the parent class (copy/paste)
2) Put the included details in their intended class method and use PHP Class Extension to use an Extension class.
3) Extract the info. in the include and place it in its own class entirely. Place the include call in the parent script rather than the test class script. Reference
(there's probably more ideas how to work around your issue, but the best by a loooong chalk is one - to simply copy and paste the code in. If the code is verbose then you can easily hide it with any decent IDE closing off that method to one line of visible code.)
(From the point of view of the PHP compiler you're not saving anything with includes.)

Create a function that can be used anywhere within Wordpress site

I want to create a number of functions in my plugin 'membershipintegration.php' which can be called anywhere on my Wordpress site.
I thought that if I created a class and defined a public function within the class in the membershipintegration.php I could use it wherever I liked.
class MembershipIntegration
{
public function switchmembership () {
echo 'some code'
}
}
However, it doesn't seem to work and I've used 'function_exists' on my sandbox page and it says the function isn't active.
Any thoughts much appreciated. Thank you.
Wordpress automatically load your membershipintegration.php when the plugin is active, then any function created inside this file or any other included file is automatically loaded and available in any place.
The recommendation is:
Create a file called functions.php
<?php
function myFunctionOne(){
//some code
}
and then in your membershipintegration.php use:
require __DIR__.DIRECTORY_SEPARATOR.'functions.php';
There's no such thing as a function inside a class. PHP classes consist of properties and methods. The keyword to define a user-defined method is function so it's a little confusing.
To access a public method, you first need an instance of that method. For instance:
$s = new MembershipIntegration();
Then you can access the public method:
$s->switchmembership();
<?php
require plugin_dir_path( __FILE__ ) . 'file-name.php';
new CLassName();
?>
put this code on your plugin index file then it can be call any where if your plugin is activate

Execute a Function in Silverstripe via Cronjob

Hi I want to execute a function via cronjob to start an csv import. At the moment the import is triggered by accessing a controller in the browser tld.de/Update
The controller has this code http://pastie.org/8351266
How can I execute the function init() via Cronjob?
Thx!
In SilverStripe you can access any route that is accessible via HTTP also by running cli-script.php in the command line
There also is sake which is just a bash wrapper around cli-script.php (but sake needs to be installed)
so, from your project directory, you can run both commands which will perform the same action (in this case, run a dev/build):
php framework/cli-script.php dev/build
sake dev/build
see the docs for commandline ussage of silverstripe: http://doc.silverstripe.org/framework/en/topics/commandline
the 2nd part of your question (how to call a method from a controller) is actually more a question of routing in silverstripe and has nothing to do with how it is called (cronjob)
I assume that your controller is a Page_Controller or a subclass of that (so bound to a SiteTree Model), then routing is done for you (it takes the URLs you set in the CMS).
so lets see some example code and lets assume you have a page with the URLSegment about:
class Page_Controller extends ContentController {
private static $allowed_actions = array('something');
public function init() {
// the init method will run before every action
// this means this code will run, no matter if you visit /about or /about/something
}
public function index() {
// this is the default action (this code is optional and can be removed),
// and will be called if you visit website.com/about
return $this;
}
public function something() {
// this is the somethingaction,
// and will be called if you visit website.com/about/something
// do something here
return $this;
}
}
you can then call run to get the result of the index():
php framework/cli-script.php about
and this to get the result of something():
php framework/cli-script.php about/something
NOTE: the init method itself is not accessable via URL, it is the "setup" that runs before an action
NOTE: all actions other than index() have to be allowed by adding them to $allowed_actions (also note that you need to ?flush=1 after adding to $allowed_actions to reload the config cache)
EDIT: this was actually the response to your first question, after seeing your code example, this addition:
for standalone controllers it works the same way, just that you have to define the routes, and make sure that you have $Action in the route so that something() can be called
You could do this without Silverstripe sake. Install curl and call the URL via a cronjob, ie:
0 0 * * * curl --silent http://tld.de/Update
The proper way to do this would be to write a Silverstripe task, and invoke your controller from within the task. I haven't tested this code but it would go something like this:
class YourTask extends BuildTask {
public $description = "...";
//...
public function run($request) {
YourController::init();
}
}
You can invoke it over sake using:
0 0 * * * /path/to/framework/sake dev/tasks/YourTask
why not create a build task ? which is specially designed for such requirements (at-least that's how I consider build tasks)
<?php
class ArticleCsvUpdateTask extends BuildTask {
protected $title = 'Article Csv Update';
protected $description = 'Build task for article Csv update';
public function run($request) {
$loader = new ArticleCsvBulkLoader('Color');
if($loader->load('import-new.csv')) {
$loader->load('import-new.csv');
}
}
}
Which can be assess both from browser using "yoursite/dev/tasks/ArticleCsvUpdateTask" and from command line using "php framework/cli-script.php dev/tasks/ArticleCsvUpdateTask" OR using "sake dev/tasks/ArticleCsvUpdateTask" (if you have sake installed).
May be I am not getting your exact requirement but I believe this is much cleaner and nicer way of running a cron job with silverstripe.
See Zauberfisch's answer for a complete solution
I'm not familiar with Silverstripe, but if I understand correctly, this controller init function can be called with a HTTP request.
As the silverstripe docs say, you can call any url from the command line:
php framework/cli-script.php Update/init
More information is available here, and consider using sake for this task.
I think the right way do this is create a php file console like:
#!/usr/bin/env php
<?php
require_once "/path/to/your/class/Update.php";
$class = new Update();
$class->init();
Add right perms to this file
chmod 755 consolefile
And finally run this script with cronjob

Can spl_autoload be placed in another file?

I'm currently making my first website with PHP. Rather than writing autoload for each individual page, I wish to create one file with a general autoload ability.
Here is my autoloadControl.php:
// nullify any existing autoloads
spl_autoload_register(null,false);
//specify extensions that may be loaded
spl_autoload_extensions('.php. .class.php');
function regularLoader($className){
$file = $className.'.php';
include $file;
}
//register the loader function
spl_autoload_register('regularLoader');
Here is my index.php file:
require("header.php");
require("autoloadControl.php");
$dbConnection = new dbControl();
$row=$dbConnection->getLatestEntry();
Currently, the $dbConnection = new dbControl() gives me the following error:
Fatal error: Class 'dbControl'
So my question is, is there a way to use autoload this way or must I place it at the top of every PHP file I write that uses another file?
Placing spl_autoload in an external file is both valid and a good practice for making your code more maintainable--change in one place what could be 10, 20, or more.
It appears that your dbControl class is not being provided in the code you provided. Assuming you are including the class before referencing it, and the class works properly, then you should have no problem accomplishing this task.
require("header.php");
require("autoloadControl.php");
$dbConnection = new dbControl(); // Where is this class located?
Here is an OOP approach for your autoloadControl.php file:
<?php
class Loader
{
public static function registerAutoload()
{
return spl_autoload_register(array(__CLASS__, 'includeClass'));
}
public static function unregisterAutoload()
{
return spl_autoload_unregister(array(__CLASS__, 'includeClass'));
}
public static function registerExtensions()
{
return spl_autoload_extensions('.php. .class.php');
}
public static function includeClass($class)
{
require(PATH . '/' . strtr($class, '_\\', '//') . '.php');
}
}
?>
Your problem is not related to where you are defining your callback, but how.
Using spl_autoload_extensions('.php') would achieve the same thing as your custom callback; you don't need both if your callback is as simple as this. Your comment is also wrong - calling spl_autoload_register with no arguments will not clear current callbacks, but it will register the default callback.
However, in your code, you have specified the argument to spl_autoload_extensions incorrectly - it should be a comma-separated list of extensions. So I think what you want is this:
// Tell default autoloader to look for class_name.php and class_name.class.php
spl_autoload_extensions('.php,.class.php')
// Register default autoloader
spl_autoload_register();
// READY!
The main difference this will make from your code is that the default autoloader will look for 'dbcontrol.php' (all lower-case) whereas yours will look for 'dbControl.php' (case as mentioned in PHP code). Either way, you certainly don't need both.

How to refer to a function?

I am learning how to use hooks in mediawiki. I am also new to PHP.
General hook handler can be added by putting next line in to LocalSettings.php:
$wgHooks['event'][] = 'function';
Suppose I wrote myfunction in my.php file. How can I point to this function from LocalSettings.php
Edit. I have written some function in my.php file. How to refer to this function?
I should tell mediawiki where find this function.I don't know how to do it.
Should I write '$wgHooks['event'][] = 'my.php:function'. Or I should include my.php file to LocalSetting and then just write '$wgHooks['event'][] = 'function'
As the docs say, you need to push a string with your function name (or an array of strings etc.) to the hook array.
AFAIK, when triggering the hook they will be invoked with call_user_func(). So, it will depend on your function declaration in the my.php file. With a myfunction, it should be
$wgHooks['event'][] = 'myfunction';
from what i read from the mediawiki docs, you need to create an extension, and in your extension you install your hook. in my.php you will write:
// $wgHooks is a global variable
$wgHooks['event'][] = 'function';
Hope i understand correctly
Extension docs
http://www.mediawiki.org/wiki/Manual:Extensions
I am not sure I understand completely what you want, but if you want to call a user defined function you can use call_user_func which takes as argument the name of your function. You have to include the file so the function will be available.
call_user_func('myfunction ', array());
You refer to functions via callbacks in PHP. A callback is one of these:
a function name: 'myFunc'
an array containing a class name and a function name: array('MyClass', 'myFunc')
an array containing an object and a function name: array($myObj, 'myFunc')
an anonymous function (which is technically a Closure object): function($x, $y) { /* PHP code */ } (this is PHP 5.3+ only, but so are recent versions of MediaWiki)
Invoking these callbacks via call_user_func($callback, $arg1, $arg2) will be equivalent to the following, respectively:
myFunc($arg1, $arg2);
MyClass::myFunc($arg1, $arg2);
$myObj->myFunc($arg1, $arg2);
executing the body of the anonymous function, replacing $x and $y with $arg1 and $arg2
If this code would fail (e.g. you use the first version, and the function myFunc is not loaded), the callback will also fail. You can use autoloading with the second form, in MediaWiki that is normally done via $wgAutoloadClasses:
// in MyExtension.php
$wgHooks['event'][] = array('MyExtension', 'myEventHandler');
$wgAutoloadClasses['MyExtension'] = dirname(__FILE__) . 'MyExtension.body.php';
// in MyExtension.body.php
class MyExtension {
public function myEventHandler($p1, $p2) {
// do stuff
}
}
That way, you can load MyExtension.php (which is a small file with configuration settings only) from LocalSettings.php, and MyExtension.body.php (which has all the code) only gets loaded in those requests which actually use your extension.

Categories