One Hat Cyber Team
Your IP:
216.73.216.102
Server IP:
198.54.114.155
Server:
Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
Server Software:
LiteSpeed
PHP Version:
5.6.40
Create File
|
Create Folder
Execute
Dir :
~
/
home
/
fluxyjvi
/
public_html
/
assets
/
images
/
Edit File:
docs.tar
en/index.rst 0000644 00000000214 15107322020 0006774 0 ustar 00 Common Documentation ==================== Welcome to the Doctrine Common Library documentation. .. toctree:: :depth: 2 :glob: * webhook.md 0000644 00000004006 15107406537 0006534 0 ustar 00  # Process realtime status updates with a webhook A webhook is a URL Mollie will call when an object’s status changes, for example when a payment changes from `open` to `paid`. More specifics can be found in [the webhook guide](https://docs.mollie.com/guides/webhooks). To implement the webhook in your Laravel application you need to provide a `webhookUrl` parameter when creating a payment (or subscription): ```php $payment = Mollie::api()->payments()->create([ 'amount' => [ 'currency' => 'EUR', 'value' => '10.00', // You must send the correct number of decimals, thus we enforce the use of strings ], 'description' => 'My first API payment', 'redirectUrl' => 'https://webshop.example.org/order/12345/', 'webhookUrl' => route('webhooks.mollie'), ]); ``` And create a matching route and controller for the webhook in your application: ```php // routes/web.php Route::name('webhooks.mollie')->post('webhooks/mollie', 'MollieWebhookController@handle'); ``` ```php // App/Http/Controllers/MollieWebhookController.php class MollieWebhookController extends Controller { public function handle(Request $request) { if (! $request->has('id')) { return; } $payment = Mollie::api()->payments()->get($request->id); if ($payment->isPaid()) { // do your thing... } } } ``` Finally, it is _strongly advised_ to disable the `VerifyCsrfToken` middleware, which is included in the `web` middleware group by default. (Out of the box, Laravel applies the `web` middleware group to all routes in `routes/web.php`.) You can exclude URIs from the CSRF protection in the `app/Http/Middleware/VerifyCsrfToken.php` file: ```php /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ 'webhooks/mollie' ]; ``` If this solution does not work, open an [issue](https://github.com/mollie/laravel-mollie/issues) so we can assist you. mollie_connect.md 0000644 00000003730 15107406537 0010073 0 ustar 00  # Using Mollie Connect with Laravel Socialite (Oauth) [Mollie Connect](https://docs.mollie.com/oauth/overview) allows you to create apps for Mollie merchants via OAuth. ## Why should I use OAuth? Mollie Connect is built on the [OAuth standard](https://en.wikipedia.org/wiki/OAuth). The OAuth connection enables you to access other merchants’ accounts with their consent, without having to exchange API keys. Whether you are just looking to improve your customers’ experiences, to automate essential business processes, or to whitelabel our platform completely, it is all possible with OAuth. Our OAuth platform allows you to: - Create payments and refunds on behalf of merchants - Manage merchants’ website profiles - View a merchants’ transaction and settlement data - Show the next settlement and balance at Mollie in your app - Integrate merchants’ invoices from Mollie in your app - Charge merchants for payments initiated through your app ([application fees](https://docs.mollie.com/oauth/application-fees)) ## Installation Make sure the Laravel Socialite package is installed. Then update `config/services.php` by adding this to the array: ```php 'mollie' => [ 'client_id' => env('MOLLIE_CLIENT_ID', 'app_xxx'), 'client_secret' => env('MOLLIE_CLIENT_SECRET'), 'redirect' => env('MOLLIE_REDIRECT_URI'), ], ``` Then add the corresponding credentials (`MOLLIE_CLIENT_ID`, `MOLLIE_CLIENT_SECRET`, `MOLLIE_REDIRECT_URI`) to your `.env` file. ## Example usage ```php Route::get('login', function () { return Socialite::with('mollie') ->scopes(['profiles.read']) // Additional permission: profiles.read ->redirect(); }); Route::get('login_callback', function () { $user = Socialite::with('mollie')->user(); Mollie::api()->setAccessToken($user->token); return Mollie::api()->profiles()->page(); // Retrieve payment profiles available on the obtained Mollie account }); ``` recurring_and_direct_charge.md 0000644 00000005011 15107406537 0012560 0 ustar 00  # Mollie Recurring Here you can see an example of how easy it is to use [Mollie recurring](https://docs.mollie.com/payments/recurring) payments. ## Create a customer First of all you need to [create a new customer](https://docs.mollie.com/payments/recurring#payments-recurring-first-payment) (step 1), this is pretty straight forward ```php $customer = Mollie::api()->customers()->create([ 'name' => 'John Doe', 'email' => 'john@doe.com', ]); ``` ## Initial Payment After creating the user, you can [start a payment](https://docs.mollie.com/payments/recurring#payments-recurring-first-payment) (step 3), it's important to set `sequenceType` to `first`, this will generate a mandate on Mollie's end that can be used to do direct charges. Without setting the `method` the payment screen of Mollie will display your methods that support recurring payments. ```php $payment = Mollie::api()->payments()->create([ 'amount' => [ 'currency' => 'EUR', 'value' => '25.00', // You must send the correct number of decimals, thus we enforce the use of strings ], 'customerId' => $customer->id, 'sequenceType' => 'first', 'description' => 'My Initial Payment', 'redirectUrl' => 'https://domain.com/return', 'webhookUrl' => route('webhooks.mollie'), ]); // Redirect the user to Mollie's payment screen. return redirect($payment->getCheckoutUrl(), 303); ``` ## Direct Charge After doing the initial payment, you may [charge the users card/account directly](https://docs.mollie.com/payments/recurring#payments-recurring-charging-on-demand). Make sure there's a valid mandate connected to the customer. In case there are multiple mandates at least one should have `status` set to `valid`. Checking mandates is easy: ```php $mandates = Mollie::api()->mandates()->listFor($customer); ``` If any of the mandates is valid, charging the user is a piece of cake. Make sure `sequenceType` is set to `recurring`. ```php $payment = Mollie::api()->payments()->create([ 'amount' => [ 'currency' => 'EUR', 'value' => '25.00', // You must send the correct number of decimals, thus we enforce the use of strings ], 'customerId' => $customer->id, 'sequenceType' => 'recurring', 'description' => 'Direct Charge', 'webhookUrl' => route('webhooks.mollie'), ]); ``` Like any other payment, Mollie will call your webhook to register the payment status so don't forget to save the transaction id to your database. migration_instructions_v1_to_v2.md 0000644 00000003526 15107406537 0013440 0 ustar 00  # Migrating from Laravel-Mollie v1.x to v2 ### Step 1: Update composer dependencies Update `composer.json` to match this: ``` "require": { "mollie/laravel-mollie": "^2.0" } ``` Then run `composer update mollie/laravel-mollie`. ### Step 2: Reconfiguring the Mollie API key Setting the api key has been simplified. It now only requires you to set a single variable in your `.env` file. This is how you do it: - If you have a `mollie.php` file in your `config/` directory, remove it. - Add `MOLLIE_KEY=your_api_key_here` to your `.env` file. Use the test key for test mode, or the live key for live mode. - You can now remove the `MOLLIE_TEST_MODE`, `MOLLIE_KEY_TEST` and `MOLLIE_KEY_LIVE` variables from the .env file. ### Step 3: Changed package methods A few months ago Mollie launched the v2 API, along with an upgraded php core client. The v2 release of this Laravel-Mollie package leverages the new features of the v2 API. This also means some breaking changes have been introduced in this package. Some methods were removed: - `Mollie::api()->permissions()` - `Mollie::api()->organizations()` - `Mollie::api()->issuers()` These methods were renamed: - `Mollie::api()->customerMandates()` into `Mollie::api()->mandates()` - `Mollie::api()->customersPayments()` into `Mollie::api()->customerPayments()` - `Mollie::api()->customerSubscriptions()` into `Mollie::api()->subscriptions()` - `Mollie::api()->paymentsRefunds()` into `Mollie::api()->refunds()` Also, this method was added: - `Mollie::api()->invoices()` ### Step 4: Other changes More breaking changes were introduced with the new Mollie API. Read about it here in the [official migration docs](https://docs.mollie.com/migrating-v1-to-v2). ## Stuck? Feel free to open an [issue](https://github.com/mollie/laravel-mollie/issues). roadmap.md 0000644 00000004616 15107406537 0006530 0 ustar 00  # Laravel-Mollie Roadmap This roadmap lists all current and upcoming activity for the Laravel-Mollie package. Please submit an [issue](https://github.com/mollie/laravel-mollie/issues) if you have a suggestion for Laravel-Mollie specific functionality. ## Planned for next major release ### Provide default webhook The Laravel-Mollie package makes it easy to set up a new Mollie payment in your Laravel application. But right now, you'll need to implement the webhook yourself. We plan on providing a default webhook, which will trigger an Event when a payment status has been updated. This way, you'll only need to listen for the PaymentUpdatedEvent. Another solution may be to provide a default overridable controller, like Cashier has. Or to implement both events and the controller. ### Switch to MIT license Currently, the Laravel Mollie client has a *BSD 2-Clause "Simplified" License*. We're discussing switching to a *MIT* license, which is most common in Laravel packages. ## Other Laravel packages by Mollie Besides the Laravel-Mollie package, we're looking for other options to support you integrating Mollie in your Laravel applications. ### Explore Laravel Cashier support ("Laravel/Cashier-Mollie") Laravel Cashier is a very popular package for easily adding recurring payments to your Laravel application. We are exploring whether it's possible for Laravel Cashier to support Mollie. You can join the discussion [here](https://github.com/mollie/laravel-mollie/issues/41). ### Explore Laravel Spark support [Laravel Spark](https://spark.laravel.com/) is a commercial SAAS starter kit. By adding Cashier-Mollie support, new SAAS projects can be built rapidly on top of Mollie's subscription services. Laravel Spark leverages Laravel Cashier for subscription billing. When/If Cashier-Mollie is implemented, support for Laravel Spark would be a logical next topic for exploration. ### Explore Laravel Nova plugin options [Laravel Nova](https://nova.laravel.com/) is a powerful Laravel and Vue based CMS (commercial license). Launch of this new CMS is scheduled August 2018. Adoption rate is expected to be high; [Sander](https://github.com/sandervanhooft) expects Nova is going to blow a hole in other Laravel and PHP CMSes' market shares. A Laravel Nova plugin for Mollie could for example list and manage payments, and include a few dashboard cards. en/custom.rst 0000644 00000023616 15107410637 0007226 0 ustar 00 Custom Annotation Classes ========================= If you want to define your own annotations, you just have to group them in a namespace and register this namespace in the ``AnnotationRegistry``. Annotation classes have to contain a class-level docblock with the text ``@Annotation``: .. code-block:: php namespace MyCompany\Annotations; /** @Annotation */ class Bar { // some code } Inject annotation values ------------------------ The annotation parser checks if the annotation constructor has arguments, if so then it will pass the value array, otherwise it will try to inject values into public properties directly: .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * * Some Annotation using a constructor */ class Bar { private $foo; public function __construct(array $values) { $this->foo = $values['foo']; } } /** * @Annotation * * Some Annotation without a constructor */ class Foo { public $bar; } Optional: Constructors with Named Parameters -------------------------------------------- Starting with Annotations v1.11 a new annotation instantiation strategy is available that aims at compatibility of Annotation classes with the PHP 8 attribute feature. You need to declare a constructor with regular parameter names that match the named arguments in the annotation syntax. To enable this feature, you can tag your annotation class with ``@NamedArgumentConstructor`` (available from v1.12) or implement the ``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation`` interface (available from v1.11 and deprecated as of v1.12). When using the ``@NamedArgumentConstructor`` tag, the first argument of the constructor is considered as the default one. Usage with the ``@NamedArgumentConstructor`` tag .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * @NamedArgumentConstructor */ class Bar implements NamedArgumentConstructorAnnotation { private $foo; public function __construct(string $foo) { $this->foo = $foo; } } /** Usable with @Bar(foo="baz") */ /** Usable with @Bar("baz") */ In combination with PHP 8's constructor property promotion feature you can simplify this to: .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * @NamedArgumentConstructor */ class Bar implements NamedArgumentConstructorAnnotation { public function __construct(private string $foo) {} } Usage with the ``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation`` interface (v1.11, deprecated as of v1.12): .. code-block:: php namespace MyCompany\Annotations; use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** @Annotation */ class Bar implements NamedArgumentConstructorAnnotation { private $foo; public function __construct(private string $foo) {} } /** Usable with @Bar(foo="baz") */ Annotation Target ----------------- ``@Target`` indicates the kinds of class elements to which an annotation type is applicable. Then you could define one or more targets: - ``CLASS`` Allowed in class docblocks - ``PROPERTY`` Allowed in property docblocks - ``METHOD`` Allowed in the method docblocks - ``FUNCTION`` Allowed in function dockblocks - ``ALL`` Allowed in class, property, method and function docblocks - ``ANNOTATION`` Allowed inside other annotations If the annotations is not allowed in the current context, an ``AnnotationException`` is thrown. .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * @Target({"METHOD","PROPERTY"}) */ class Bar { // some code } /** * @Annotation * @Target("CLASS") */ class Foo { // some code } Attribute types --------------- The annotation parser checks the given parameters using the phpdoc annotation ``@var``, The data type could be validated using the ``@var`` annotation on the annotation properties or using the ``@Attributes`` and ``@Attribute`` annotations. If the data type does not match you get an ``AnnotationException`` .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * @Target({"METHOD","PROPERTY"}) */ class Bar { /** @var mixed */ public $mixed; /** @var boolean */ public $boolean; /** @var bool */ public $bool; /** @var float */ public $float; /** @var string */ public $string; /** @var integer */ public $integer; /** @var array */ public $array; /** @var SomeAnnotationClass */ public $annotation; /** @var array<integer> */ public $arrayOfIntegers; /** @var array<SomeAnnotationClass> */ public $arrayOfAnnotations; } /** * @Annotation * @Target({"METHOD","PROPERTY"}) * @Attributes({ * @Attribute("stringProperty", type = "string"), * @Attribute("annotProperty", type = "SomeAnnotationClass"), * }) */ class Foo { public function __construct(array $values) { $this->stringProperty = $values['stringProperty']; $this->annotProperty = $values['annotProperty']; } // some code } Annotation Required ------------------- ``@Required`` indicates that the field must be specified when the annotation is used. If it is not used you get an ``AnnotationException`` stating that this value can not be null. Declaring a required field: .. code-block:: php /** * @Annotation * @Target("ALL") */ class Foo { /** @Required */ public $requiredField; } Usage: .. code-block:: php /** @Foo(requiredField="value") */ public $direction; // Valid /** @Foo */ public $direction; // Required field missing, throws an AnnotationException Enumerated values ----------------- - An annotation property marked with ``@Enum`` is a field that accepts a fixed set of scalar values. - You should use ``@Enum`` fields any time you need to represent fixed values. - The annotation parser checks the given value and throws an ``AnnotationException`` if the value does not match. Declaring an enumerated property: .. code-block:: php /** * @Annotation * @Target("ALL") */ class Direction { /** * @Enum({"NORTH", "SOUTH", "EAST", "WEST"}) */ public $value; } Annotation usage: .. code-block:: php /** @Direction("NORTH") */ public $direction; // Valid value /** @Direction("NORTHEAST") */ public $direction; // Invalid value, throws an AnnotationException Constants --------- The use of constants and class constants is available on the annotations parser. The following usages are allowed: .. code-block:: php namespace MyCompany\Entity; use MyCompany\Annotations\Foo; use MyCompany\Annotations\Bar; use MyCompany\Entity\SomeClass; /** * @Foo(PHP_EOL) * @Bar(Bar::FOO) * @Foo({SomeClass::FOO, SomeClass::BAR}) * @Bar({SomeClass::FOO_KEY = SomeClass::BAR_VALUE}) */ class User { } Be careful with constants and the cache ! .. note:: The cached reader will not re-evaluate each time an annotation is loaded from cache. When a constant is changed the cache must be cleaned. Usage ----- Using the library API is simple. Using the annotations described in the previous section, you can now annotate other classes with your annotations: .. code-block:: php namespace MyCompany\Entity; use MyCompany\Annotations\Foo; use MyCompany\Annotations\Bar; /** * @Foo(bar="foo") * @Bar(foo="bar") */ class User { } Now we can write a script to get the annotations above: .. code-block:: php $reflClass = new ReflectionClass('MyCompany\Entity\User'); $classAnnotations = $reader->getClassAnnotations($reflClass); foreach ($classAnnotations AS $annot) { if ($annot instanceof \MyCompany\Annotations\Foo) { echo $annot->bar; // prints "foo"; } else if ($annot instanceof \MyCompany\Annotations\Bar) { echo $annot->foo; // prints "bar"; } } You have a complete API for retrieving annotation class instances from a class, property or method docblock: Reader API ~~~~~~~~~~ Access all annotations of a class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getClassAnnotations(\ReflectionClass $class); Access one annotation of a class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getClassAnnotation(\ReflectionClass $class, $annotationName); Access all annotations of a method ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getMethodAnnotations(\ReflectionMethod $method); Access one annotation of a method ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getMethodAnnotation(\ReflectionMethod $method, $annotationName); Access all annotations of a property ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getPropertyAnnotations(\ReflectionProperty $property); Access one annotation of a property ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName); Access all annotations of a function ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getFunctionAnnotations(\ReflectionFunction $property); Access one annotation of a function ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getFunctionAnnotation(\ReflectionFunction $property, $annotationName); en/annotations.rst 0000644 00000023130 15107410637 0010240 0 ustar 00 Handling Annotations ==================== There are several different approaches to handling annotations in PHP. Doctrine Annotations maps docblock annotations to PHP classes. Because not all docblock annotations are used for metadata purposes a filter is applied to ignore or skip classes that are not Doctrine annotations. Take a look at the following code snippet: .. code-block:: php namespace MyProject\Entities; use Doctrine\ORM\Mapping AS ORM; use Symfony\Component\Validator\Constraints AS Assert; /** * @author Benjamin Eberlei * @ORM\Entity * @MyProject\Annotations\Foobarable */ class User { /** * @ORM\Id @ORM\Column @ORM\GeneratedValue * @dummy * @var int */ private $id; /** * @ORM\Column(type="string") * @Assert\NotEmpty * @Assert\Email * @var string */ private $email; } In this snippet you can see a variety of different docblock annotations: - Documentation annotations such as ``@var`` and ``@author``. These annotations are ignored and never considered for throwing an exception due to wrongly used annotations. - Annotations imported through use statements. The statement ``use Doctrine\ORM\Mapping AS ORM`` makes all classes under that namespace available as ``@ORM\ClassName``. Same goes for the import of ``@Assert``. - The ``@dummy`` annotation. It is not a documentation annotation and not ignored. For Doctrine Annotations it is not entirely clear how to handle this annotation. Depending on the configuration an exception (unknown annotation) will be thrown when parsing this annotation. - The fully qualified annotation ``@MyProject\Annotations\Foobarable``. This is transformed directly into the given class name. How are these annotations loaded? From looking at the code you could guess that the ORM Mapping, Assert Validation and the fully qualified annotation can just be loaded using the defined PHP autoloaders. This is not the case however: For error handling reasons every check for class existence inside the ``AnnotationReader`` sets the second parameter $autoload of ``class_exists($name, $autoload)`` to false. To work flawlessly the ``AnnotationReader`` requires silent autoloaders which many autoloaders are not. Silent autoloading is NOT part of the `PSR-0 specification <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md>`_ for autoloading. This is why Doctrine Annotations uses its own autoloading mechanism through a global registry. If you are wondering about the annotation registry being global, there is no other way to solve the architectural problems of autoloading annotation classes in a straightforward fashion. Additionally if you think about PHP autoloading then you recognize it is a global as well. To anticipate the configuration section, making the above PHP class work with Doctrine Annotations requires this setup: .. code-block:: php use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\AnnotationRegistry; AnnotationRegistry::registerFile("/path/to/doctrine/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php"); AnnotationRegistry::registerAutoloadNamespace("Symfony\Component\Validator\Constraint", "/path/to/symfony/src"); AnnotationRegistry::registerAutoloadNamespace("MyProject\Annotations", "/path/to/myproject/src"); $reader = new AnnotationReader(); AnnotationReader::addGlobalIgnoredName('dummy'); The second block with the annotation registry calls registers all the three different annotation namespaces that are used. Doctrine Annotations saves all its annotations in a single file, that is why ``AnnotationRegistry#registerFile`` is used in contrast to ``AnnotationRegistry#registerAutoloadNamespace`` which creates a PSR-0 compatible loading mechanism for class to file names. In the third block, we create the actual ``AnnotationReader`` instance. Note that we also add ``dummy`` to the global list of ignored annotations for which we do not throw exceptions. Setting this is necessary in our example case, otherwise ``@dummy`` would trigger an exception to be thrown during the parsing of the docblock of ``MyProject\Entities\User#id``. Setup and Configuration ----------------------- To use the annotations library is simple, you just need to create a new ``AnnotationReader`` instance: .. code-block:: php $reader = new \Doctrine\Common\Annotations\AnnotationReader(); This creates a simple annotation reader with no caching other than in memory (in php arrays). Since parsing docblocks can be expensive you should cache this process by using a caching reader. To cache annotations, you can create a ``Doctrine\Common\Annotations\PsrCachedReader``. This reader decorates the original reader and stores all annotations in a PSR-6 cache: .. code-block:: php use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\PsrCachedReader; $cache = ... // instantiate a PSR-6 Cache pool $reader = new PsrCachedReader( new AnnotationReader(), $cache, $debug = true ); The ``debug`` flag is used here as well to invalidate the cache files when the PHP class with annotations changed and should be used during development. .. warning :: The ``AnnotationReader`` works and caches under the assumption that all annotations of a doc-block are processed at once. That means that annotation classes that do not exist and aren't loaded and cannot be autoloaded (using the AnnotationRegistry) would never be visible and not accessible if a cache is used unless the cache is cleared and the annotations requested again, this time with all annotations defined. By default the annotation reader returns a list of annotations with numeric indexes. If you want your annotations to be indexed by their class name you can wrap the reader in an ``IndexedReader``: .. code-block:: php use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\IndexedReader; $reader = new IndexedReader(new AnnotationReader()); .. warning:: You should never wrap the indexed reader inside a cached reader, only the other way around. This way you can re-use the cache with indexed or numeric keys, otherwise your code may experience failures due to caching in a numerical or indexed format. Registering Annotations ~~~~~~~~~~~~~~~~~~~~~~~ As explained in the introduction, Doctrine Annotations uses its own autoloading mechanism to determine if a given annotation has a corresponding PHP class that can be autoloaded. For annotation autoloading you have to configure the ``Doctrine\Common\Annotations\AnnotationRegistry``. There are three different mechanisms to configure annotation autoloading: - Calling ``AnnotationRegistry#registerFile($file)`` to register a file that contains one or more annotation classes. - Calling ``AnnotationRegistry#registerNamespace($namespace, $dirs = null)`` to register that the given namespace contains annotations and that their base directory is located at the given $dirs or in the include path if ``NULL`` is passed. The given directories should *NOT* be the directory where classes of the namespace are in, but the base directory of the root namespace. The AnnotationRegistry uses a namespace to directory separator approach to resolve the correct path. - Calling ``AnnotationRegistry#registerLoader($callable)`` to register an autoloader callback. The callback accepts the class as first and only parameter and has to return ``true`` if the corresponding file was found and included. .. note:: Loaders have to fail silently, if a class is not found even if it matches for example the namespace prefix of that loader. Never is a loader to throw a warning or exception if the loading failed otherwise parsing doc block annotations will become a huge pain. A sample loader callback could look like: .. code-block:: php use Doctrine\Common\Annotations\AnnotationRegistry; use Symfony\Component\ClassLoader\UniversalClassLoader; AnnotationRegistry::registerLoader(function($class) { $file = str_replace("\\", DIRECTORY_SEPARATOR, $class) . ".php"; if (file_exists("/my/base/path/" . $file)) { // file_exists() makes sure that the loader fails silently require "/my/base/path/" . $file; } }); $loader = new UniversalClassLoader(); AnnotationRegistry::registerLoader(array($loader, "loadClass")); Ignoring missing exceptions ~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default an exception is thrown from the ``AnnotationReader`` if an annotation was found that: - is not part of the list of ignored "documentation annotations"; - was not imported through a use statement; - is not a fully qualified class that exists. You can disable this behavior for specific names if your docblocks do not follow strict requirements: .. code-block:: php $reader = new \Doctrine\Common\Annotations\AnnotationReader(); AnnotationReader::addGlobalIgnoredName('foo'); PHP Imports ~~~~~~~~~~~ By default the annotation reader parses the use-statement of a php file to gain access to the import rules and register them for the annotation processing. Only if you are using PHP Imports can you validate the correct usage of annotations and throw exceptions if you misspelled an annotation. This mechanism is enabled by default. To ease the upgrade path, we still allow you to disable this mechanism. Note however that we will remove this in future versions: .. code-block:: php $reader = new \Doctrine\Common\Annotations\AnnotationReader(); $reader->setEnabledPhpImports(false); en/sidebar.rst 0000644 00000000101 15107410640 0007277 0 ustar 00 .. toctree:: :depth: 3 index annotations custom en/reference/class-loading.rst 0000644 00000022444 15107463116 0012370 0 ustar 00 Class Loading ============= Class loading is an essential part of any PHP application that makes heavy use of classes and interfaces. Unfortunately, a lot of people and projects spend a lot of time and effort on custom and specialized class loading strategies. It can quickly become a pain to understand what is going on when using multiple libraries and/or frameworks, each with its own way to do class loading. Class loading should be simple and it is an ideal candidate for convention over configuration. Overview -------- The Doctrine Common ClassLoader implements a simple and efficient approach to class loading that is easy to understand and use. The implementation is based on the widely used and accepted convention of mapping namespace and class names to a directory structure. This approach is used for example by Symfony2, the Zend Framework and of course, Doctrine. For example, the following class: .. code-block:: php <?php namespace MyProject\Shipping; class ShippingStrategy { ... } resides in the following directory structure: :: src/ /MyProject /Shipping ShippingStrategy.php Note that the name of "src" or the structure above or beside this directory is completely arbitrary. "src" could be named "classes" or "lib" or whatever. The only convention to adhere to is to map namespaces to directories and classes to files named after the class name. Usage ----- To use a Doctrine Common ClassLoader, you first need to load the class file containing the ClassLoader. This is the only class file that actually needs to be loaded explicitly via ``require``. All other classes will be loaded on demand by the configured class loaders. .. code-block:: php <?php use Doctrine\Common\ClassLoader; require '/path/to/Doctrine/Common/ClassLoader.php'; $classLoader = new ClassLoader('MyProject', '/path/to/src'); A ``ClassLoader`` takes two constructor parameters, both optional. In the normal case both arguments are supplied. The first argument specifies the namespace prefix this class loader should be responsible for and the second parameter is the path to the root directory where the classes can be found according to the convention mentioned previously. The class loader in the example above would thus be responsible for all classes under the 'MyProject' namespace and it would look for the class files starting at the directory '/path/to/src'. Also note that the prefix supplied in the first argument need not be a root namespace but can be an arbitrarily nested namespace as well. This allows you to even have the sources of subnamespaces split across different directories. For example, all projects under the Doctrine umbrella reside in the Doctrine namespace, yet the sources for each project usually do not reside under a common root directory. The following is an example of configuring three class loaders, one for each used Doctrine project: .. code-block:: php <?php use Doctrine\Common\ClassLoader; require '/path/to/Doctrine/Common/ClassLoader.php'; $commonLoader = new ClassLoader('Doctrine\Common', '/path/to/common/lib'); $dbalLoader = new ClassLoader('Doctrine\DBAL', '/path/to/dbal/lib'); $ormLoader = new ClassLoader('Doctrine\ORM', '/path/to/orm/lib'); $commonLoader->register(); $dbalLoader->register(); $ormLoader->register(); Do not be afraid of using multiple class loaders. Due to the efficient class loading design you will not incur much overhead from using many class loaders. Take a look at the implementation of ``ClassLoader#loadClass`` to see how simple and efficient the class loading is. The iteration over the installed class loaders happens in C (with the exception of using ``ClassLoader::classExists``). A ClassLoader can be used in the following other variations, however, these are rarely used/needed: - If only the second argument is not supplied, the class loader will be responsible for the namespace prefix given in the first argument and it will rely on the PHP include_path. - If only the first argument is not supplied, the class loader will be responsible for *all* classes and it will try to look up *all* classes starting at the directory given as the second argument. - If both arguments are not supplied, the class loader will be responsible for *all* classes and it will rely on the PHP include_path. File Extension -------------- By default, a ClassLoader uses the ``.php`` file extension for all class files. You can change this behavior, for example to use a ClassLoader to load classes from a library that uses the ".class.php" convention (but it must nevertheless adhere to the directory structure convention!): .. code-block:: php <?php $customLoader = new ClassLoader('CustomLib', '/path/to/custom/lib'); $customLoader->setFileExtension('.class.php'); $customLoader->register(); Namespace Separator ------------------- By default, a ClassLoader uses the ``\`` namespace separator. You can change this behavior, for example to use a ClassLoader to load legacy Zend Framework classes that still use the underscore "_" separator: .. code-block:: php <?php $zend1Loader = new ClassLoader('Zend', '/path/to/zend/lib'); $zend1Loader->setNamespaceSeparator('_'); $zend1Loader->register(); Failing Silently and class_exists ---------------------------------- A lot of class/autoloaders these days try to fail silently when a class file is not found. For the most part this is necessary in order to support using ``class_exists('ClassName', true)`` which is supposed to return a boolean value but triggers autoloading. This is a bad thing as it basically forces class loaders to fail silently, which in turn requires costly file_exists or fopen calls for each class being loaded, even though in at least 99% of the cases this is not necessary (compare the number of class_exists(..., true) invocations to the total number of classes being loaded in a request). The Doctrine Common ClassLoader does not fail silently, by design. It therefore does not need any costly checks for file existence. A ClassLoader is always responsible for all classes with a certain namespace prefix and if a class is requested to be loaded and can not be found this is considered to be a fatal error. This also means that using class_exists(..., true) to check for class existence when using a Doctrine Common ClassLoader is not possible but this is not a bad thing. What class\_exists(..., true) actually means is two things: 1) Check whether the class is already defined/exists (i.e. class_exists(..., false)) and if not 2) check whether a class file can be loaded for that class. In the Doctrine Common ClassLoader the two responsibilities of loading a class and checking for its existence are separated, which can be observed by the existence of the two methods ``loadClass`` and ``canLoadClass``. Thereby ``loadClass`` does not invoke ``canLoadClass`` internally, by design. However, you are free to use it yourself to check whether a class can be loaded and the following code snippet is thus equivalent to class\_exists(..., true): .. code-block:: php <?php // Equivalent to if (('Foo', true)) if there is only 1 class loader to check if (class_exists('Foo', false) || $classLoader->canLoadClass('Foo')) { // ... } The only problem with this is that it is inconvenient as you need to have a reference to the class loaders around (and there are often multiple class loaders in use). Therefore, a simpler alternative exists for the cases in which you really want to ask all installed class loaders whether they can load the class: ``ClassLoader::classExists($className)``: .. code-block:: php <?php // Equivalent to if (class_exists('Foo', true)) if (ClassLoader::classExists('Foo')) { // ... } This static method can basically be used as a drop-in replacement for class_exists(..., true). It iterates over all installed class loaders and asks each of them via ``canLoadClass``, returning early (with TRUE) as soon as one class loader returns TRUE from ``canLoadClass``. If this sounds like it can potentially be rather costly then because that is true but it is exactly the same thing that class_exists(..., true) does under the hood, it triggers a complete interaction of all class/auto loaders. Checking for class existence via invoking autoloading was never a cheap thing to do but now it is more obvious and more importantly, this check is no longer interleaved with regular class loading, which avoids having to check each and every class for existence prior to loading it. The vast majority of classes to be loaded are *not* optional and a failure to load such a class is, and should be, a fatal error. The ClassLoader design reflects this. If you have code that requires the usage of class\_exists(..., true) or ClassLoader::classExists during normal runtime of the application (i.e. on each request) try to refactor your design to avoid it. Summary ------- No matter which class loader you prefer to use (Doctrine classes do not care about how they are loaded), we kindly encourage you to adhere to the simple convention of mapping namespaces and class names to a directory structure. Class loading should be simple, automated and uniform. Time is better invested in actual application development than in designing special directory structures, autoloaders and clever caching strategies for class loading.
Simpan