Merge pull request #10165 from nupplaphil/bug/strip_pageinfo
[friendica.git/.git] / doc / autoloader.md
index 25ffd7f..e158868 100644 (file)
-Autoloader\r
-==========\r
-\r
-* [Home](help)\r
-\r
-There is some initial support to class autoloading in Friendica core.\r
-\r
-The autoloader code is in `include/autoloader.php`.\r
-It's derived from composer autoloader code.\r
-\r
-Namespaces and Classes are mapped to folders and files in `library/`,\r
-and the map must be updated by hand, because we don't use composer yet.\r
-The mapping is defined by files in `include/autoloader/` folder.\r
-\r
-Currently, only HTMLPurifier library is loaded using autoloader.\r
-\r
-\r
-## A quick introdution to class autoloading\r
-\r
-The autoloader it's a way for php to automagically include the file that define a class when the class is first used, without the need to use "require_once" every time.\r
-\r
-Once is setup you don't have to use it in any way. You need a class? you use the class.\r
-\r
-At his basic is a function passed to the "spl_autoload_register()" function, which receive as argument the class name the script want and is it job to include the correct php file where that class is defined.\r
-The best source for documentation is [php site](http://php.net/manual/en/language.oop5.autoload.php).\r
-\r
-One example, based on fictional friendica code.\r
-\r
-Let's say you have a php file in "include/" that define a very useful class:\r
-\r
-```\r
-    file: include/ItemsManager.php\r
-    <?php\r
-    namespace \Friendica;\r
-    \r
-    class ItemsManager {\r
-       public function getAll() { ... }\r
-       public function getByID($id) { ... }\r
-    }\r
-```\r
-\r
-The class "ItemsManager" has been declared in "Friendica" namespace.\r
-Namespaces are useful to keep things separated and avoid names clash (could be that a library you want to use defines a class named "ItemsManager", but as long as is in another namespace, you don't have any problem)\r
-\r
-If we were using composer, we had configured it with path where to find the classes of "Friendica" namespace, and then the composer script will generate the autoloader machinery for us.\r
-As we don't use composer, we need check that the autoloader knows the Friendica namespace.\r
-So in "include/autoloader/autoload_psr4.php" there should be something like\r
-\r
-```\r
-    $vendorDir = dirname(dirname(dirname(__FILE__)))."/library";\r
-    $baseDir = dirname($vendorDir);\r
-    return array(\r
-       "Friendica" => array($baseDir."/include");\r
-    );\r
-```\r
-\r
-\r
-That tells the autoloader code to look for files that defines classes in "Friendica" namespace under "include/" folder. (And btw, that's why the file has the same name as the class it defines.)\r
-\r
-*note*: The structure of files in "include/autoloader/" has been copied from the code generated by composer, to ease the work of enable autoloader for external libraries under "library/"\r
-\r
-Let's say now that you need to load some items in a view, maybe in a fictional "mod/network.php".\r
-Somewere at the start of the scripts, the autoloader was initialized. In Friendica is done at the top of "boot.php", with "require_once('include/autoloader.php');".\r
-\r
-The code will be something like:\r
-\r
-```\r
-    file: mod/network.php\r
-    <?php\r
-    \r
-    function network_content(App &$a) {\r
-       $itemsmanager = new \Friendica\ItemsManager();\r
-       $items = $itemsmanager->getAll();\r
-    \r
-       // pass $items to template\r
-       // return result\r
-    }\r
-```\r
-\r
-That's a quite simple example, but look: no "require()"!\r
-You need to use a class, you use the class and you don't need to do anything more.\r
-\r
-Going further: now we have a bunch of "*Manager" classes that cause some code duplication, let's define a BaseManager class, where to move all code in common between all managers:\r
-\r
-```\r
-    file: include/BaseManager.php\r
-    <?php\r
-    namespace \Friendica;\r
-    \r
-    class BaseManager {\r
-      public function thatFunctionEveryManagerUses() { ... }\r
-    }\r
-```\r
-\r
-and then let's change the ItemsManager class to use this code\r
-\r
-```\r
-    file: include/ItemsManager.php\r
-    <?php\r
-    namespace \Friendica;\r
-    \r
-    class ItemsManager extends BaseManager {\r
-       public function getAll() { ... }\r
-       public function getByID($id) { ... }\r
-    }\r
-```\r
-\r
-The autoloader don't mind what you need the class for. You need a class, you get the class.\r
-It works with the "BaseManager" example here, it works when we need to call static methods on a class:\r
-\r
-```\r
-    file: include/dfrn.php\r
-    <?php    \r
-    namespace \Friendica;\r
-    \r
-    class dfrn {\r
-      public static function  mail($item, $owner) { ... }\r
-    }\r
-```\r
-\r
-```\r
-    file: mod/mail.php\r
-    <?php\r
-    \r
-    mail_post($a){\r
-     ...\r
-     \Friendica\dfrn::mail($item, $owner);\r
-     ...\r
-    }\r
-```\r
-\r
-If your code is in same namespace as the class you need, you don't need to prepend it:\r
-\r
-```\r
-    file: include/delivery.php\r
-    <?php\r
-    \r
-    namespace \Friendica;\r
-    \r
-    // this is the same content of current include/delivery.php, \r
-    // but has been declared to be in "Friendica" namespace\r
-    \r
-    [...]\r
-    switch($contact['network']) {\r
-    \r
-        case NETWORK_DFRN:\r
-            if ($mail) {\r
-                $item['body'] = ...\r
-                $atom = dfrn::mail($item, $owner);\r
-            } elseif ($fsuggest) {\r
-                $atom = dfrn::fsuggest($item, $owner);\r
-                q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id']));\r
-            } elseif ($relocate)\r
-                $atom = dfrn::relocate($owner, $uid);\r
-    [...]\r
-```\r
-\r
-This is real "include/delivery.php" unchanged, but as the code is declared to be in "Friendica" namespace, you don't need to write it when you need to use the "dfrn" class.\r
-But if you want to use classes from another library, you need to use the full namespace, e.g.\r
-\r
-```\r
-    <?php\r
-    namespace \Frienidca;\r
-    \r
-    class Diaspora {\r
-      public function md2bbcode() {\r
-        $html = \Michelf\MarkdownExtra::defaultTransform($text); \r
-      }\r
-    }\r
-```\r
-\r
-if you use that class in many places of the code and you don't want to write the full path to the class everytime, you can use the "use" php keyword\r
-\r
-```\r
-    <?php\r
-    namespace \Frienidca;\r
-    \r
-    use \Michelf\MarkdownExtra;\r
-    \r
-    class Diaspora {\r
-      public function md2bbcode() {\r
-        $html = MarkdownExtra::defaultTransform($text); \r
-      }\r
-    }\r
-```\r
-\r
-Note that namespaces are like paths in filesystem, separated by "\", with the first "\" being the global scope.\r
-You can go more deep if you want to, like:\r
-\r
-```\r
-    <?php\r
-    namespace \Friendica\Network;\r
-    \r
-    class DFRN {\r
-    }\r
-```\r
-\r
-or\r
-\r
-```\r
-    <?php\r
-    namespace \Friendica\DBA;\r
-    \r
-    class MySQL {\r
-    }\r
-```\r
-\r
-So you can think of namespaces as folders in a unix filesystem, with global scope as the root ("\").\r
-\r
+Autoloader with Composer
+==========
+
+* [Home](help)
+  * [Developer Intro](help/Developers-Intro)
+
+Friendica uses [Composer](https://getcomposer.org) to manage dependencies libraries and the class autoloader both for libraries and namespaced Friendica classes.
+
+It's a command-line tool that downloads required libraries into the `vendor` folder and makes any namespaced class in `src` available through the whole application through `boot.php`.
+
+* [Using Composer](help/Composer)
+
+## A quick introduction to class autoloading
+
+The autoloader dynamically includes the file defining a class when it is first referenced, either by instantiating an object or simply making sure that it is available, without the need to explicitly use "require_once".
+
+Once it is set up you don't have to directly use it, you can directly use any class that is covered by the autoloader (currently `vendor` and `src`)
+
+Under the hood, Composer registers a callback with [`spl_autoload_register()`](http://php.net/manual/en/function.spl-autoload-register.php) that receives a class name as an argument and includes the corresponding class definition file.
+For more info about PHP autoloading, please refer to the [official PHP documentation](http://php.net/manual/en/language.oop5.autoload.php).
+
+### Example
+
+Let's say you have a PHP file in `src/` that define a very useful class:
+
+```php
+// src/ItemsManager.php
+<?php
+namespace Friendica;
+
+class ItemsManager {
+       public function getAll() { ... }
+       public function getByID($id) { ... }
+}
+```
+
+The class `ItemsManager` has been declared in the `Friendica` namespace.
+Namespaces are useful to keep classes separated and avoid names conflicts (could be that a library you want to use also defines a class named `ItemsManager`, but as long as it is in another namespace, you don't have any problem)
+
+Let's say now that you need to load some items in a view, maybe in a fictional `mod/network.php`.
+In order for the Composer autoloader to work, it must first be included.
+In Friendica this is already done at the top of `boot.php`, with `require_once('vendor/autoload.php');`.
+
+The code will be something like:
+
+```php
+// mod/network.php
+<?php
+
+use Friendica\App;
+
+function network_content(App $a) {
+       $itemsmanager = new \Friendica\ItemsManager();
+       $items = $itemsmanager->getAll();
+
+       // pass $items to template
+       // return result
+}
+```
+
+That's a quite simple example, but look: no `require()`!
+If you need to use a class, you can simply use it and you don't need to do anything else.
+
+Going further: now we have a bunch of `*Manager` classes that cause some code duplication.
+Let's define a `BaseManager` class, where we move all common code between all managers:
+
+```php
+// src/BaseManager.php
+<?php
+namespace Friendica;
+
+class BaseManager {
+       public function thatFunctionEveryManagerUses() { ... }
+}
+```
+
+and then let's change the ItemsManager class to use this code
+
+```php
+// src/ItemsManager.php
+<?php
+namespace Friendica;
+
+class ItemsManager extends BaseManager {
+       public function getAll() { ... }
+       public function getByID($id) { ... }
+}
+```
+
+Even though we didn't explicitly include the `src/BaseManager.php` file, the autoloader will when this class is first defined, because it is referenced as a parent class.
+It works with the "BaseManager" example here and it works when we need to call static methods:
+
+```php
+// src/Dfrn.php
+<?php
+namespace Friendica;
+
+class Dfrn {
+       public static function  mail($item, $owner) { ... }
+}
+```
+
+```php
+// mod/mail.php
+<?php
+
+mail_post($a){
+       ...
+       Friendica\Protocol\DFRN::mail($item, $owner);
+       ...
+}
+```
+
+If your code is in same namespace as the class you need, you don't need to prepend it:
+
+```php
+// include/delivery.php
+<?php
+
+namespace Friendica;
+
+use Friendica\Protocol\DFRN;
+
+// this is the same content of current include/delivery.php,
+// but has been declared to be in "Friendica" namespace
+
+[...]
+switch($contact['network']) {
+       case NETWORK_DFRN:
+               if ($mail) {
+                       $item['body'] = ...
+                       $atom = DFRN::mail($item, $owner);
+               } elseif ($fsuggest) {
+                       $atom = DFRN::fsuggest($item, $owner);
+                       q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id']));
+               } elseif ($relocate)
+                       $atom = DFRN::relocate($owner, $uid);
+[...]
+```
+
+This is the current code of `include/delivery.php`, and since the code is declared to be in the "Friendica" namespace, you don't need to write it when you need to use the "Dfrn" class.
+But if you want to use classes from another library, you need to use the full namespace, e.g.
+
+```php
+// src/Diaspora.php
+<?php
+
+namespace Friendica;
+
+class Diaspora {
+       public function md2bbcode() {
+               $html = \Michelf\MarkdownExtra::defaultTransform($text);
+       }
+}
+```
+
+if you use that class in many places of the code and you don't want to write the full path to the class every time, you can use the "use" PHP keyword
+
+```php
+// src/Diaspora.php
+<?php
+namespace Friendica;
+
+use \Michelf\MarkdownExtra;
+
+class Diaspora {
+       public function md2bbcode() {
+               $html = MarkdownExtra::defaultTransform($text);
+       }
+}
+```
+
+Note that namespaces are like paths in filesystem, separated by "\", with the first "\" being the global scope.
+You can go deeper if you want to, like:
+
+```
+// src/Network/Dfrn.php
+<?php
+namespace Friendica\Network;
+
+class Dfrn {
+}
+```
+
+Please note that the location of the file defining the class must be placed in the appropriate sub-folders of `src` if the namespace isn't plain `Friendica`.
+
+or
+
+```
+// src/Dba/Mysql
+<?php
+namespace Friendica\Dba;
+
+class Mysql {
+}
+```
+
+So you can think of namespaces as folders in a Unix file system, with global scope as the root ("\").
+
+## Related
+
+* [Using Composer](help/Composer)
+* [How To Move Classes to `src`](help/Developer-How-To-Move-Classes-to-src)