Computer lessons

Creation of aliases and redirects. Apache

To create an alias (alias) for a path, use the Yii::setAlias() method:

// alias for the folder path Yii::setAlias("@myalias", "/path/to/myfolder");
// alias folder path based on another alias Yii::setAlias("@img", "@myalias/path/to/img");
// URL alias Yii::setAlias("@mysite", "http://mysite.com");

Path aliases in yii2 can be set in the application configuration file using the aliases property, example:

Return [ // ... "aliases" => [ "@myalias" => "/path/to/myfolder", "@mysite" => "http://mysite.com" ], ];

How to get a path alias in Yii 2

To get a path alias in yii2, use the Yii::getAlias() method:

Echo Yii::getAlias("@myalias"); // returns: /path/to/myfolder echo Yii::getAlias("@mysite"); // returns: http://mysite.com echo Yii::getAlias("@myalias/other/folder/index.php"); // returns: /path/to/myfolder/other/folder/index.php

More on path aliases in Yii 2

Nickname

The alias name can contain /, and the Yii::getAlias() method will determine which part is the alias name and which part is an additional path, for example:

Yii::setAlias("@test", "/path/to/test"); Yii::setAlias("@test/val", "/path/to/val"); Yii::getAlias("@test/folder/index.php"); // will return: /path/to/test/folder/index.php Yii::getAlias("@test/val/index.php"); // will return: /path/to/val/index.php

If the alias @test/val had not been defined on line 2, line 4 would have returned /path/to/test/val/index.php

Extension aliases

When installing an extension using composer, it is automatically given an alias (path to the root directory of the extension). For example, when installing imperavi redactor (vova07/yii2-imperavi-widget), you will have access to the path alias @vova07/imperavi (@vendor/vova07/yii2-imperavi-widget/src)

Path aliases in Yii 2 basic application

List of basic, predefined aliases (aliases) of paths in yii2 basic:

  • @web: Application base URL
  • @webroot: Webroot applications

Aliases of paths in Yii 2 advanced application

List of basic, predefined aliases (aliases) of paths in yii2 advanced:

  • @app: Application root directory
  • @vendor: Vendor folder, under @app
  • @runtime: Path to temporary application files runtime/cache
  • @web: Application base URL
  • @webroot: Directory with application tests
  • @tests: Directory with application tests
  • @common: Alias ​​for the common directory under @app
  • @frontend: Alias ​​for the frontend directory under @app
  • @backend: Alias ​​for the backend directory, under @app
  • @console: Alias ​​for the console directory under @app
  • Translation

Bash aliases are shortcuts to files that allow you to refer to another command through more memorable words, abbreviations, or symbols. For example, if you use Git, you may run git status many times throughout the day, so to save time and keystrokes, you can give it an alias that will call the correct command.

I've seen a lot of unusual nicknames over the years, and many of them are unique to the person. Labels that make sense to one may be completely confusing to another. That's what makes them so funny.

Nah="git reset --hard;git clean -df"
This can be really demonstrated: imagine that you started working on a new feature and perhaps added a few new files, and after lunch you decided that you did everything wrong. Running the "nah" command will return the code to its previous state, removing any changes you made. It's very convenient and useful!

How to create your own aliases

For those who don't create bash aliases, the process is quite simple. First, use a text editor to open the ~/.bashrc file located in your home directory. Then uncomment or add the following lines:

If [ -f ~/.bash_aliases ]; then. ~/.bash_aliases fi
The command seems to tell you to load the ~/.bash_aliases file if it exists, so you can put all your aliases into it and make them easier to share. Finally, create a ~/.bash_aliases file and add the following as your first alias:

Alias ​​art="php artisan"
Save the changes and run the command in the terminal:

Source ~/.bashrc
You can now use the "art" alias.

Just remember that every time you change the ~/.bash_aliases file, you need to run this command, or restart your terminal for the changes to take effect.

Community aliases for Laravel

Below is a list of aliases used by the Laravel community:

WaveHack

# Laravel artisan() ( if [ -f bin/artisan ]; then php bin/artisan "$@" else php artisan "$@" fi ) alias serve="artisan serve" alias tinker="artisan tinker" # Misc PHP t() ( if [ -f vendor/bin/phpunit ]; then vendor/bin/phpunit "$@" else phpunit "$@" fi )

bmadigan

nah="git reset --hard;git clean -df" vm="ssh [email protected]-p 2222"

Tainmar

pa="php artisan"

Mohamed Said

alias dracarys="git reset --hard && git clean -df" alias copyssh="pbcopy< $HOME/.ssh/id_rsa.pub" alias reloadcli="source $HOME/.zshrc" alias zshrc="/Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl ~/.zshrc " alias shrug="echo "¯\_(ツ)_/¯" | pbcopy"; alias fight="echo "(ง"̀-"́)ง" | pbcopy"; *** This one opens a PR from the current branch function openpr() { br=`git branch | grep "*"` repo=$1 parentBranch=$2 open -a /Applications/Google\ Chrome.app https://github.com/${repo/* /}/compare/${parentBranch/* /}...themsaid:${br/* /}\?expand\=1 }

Jeffrey Way

alias gl="git log --graph --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset" --abbrev-commit" alias wip="git add . && git commit -m "wip"" alias nah="git reset --hard && git clean -df" alias p="phpunit" alias pf=" phpunit --filter " alias art="php artisan" alias migrate="php artisan migrate"

Bill Mitchell

alias a="php artisan" alias pu="vendor/bin/phpunit" alias puf="vendor/bin/phpunit --filter " alias pug="vendor/bin/phpunit --group " alias cdo="composer dump- autoload -o" alias serve="php artisan serve"

Jesus Amieiro

alias pa="php artisan" alias par:l="php artisan route:list" alias pam="php artisan migrate" alias pam:r="php artisan migrate:refresh" alias pam:rs="php artisan migrate:refresh --seed" alias cu="composer update" alias ci="composer install" alias cda="composer dump-autoload -o" alias vu="cd ~/Homestead && vagrant up" alias vs="vagrant suspend" alias vssh ="vagrant ssh"

Piotr

alias artisan = "php artisan" alias db-reset="php artisan migrate:reset && php artisan migrate --seed"

freekmurze

alias a="php artisan"

paulredmond

alias _="sudo" alias art="php artisan" alias tinker="php artisan tinker" alias ll="ls -lh" alias la="ls -lAh" alias c="composer" alias iphp="psysh" # repl alias g="git" alias gs="git status" alias d="docker" alias dc="docker-compose" alias dm="docker-machine" alias k="kubectl" alias publicip="dig +short myip .opendns.com @resolver1.opendns.com" alias chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome" # Show file and folder permissions as octal # Usage: `octal file.txt` or `octal my/path` alias octal="stat -f "%A %a %N"" # Mac conveniences for Linux alias pbcopy="xclip -selection clipboard" alias pbpaste="xclip -selection clipboard -o" if type " xdg-open" &> /dev/null; then alias open="xdg-open" fi

TJ Miller

nah: aliased to git reset --hard && git clean -fd aa: aliased to php artisan

sebastiaanluca

# Hub (extend git commands) alias git=hub # Directories alias ll="ls -FGlAhp" alias ..="cd ../" alias ...="cd ../../" alias .... ="cd ../../../" alias .....="cd ../../../../" alias df="df -h" alias diskusage="df" alias fu="du -ch" alias folderusage="fu" alias tfu="du -sh" alias totalfolderusage="tfu" alias finder="open -a "Finder" ." # Vagrant alias vagrantgo="vagrant up && vagrant ssh" alias vgo="vagrantgo" alias vhalt="vagrant halt" alias vreload="vagrant reload && vgo" # PHP alias c="composer" alias cr="composer require" alias cda="composer dumpautoload" alias co="composer outdated --direct" alias update-global-composer="cd ~/.composer && composer update" alias composer-update-global="update-global-composer" alias a="php artisan" alias pa="php artisan" alias phpa="php artisan" alias art="php artisan" alias arti="php artisan" alias test="vendor/bin/phpunit" alias y="yarn" alias yr="yarn run" # Homestead alias edithomestead="open -a "Visual Studio Code" ~/Homestead/Homestead.yaml" alias homesteadedit="edithomestead" alias dev-homestead="cd ~/Homestead && vgo" alias homestead-update="cd ~/Homestead && vagrant box update && git pull origin master" alias update-homestead="homestead-update" # Various alias editaliases="open -a "Visual Studio Code" ~/.bash_aliases" alias showpublickey="cat ~/.ssh/id_ed25519.pub" alias ip="curl icanhazip.com" alias localip="ifconfig | grep -Eo "inet (addr:)?(*\.){3}*" | grep -Eo "(*\.){3}*" | grep -v "127.0.0.1"" alias copy="rsync -avv --stats --human-readable --itemize-changes --progress --partial" # Functions mkcdir () { mkdir -p -- "$1" && cd -P -- "$1" } function homestead() { (cd ~/Homestead && vagrant $*) } !}

Alexander Melihov

alias ars="php artisan serve" alias art="php artisan tinker"

jordonbaade

alias l="php artisan"

Deleu

alias unit="php vendor/phpunit/phpunit/phpunit" alias unitreport="php -d xdebug.profiler_enable=On vendor/phpunit/phpunit/phpunit --coverage-html=./public/report" alias laravel-installer=" composer create-project --prefer-dist laravel/laravel"

curieuxmurray

alias artisan="php artisan" alias cclear="php artisan cache:clear" # now with 5.5 alias fresh="artisan migrate:fresh --seed"

wilburpowery

alias pf="phpunit --filter" alias artisan="php artisan" alias tinker="php artisan tinker"

waunakeesoccer1

alias mfs="php artisan migrate:fresh --seed"

From the translator

I myself use the following aliases:

Alias ​​art="php artisan" alias da="composer dumpauto" alias migrate="php artisan migrate"

Aliases in Windows

On the Windows operating system, aliases are specified using the doskey command. For example:
dokey art=php artisan $*

But there is one “BUT”: the next time you open the Windows command line, it will “forget” them. It's very easy to fix this problem.

For convenience, go to the folder with your account %USERPROFILE% and create a file dos_aliases.bat in it.

Inside the file we write the commands we need, for example:

Doskey art=php artisan $*

“Dollar with an asterisk” gives the alias the understanding that some arguments and/or parameters can be passed to it, for example, art -V to display the version of the engine kernel.

Next, in the start menu, find the command line (cmd.exe), right-click on it and create a shortcut, saving it to the desktop. Next, right-click on this shortcut, selecting “Properties” in the drop-down menu (in English “Properties” or “Eigenschaften” in German), then in the “Target” field (“Target” in English, or “Ziel” in German, depending on the OS localization used), where we see the line %windir%\system32\cmd.exe , add /k %USERPROFILE%\dos_aliases.bat . Thus, we force our file to be loaded every time we launch the command line, opening it using this shortcut.

The full line will look like this:
%windir%\system32\cmd.exe /k %USERPROFILE%\dos_aliases.bat

After that, save and launch the command line using the shortcut we edited. Voila!

OpenServer

For those who use the console included with OpenServer, things are even simpler: the console configuration is stored in the file %ConEmuBaseDir%\CmdInit.cmd .

Of course, if you enter it in the path, the operating system will swear. This is because she does not know about the existence of this path - it is used inside the OpenServer environment so as not to clutter the system.

So, we will find the file we need in the folder with OpenServer installed: \modules\conemu\ConEmu\CmdInit.bat.

Open it with a text editor and add our command at the bottom of the file:

Doskey art=php artisan $*

Save and launch the console. Profit!

By analogy, you can add absolutely any commands that will make your life easier by reducing the time it takes to enter them.

Windows PowerShell

We launch Windows PowerShell as an administrator and check the rights to run individual scripts with the `ps1` extension by running the command:

Get-ExecutionPolicy

By default, the `Restricted` policy is set, prohibiting the execution of any scripts. We will replace it with `RemoteSigned`, which allows you to run all scripts except those downloaded from the network:

Set-ExecutionPolicy RemoteSigned

New-Item -type file $PROFILE

At this point, an error may appear because the directory " was not found in the "My Documents" folder. WindowsPowerShell" - let's create it... yes, manually. Then we will repeat the command.

Go to the `%USERPROFILE%\Documents\WindowsPowerShell` folder and open the `Microsoft.PowerShell_profile.ps1` file with a text editor. We will enter our teams into it.

Firstly, I immediately specified the transition to the desired directory:

Cd "f:\dev\domains\"

And below are the following aliases:
art = php artisan migrate = php artisan migrate down = php artisan down up = php artisan up cclear = php artisan cache:clear da = composer dumpauto docup = docker-compose up -d nginx mysql redis beanstalkd docdown = docker-compose kill doc = docker-compose exec workspace bash

In order to specify a command with a parameter in PowerShell, you need to use a function, within which the received arguments will be passed on. Thus, the alias for the `art` command in PowerShell takes the form:

Function Call-Art ( php artisan $args ) New-Alias ​​-Name art -Value Call-Art

And I’ll end the article with a complete list of my aliases in Windows PowerShell:

# Set Main Directory cd "f:\dev\domains\" # Artisan Commands. function Call-Art ( php artisan $args ) New-Alias ​​-Name art -Value Call-Art # Run the database migrations. function Call-Art-Migrate ( php artisan migrate ) New-Alias ​​-Name migrate -Value Call-Art-Migrate # Put the application into maintenance mode. function Call-Art-Down ( php artisan down ) New-Alias ​​-Name down -Value Call-Art-Down # Bring the application out of maintenance mode. function Call-Art-Up ( php artisan up ) New-Alias ​​-Name up -Value Call-Art-Up # Flush the application cache function Call-Art-Cache-Clear ( php artisan cache:clear ) New-Alias ​​-Name cclear -Value Call-Art-Cache-Clear # Composer Dump-Autoload. function Call-Composer-Dump-Autoload ( composer dumpauto ) New-Alias ​​-Name da -Value Call-Composer-Dump-Autoload # Start the Docker function Call-Start-Docker ( docker-compose up -d nginx mysql redis beanstalkd ) New -Alias ​​-Name docup -Value Call-Start-Docker # Kill the Docker function Call-Kill-Docker ( docker-compose kill ) New-Alias ​​-Name docdown -Value Call-Kill-Docker # Enter the Docker function Call-Enter- Docker ( docker-compose exec workspace bash ) New-Alias ​​-Name doc -Value Call-Enter-Docker

From now on, every time you start the program shell, our file will be automatically loaded, providing the opportunity to use your favorite commands.

Hello all readers!

Today we will look at a rather important topic that is put forward by many employers, namely multilingualism.

What did I mean when I spoke about multilingualism? Well, probably each of my esteemed readers have seen cool portals more than once and among all the rabble of information they found two small icons, mainly with the well-known stars and stripes and the familiar white-blue-red flags. Of course, after clicking on one of them, the Russian speech we are accustomed to turned into bourgeois language (), or vice versa. But have you ever asked yourself how this is all done? Well, that's exactly what I'm going to talk about.

I’ll say right away that to work with the material that will be presented here, you will need PHP support of at least 4.39.

So, as you know, the content of our site is divided into dynamic and static. We consider static content to be something that will not change its meaning during operation (keywords, error text, and other nonsense). This is where we will start. But let's analyze exactly how we will change the language of a given text value. I hope no one suggested using exceptions, because this is so irrational that it couldn’t be more irrational. Instead, I suggest using constants (read about data types on php.net). We will simply declare a function word, which, depending on the meaning of the language, will accordingly change its meaning. How do we do this? Yes, like everyone else, let’s create two (for example) different files, the names of which will have the following pattern:

Language_map.php;

As you already understood, instead of the word `language` we will substitute a value that characterizes this language. In our case, we will use a two-character language code (ru, en, ua, pl, etc.).

Well, we’ve figured out the theory, now let’s put our knowledge into practice. We create two files. I created files with English translation and Russian, and how you create it is up to your taste.

File: en_map.php

File: ru_map.php

So, in my opinion, there is nothing complicated, and everything written is subject to the most banal laws of RHP. First, we check whether the constants have already been declared; if they were, then we do not declare them; otherwise, we declare them.

This was the easy part, now let's move on to a more difficult topic - translating the dynamic part.

Let's say you have a large portal system or a simple website, but you, a talented programmer who knows all aspects of PHP, are not its owner, but made it to order. The owner is a full-time designer (), who has no idea, no idea about any programming subtleties, but he has only one desire for everything to work, and he can change everything. As for everything, that’s another story, but we will still allow him to change the language parameters of the site (whatever the child amuses himself with).

But again returning to the dilemma about “Designers and Programmers”, it is necessary to mention again that such a site must be completely, so to speak, “What You See Is What You Get,” otherwise it is impossible. Therefore, I will try to do everything so that it does not cause nervous tics in programmers, and can satisfy designers (meaning usability).

So, away with empty words and forward to Berlin. We'll start with theory. So, how are we going to distinguish between the languages ​​of dynamic content, which, at best, is removed, changed, or even worse? There is no way to use constants here, so what should we do?

I can already hear the thoughts floating around you.

Personally, when I tried to bring this to life, at first I did it in the most irrational way, namely, to translate articles, I divided the fields in the table that were subject to translation in two (that is, I created field_eng and field_ru) in this way, already large tables turned into simply obscenely huge. So I started looking for an alternative, and believe it or not, I found it. Do you already feel warmer, yes, soon we will come to the hottest part. I found a way out of this situation, and now I intend to explain it to you, and whether you understand it or not will depend on you. First, let's agree on all the details.

First, we need a table in which the data for translation will be placed. Let's say we have a table `articles` in which some articles will be placed, and they should have, say, two translations, but one is required. We will be interested only in two key, in our case, fields: title, description. We will structure the text in this way:

<%eng%>English version of the article <%ru%>Russian version of the article

Then the line, as a combination of these two structures, will be added to the `title` and `description` fields of the `articles` table.

This method will consist of searching for the first occurrence of the opening keyword (for example<%eng%>), then we will find the first occurrence of the closing keyword. But we must not forget that we need not just the entry, but the length of the structure. In the first case, we will add the length of the structure to the first occurrence of the opening structure; the second step will be to find the length of the closing structure. But you ask:<Как же мы получим текст?>.

Using the substr() function. The first parameter will be the text itself, the second will be the length of the opening structure, and the third (most interesting) will be the difference between the first occurrence of the closing structure and the length of the text. Yes, I understand it is not so easy, but it needs to be understood. Therefore, we will now do this in practice. I created a function that will highlight text between key tags. It will take three parameters: the text to be parsed, the language to be used for parsing, and an array of structures.

","<%/","%>")) ( $start_tag=strpos($data,$delimiters.$lang.$delimiters)+ strlen($delimiters.$lang.$delimiters); $count=(strpos($data,$delimiters.$lang.$ delimiters)-strlen($data)) $data=substr($data,$start_tag,$count); if(trim($data)=="")( $data=NOT_ENTERED; ) return $data; ) ?>

As you can see, it’s quite long and you can get confused, but if you don’t understand this, then it’s not a big problem, because the function for enumerating already exists, and a little further I’ll look at another method for the same purpose. Yes, and don’t forget to declare the language constant NOT_ENTERED somewhere, which will be assigned to the result of the function if the text length is zero.

So, we figured it out by brute force, but now we are faced with a new task, compiling plain text into a specially formatted string. This is already much simpler, and if you know PHP well enough, then you can easily write such a function, and if you are still swimming, then please go to the office.

The algorithm is not complicated and consists in substituting all language constructs in one line. At first, in a fit of laziness, I wanted to limit the script to a certain number of languages ​​(this makes it easier to implement), but then I changed my mind and got this:

","<%/","%>")) ( if(!is_array($data)) ( die(PARAM_CHECK_ERROR); ) $data=""; $temp=""; $count=0; foreach($data as $k=>$v) ( if(!is_string($k)) ( break; ) $count++; if($count>1 & $temp=$k) ( die(ERROR_CONSTRUCTION_COUNT); ) $temp=$k; $data.=$delimiters.$ k.$delimiters.$v.$delimiters.$k.$delimiters; ) return $data; ) ?>

Well, here I will explain a little. The function takes an array as a parameter. The array structure should be like this:

"language identifier"=>"text";

Afterwards we check that if the received parameter is not an array then<пока Вася!>.

If it is still an array, then of course we enumerate it, and in place of the language in the construction we put the key of this element of the associative array, and in place of the text, of course, the text itself, that is, the value of the $v variable. Then we merge all the data into one line. But I forgot to mention one important detail, in other words, a rather large piece of text. First, before the loop, we declared three variables: data, temp, count;

The count variable is the number of iterations of the loop, and with each subsequent round of the loop the counter increases. The data variable is the future resulting string into which all language constructs will be merged. But the variables count and temp are more interesting. What are they needed for? Well, most people probably already guessed it after reading the source, but for those who haven’t yet<дошло>I'll explain. This is done to check that the language construct has not been repeated more than once. This is why we declared the count variable. Since its default value is zero, we check that the loop has been executed at least once, because if we don’t do this, something like 2=2 or 0=0 will come out, because the value of $k has not yet changed . Since the check will be ignored the first time, we assign the value to the $temp variable after the check. This is also done for a reason. During the first iteration, everything will go fine, but if we nevertheless assigned a value before the check, then the check would do the check that was already mentioned (2=2, 3=3, etc.). That's why we do it this way.

Now, as a logical conclusion, we will create a small website where all of the above will be applied:

","<%/","%>")) ( $data=substr($data, (strpos($data,$delimiters.$lang.$delimiters)+ strlen($delimiters.$lang.$delimiters)), (strpos($data,$delimiters. $lang.$delimiters)-strlen($data))); if(trim($data)=="") ( $data=NOT_ENTERED; ) return $data; ) function compilateLanguageString($data, $delimiters=array( "<%","%>","<%/","%>")) ( if(!is_array($data)) ( die(PARAM_CHECK_ERROR); ) $data=""; $temp=""; $count=0; foreach($data as $k=>$v) ( if(!is_string($k)) ( break; ) $count++; if($count>1 & $temp=$k) ( die(ERROR_CONSTRUCTION_COUNT); ) $temp=$k; $data.=$delimiters.$ k.$delimiters.$v.$delimiters.$k.$delimiters; ) return $data; ) //Don't forget about<статике>if(!isset($_GET["lang"])) ( setcookie("lang",$_GET["lang"]); header("Location: index.php?module=home"); ) if(isset( $_COOKIE["lang"])) ( include $_COOKIE["lang"]."_map.php"; ) else ( include "ru_map.php": ) if(isset($_POST["add"])) ( $description=compilateLanguageString(array($_POST["description_en"],$_POST["description_ru"])); $title=compilateLanguageString(array($_POST["titlte_eng"],$_POST["title_ru"])); //Process of adding to the database ) echo" "; echo" "; echo" "; $title=($_SERVER["REMOTE_ADDR"]=="127.0.0.1")? ADMIN_WELCOM: "Hello guests!"; echo $title; echo""; echo" "; echo"":echo" "; $conn_id=@mysql_connect("localhost","root",""); @mysql_select_db("somedatabase"); $q=@mysql_query("SELECT title, description FROM `articles` LIMIT 0,1",$ conn_id); if(@mysql_ num_rows($q)==0)( ARTCILES_NOT_FOUNDED; ) else ( $row=@mysql_fetch_array($q); $title=subTextByLang($row["title"],$lang); $ description=subTextByLang($row["description"],$lang); echo"

":echo" "; echo" "; echo" "; echo"
".ARTICLE_TITLE_TEXT."". $title."
".ARTICLE_DESCRIPTION_TEXT."
".$description."
"; ) @mysql_close($conn_id); //That's not so bad, now you need to create a form to add an article echo"
"; echo" "; echo" "; echo" "; echo" "; echo" "; echo" "; echo" "; echo" "; echo"
".ARTICLE_TITLE_TEXT." (EN):
".ARTICLE_TITLE_TEXT." (RU):
".ARTICLE_DESCRIPTION_TEXT."(EN):
"; echo" "; echo"
".ARTICLE_DESCRIPTION_TEXT."(RU):
"; echo" "; echo"
"; echo"
"; ?>

Well that's it. However, there is one “but” in the script; the author cannot add more than two translation options through the form. I won’t, like the other authors, say that I did this for your training, because to be honest, when I got to this point, my head almost didn’t bother me anymore, so I’m leaving it on your shoulders. Believe me, there are plenty of possible solutions, and I really hope that you find it. Regarding the functions, I cannot say 100% that they will not cause a failure, but there should not be fatal errors, although anything can happen. But I am more than 60% sure that the syntax is broken, since I did not test the examples. But here is a really good training for you, because catching “fleas” is a very useful activity!

Well, I think this article can end here. If you don’t succeed, don’t direct your anger at your poor computer, at your keyboard, and especially at the developers of such a wonderful language as PHP, feel free to direct all your failures in my direction. I don’t think this will make me any worse, but you will have someone to take your anger out on.

You place configuration data in an extension.json or skin.json file in the root directory of your extension or skin, and MediaWiki uses it to register the extension or skin.

Before MediaWiki 1.25, the configuration for extensions and skins was in a PHP file named the extension or skin, such as MyExtension.php or MySkin.php.

require_once " $IP /extensions/Hello/Hello.php" ; require_once " $IP /extensions/FooBar/FooBar.php"; $wgFooBarEnable = true ; require_once " $IP /skins/Baz/Baz.php" ;

Now you can convert it to:

wfLoadExtensions ( array ( "Hello" , "FooBar" ) ); $wgFooBarEnable = true ; wfLoadSkin("Baz");

If you're not storing the extension in $IP/extensions , you'll need to override $wgExtensionDirectory . If you're not storing skins in $IP/skins , you'll need to override the poorly named $wgStyleDirectory . This must be done before you download an extension or skin.

$wgExtensionDirectory = "/some/path" ; wfLoadExtension("FooBar"); // Looks for /some/path/FooBar/extension.json$wgStyleDirectory = "/my/skins" ; wfLoadSkins ( array ( "BarBaz" , "BazBar" ) ); // Looks for /my/skins/BarBaz/skin.json and /my/skins/BazBar/skin.json

Since MW 1.30, namespace IDs defined in extension.json can be overwritten locally, by defining the respective constant in LocalSettings.php before loading the extension. Consider for instance the following namespace declaration in a extension.json file:

"namespaces" : [ ( "id" : 1212 , "constant" : "NS_FOO" , "name" : "Foo" ), ( "id" : 1213 , "constant" : "NS_FOO_TALK" , "name" : "Foo_Talk" " ) ]

This would per default cause the constant NS_FOO to be defined to have the value 1212. However, this can be overwritten by defining the respective constant in LocalSettings.php:

define("NS_FOO", 6688); define("NS_FOO_TALK", 6689); wfLoadExtension("Foo");

This would cause the "Foo" namespace to be registered with the ID 6688 instead of 1212. When overriding namespace IDs, don"t forget that all talk namespaces must have odd IDs, and the ID of the talk namespace must always be the subject namespace "s ID plus one.

Contents

Migration for Extension Developers

See also the extension registration wall of sadness (now superpowers) .

The maintenance/convertExtensionToRegistration.php script will help you migrate from PHP entry points(?) to a JSON metadata file. If your extension supports older versions of MediaWiki, you should leave your entry point FooBar/FooBar.php until you stop supporting older versions.

Example of running a command:

$ cd core $ php maintenance/convertExtensionToRegistration.php extensions/MassMessage/MassMessage.php $ php maintenance/convertExtensionToRegistration.php skins/MonoBook/MonoBook.php --skin

You may need to uninstall your extension from LocalSettings.php if you are getting errors that constants or functions cannot be overridden.

You should replace your PHP entry point (FooBar.php file) with something like the following to avoid breaking the wiki during the upgrade process.

"Deprecated PHP entry point used for the FooBar extension." . "Please use wfLoadExtension instead," "This version of the FooBar extension requires MediaWiki 1.29+" ); }

Or styles:

// Keep i18n globals so mergeMessageFileList.php doesn't break$wgMessagesDirs [ "FooBar" ] = __DIR__ . "/i18n" ; $wgExtensionMessagesFiles [ "FooBarAlias" ] = __DIR__ . "/FooBar.alias.php" ; wfWarn( "Deprecated PHP entry point used for the FooBar skin. Please use wfLoadSkin instead, ". "see https://www.." ); return ; ) else ( die ( "This version of the FooBar skin requires MediaWiki 1.25+" ); }

Supporting Documentation

PHP entry points usually have configuration settings documentation, which is useful and shouldn't get lost. Unfortunately JSON does not support comments. It is recommended to move the configuration documentation to the README file of the extension repository. You should also document the configuration in the wiki on your Extension page: MyExtension. It's also possible to add some documentation directly to extension.json. Registering an extension ignores any keys in extension.json starting with "@" in the structure root or under config , so you can put comments in those places. For example:

( "@note" : "This file must be kept in sync with LocalizationUpdate.php", "@name" : ...

Version 1 of the extension.json format also allowed @note in config section, but this is no longer recommended or supported in version 2. description field of the config variable should be used instead.

This should be used for brief notes and comments only.

Possibilities

If you download a large number of extensions, registration of extensions may be faster if you have APC (or APCu) installed. Extensions that are loaded with wfLoadExtension s(with multiple -s) will be cached together.

Attributes

A recurring problem is how to "register" something with a different extension. This usually means that you want to load one extension before another. For example VisualEditor has $wgVisualEditorPluginModules which allows extensions to load their modules. However, at the VisualEditor entry point there is:

$wgVisualEditorPluginModules = array();

This means that if an extension is added to the array before VisualEditor, VE will erase that entry in the array. Some extensions depended on a specific load order, others hacked this using $wgExtensionFunctions . Registering extensions solves this problem using "attributes". In an extension Math its extension.json has something like the following

("VisualEditorPluginModules": ["ext.math.visualEditor"])

Starting with manifest version 2, the attributes need to be defined in the separate section section attributes .

The attributes node needs to be an object with the extension name as key and an object of attribute/value pairs as the value. Be aware that the key in the subobject must not contain the extension name!

( "attributes" : ( "VisualEditor" : ( "PluginModules" : [ "ext.math.visualEditor" ] ) ), "manifest_version" : 2 )

When VisualEditor wants to access an attribute, it uses:

ExtensionRegistry::getInstance() -> getAttribute("VisualEditorPluginModules");

Requirements (dependencies)

Extension registration has a requires section, which acts similar to Composer "s require section. It allows an extension developer to specify several requirements for the extension, such as a specific MediaWiki version (or greater/less than) or another extension/skin. For example, to add a dependency on a MediaWiki version that is greater than 1.26.0, you can add the following code to extension.json:

("requires": ("MediaWiki": ">= 1.26.0"))

The key of the requires object is the name of the dependency (prior to MediaWiki 1.29.0 only MediaWiki was supported), the value is a valid version constraint (the format has to match the one used by composer).

In MediaWiki 1.29.0 and above you can also add dependencies on skins and other extensions like so:

( "requires" : ( "MediaWiki" : ">= 1.25.0" , "extensions" : ( "FakeExtension" : "*" ), "skins" : ( "FakeSkin" : "*" ) ) )

Check, if an extension is loaded without actually requiring it

Many extensions may provide features that work only if another extension is loaded too, without really needing this feature for the core extension function to work. As an example: If extension B is loaded, extension A can provide a real WYSIWYG editor, otherwise it will use a simple textarea. Extension A can profit from extension B (if it is loaded), but doesn't require it to be loaded to work properly. For this, you generally check, if the extension is loaded, rather than adding it as a hard dependency.

To implement a standardized way of checking, if an extension is loaded or not (without the need of extra work in an extension that is a soft-dependency in another one), extension registration can be used. It implements an isLoaded method, which returns a simple boolean, if the extension is loaded or not (the extension needs to be loaded with extension registration for this to work). Example:

if ( ExtensionRegistry :: getInstance () -> isLoaded ( "ExtensionB" ) ) ( )

Since MediaWiki 1.32 it"s also possible to check if an extension is loaded and satisfies a given composer version constraint:

if ( ExtensionRegistry :: getInstance () -> isLoaded ( "ExtensionB" , ">=1.2" ) ) ( // do things only, if extension B is loaded and has a version of 1.2 or greater. }

If you would like to check if a specific version of an extension is loaded in earlier versions of MediaWiki, information like that can be extracted with the getAllThings method, which returns credit information for all loaded extensions. Example:

$bVersion = ExtensionRegistry :: getInstance () -> getAllThings ()[ "ExtensionB" ][ "version" ] ?? null ; if ( $bVersion !== null && version_compare ( $bVersion , "2.1.0" , ">=" ) ) ( // do things only, if extension B is loaded and has a version number greater than or equal to 2.1.0 if (defined("ExtensionBVersion")) ( // You could also check for a version, if the constant holds the version // do things only, if extension B is loaded }

A more brittle way, that should be avoided is to check if a specific class of extension B exists or not, e.g. using this code:

if ( class_exists ( "ExtensionBHooks" ) ) ( // do things only, if extension B its classes exist }

This might break if the extension exists in the file system but is not loaded, e.g. if composer was used for autoloading. If the class was renamed or ceases to exist (e.g. because it is not package public) this will also break.

In general it is preferred to share code via composer components instead of extensions. If the classes of an extension only need to exist, but the extension does not need to be configured nor loaded, for what you want to do, that is a strong indicator that that code should be split off into a composer component you should depend on instead.

Configs (settings for your extension/style)

By default, extension.json assumes that your config settings start with a "wg" prefix.

If that"s not the case, you can override the prefix by using a special key:

("config": ("_prefix": "eg", "MyExtSetting": true))

That would use a prefix of "eg", and set the global variable $egMyExtSetting to true.

Starting with manifest version 2, the configuration section of extension registration provides a lot more features and allows you to describe your configuration options much more detailed. Instead of having a single key -> value store for your configuration options, you can also add the following information.

The general structure of the config changes slightly to the following, more object-oriented version:

( "config_prefix" : "eg" , "config" : ( "MyExtSetting" : ( "value" : true , "path" : false , "description" : "The description for the configuration", "descriptionmsg" : "myextension-config-myextsetting", "public" : true ) ), "manifest_version" : 2 )

Value

The value of the configuration moved to this place. This is the only required key for a configuration object.

Path

The boolean value of the path key identifies, if the value of the configuration option should be interpreted as a filesystem path, relative to the extension directory root. E.g., if the value of the configuration is myFile.png and the path is true, the actual value will be /path/to/the/wiki/extensions/MyExtension/myFile.png .

Description

The description key for a configuration option can hold a non-localized string, which can be used to explain the configuration option to other developers or the users (system administrators) of your extension. The value of the description key is usually not exposed to the frontend of the wiki, however, take a look to the outlook for more information how this feature could be used in the future!

There"s also the possibility to add a message key of MediaWiki"s internal localization system as a description (descriptionmsg), which, in the future, will be used to expose the description in the frontend of the MediaWiki installation.

public/private

This option is a boolean, which defaults to false, which means, that the configuration option and the value is marked as "private". This value is not used anywhere at the moment, take a look to the outlook to find out more about this option.

(PHP 5 >= 5.3.0)

The ability to refer to an external fully qualified name with an alias, or importing, is an important feature of namespaces. This is similar to the ability of unix-based filesystems to create symbolic links to a file or to a directory.

PHP namespaces support three kinds of aliasing or importing: aliasing a class name, aliasing an interface name, and aliasing a namespace name. Note that importing a function or constant is not supported.

In PHP, aliasing is accomplished with the use operator. Here is an example showing all 3 kinds of importing:

Example #1 importing/aliasing with the use operator

namespace foo ;
use My\Full\Classname as Another;

// this is the same as use My\Full\NSname as NSname
use My\Full\NSname;

// importing a global class
use ArrayObject ;

$obj = new namespace\ Another ; // instantiates object of class foo\Another
$obj = new Another ; NSname\subns\func(); $a = new ArrayObject(array(1)); // instantiates object of class ArrayObject
// without the "use ArrayObject" we would instantiate an object of class foo\ArrayObject
?>

Note that for namespaced names (fully qualified namespace names containing namespace separator, such as Foo\Bar as opposed to global names that do not, such as FooBar), the leading backslash is unnecessary and not recommended, as import names must be fully qualified, and are not processed relative to the current namespace.

PHP additionally supports a convenience shortcut to place multiple use statements on the same line

Example #2 importing/aliasing with the use operator, multiple use statements combined

$obj = new Another ; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func
?>

Importing is performed at compile-time, and so does not affect dynamic class, function or constant names.

Example #3 Importing and dynamic names

use My \ Full \ Classname as Another , My \ Full \ NSname ;

$obj = new Another ; // instantiates object of class My\Full\Classname
$a = "Another" ;
$obj = new $a ; ?>

In addition, importing only affects unqualified and qualified names. Fully qualified names are absolute, and unaffected by imports.

Example #4 Importing and fully qualified names

use My \ Full \ Classname as Another , My \ Full \ NSname ;

$obj = new Another ; // instantiates object of class My\Full\Classname
$obj = new \ Another ; // instantiates object of class Another
$obj = new Another \ thing ; // instantiates object of class My\Full\Classname\thing
$obj = new \ Another \ thing ; // instantiates object of class Another\thing
?>

Scoping rules for importing

The use keyword must be declared in the outermost scope of a file (the global scope) or inside namespace declarations. This is because the importing is done at compile time and not runtime, so it cannot be block scoped. The following example will show an illegal use of the use keyword:

Example #5 Illegal importing rule

namespace languages;

class Greenlandic
{
use Languages\Danish;

...
}
?>

Importing rules are per file basis, meaning included files will NOT inherit the parent file's importing rules.