Skip to content

Commit 94ba840

Browse files
authored
Merge pull request #206 from dotkernel/issue-204
Use only .md files
2 parents 8370856 + 910c427 commit 94ba840

513 files changed

Lines changed: 5469 additions & 28388 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎composer.json‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,15 @@
3636
"dotkernel/dot-response-header": "^3.6",
3737
"laminas/laminas-component-installer": "^3.5.0",
3838
"laminas/laminas-config-aggregator": "^1.17.0",
39+
"league/commonmark": "^2.10",
3940
"mezzio/mezzio": "^3.24.0",
4041
"mezzio/mezzio-fastroute": "^3.13.0",
4142
"mezzio/mezzio-twigrenderer": "^2.17.0",
4243
"ramsey/uuid": "^4.5.0",
4344
"ramsey/uuid-doctrine": "^2.1.0",
44-
"roave/psr-container-doctrine": "^5.2.2 || ^6.0.0"
45+
"roave/psr-container-doctrine": "^5.2.2 || ^6.0.0",
46+
"symfony/yaml": "^8.1",
47+
"twig/markdown-extra": "^3.28"
4548
},
4649
"require-dev": {
4750
"filp/whoops": "^2.17.0",

‎config/autoload/templates.global.php‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
declare(strict_types=1);
44

5+
use Twig\Extra\Markdown\MarkdownExtension;
6+
use Twig\RuntimeLoader\RuntimeLoaderInterface;
7+
58
return [
69
'templates' => [
710
'extension' => 'html.twig',
@@ -12,10 +15,14 @@
1215
'autoescape' => 'html',
1316
'auto_reload' => true,
1417
'cache_dir' => 'data/cache/twig',
15-
'extensions' => [],
18+
'extensions' => [
19+
MarkdownExtension::class,
20+
],
1621
'globals' => [],
1722
'optimizations' => -1,
18-
'runtime_loaders' => [],
23+
'runtime_loaders' => [
24+
RuntimeLoaderInterface::class,
25+
],
1926
'timezone' => 'UTC',
2027
],
2128
];

‎public/md-articles/android/listen-for-android-install-referrer.md‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,14 @@ language: "en"
1212

1313
## Getting Referrer Data at Install Time
1414

15-
Android market sends information at the moment of app install, delivered as a broadcasted intent by Android market at install time - even before the app is opened for the first time.
16-
This can be used to create custom links to an Android application, including bits of information about the referrer, sent directly to the app for processing at install.
17-
It can be a simple and accurate solution for mobile app install tracking, among other uses.
15+
Have you ever wondered if Android market sends you information at the moment of app install? Wouldn't it be nice to create custom links to your Android application, including bits of information about the referrer, and send it directly to the app for processing at install? This could be a simple and accurate solution for mobile app install tracking, but I'm sure you can find this useful in many ways.
16+
17+
With Android, you actually get this information as a broadcasted intent by Android market at install time - even before opening your app...
1818

1919
## FAQ
2020

2121
**Q: Does Android send information when the app is installed?**
22-
A: Yes.
23-
Android market broadcasts an intent containing referrer information at the moment the app is installed.
22+
A: Yes. Android market broadcasts an intent containing referrer information at the moment the app is installed.
2423

2524
**Q: When is this referrer information available to the app?**
2625
A: It's delivered as a broadcasted intent at install time, before the app is ever opened.

‎public/md-articles/android/multiple-broadcast-receivers-in-the-same-app-for-the-same-action.md‎

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,9 @@ language: "en"
1010

1111
# Multiple broadcast receivers in the same app, for the same action
1212

13-
## The problem
13+
Did you come to a point where using multiple broadcast receivers to listen for the same intent, separatly, in the same android app, leads to unexpected results? If that's the case, one broadcast receiver might consume the broadcasted intent, [online casino](http://www.cillap.com/) leaving the others with nothing to receive. This can be the case where you use 3rd party libraries with broadcast receivers defined.
1414

15-
When multiple broadcast receivers are registered separately to listen for the same intent within the same Android app, this can lead to unexpected results: one broadcast receiver might consume the broadcasted intent, leaving the others with nothing to receive.
16-
This can happen when using 3rd party libraries that define their own broadcast receivers alongside an app's own receivers.
17-
18-
## The approach
19-
20-
A solution for this kind of problem is a code snippet inspired by the way Admob for Android solves this, as shown in Admob's own documentation, using meta-data in the manifest file.
15+
The following is a solution for this kind of problem, a code snippet inspired by the way Admob for android seems to solve this, as shown in their [documentation](http://developer.admob.com/wiki/Android_App_Download_Tracking), using meta-data in manifest file...[[read more](http://n3vrax.wordpress.com/2011/07/15/multiple-broadcast-receivers-in-the-same-app-for-the-same-action/)].
2116

2217
## FAQ
2318

@@ -26,7 +21,3 @@ A: When multiple broadcast receivers are registered separately to listen for the
2621

2722
**Q: When is this issue most likely to occur?**
2823
A: This can happen when you use 3rd party libraries that already define their own broadcast receivers alongside your app's own receivers.
29-
30-
## Resources
31-
32-
- [Admob App Download Tracking documentation](http://developer.admob.com/wiki/Android_App_Download_Tracking)

‎public/md-articles/architecture/configprovider-bootstrap-modern-php-applications.md‎

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,81 +11,102 @@ language: "en"
1111
# ConfigProvider - Bootstrap Modern PHP Applications
1212

1313
## TL;DR
14-
1514
In PHP, a `ConfigProvider` is a class or callable that is part of an application's bootstrap process, returning configuration data that tells the platform which middleware should run, in what order, and under what conditions.
1615
Frameworks like Mezzio, Laminas, Slim, and the Dotkernel Headless Platform use ConfigProviders to declare middleware pipeline configuration, dependency injection mappings, and request handlers, which get merged together automatically during bootstrap (except in Dotkernel, where new ConfigProviders must be registered manually).
1716

17+
In PHP, the `ConfigProvider` is a class that is part of an application's bootstrap process. **It's a class or callable that returns configuration data telling the platform which middleware should run, in what order, and sometimes under what conditions.**
18+
19+
If you're talking specifically about the ConfigProvider in the Laminas/Mezzio ecosystem, it's literally an array of configuration, settings, or anything else your application needs.
20+
1821
## Where Is the ConfigProvider Used?
1922

20-
Mezzio (formerly Zend Expressive), Laminas, Slim, the Dotkernel Headless Platform, and other middleware-based frameworks often have a `ConfigProvider` class.
21-
In Laminas/Mezzio specifically, each module or package may contain a `ConfigProvider` that returns:
23+
Mezzio (formerly Zend Expressive), Laminas, Slim, the Dotkernel Headless Platform, or other middleware-based frameworks often have a `ConfigProvider` class. In Laminas/Mezzio specifically, each module or package may contain a `ConfigProvider` that returns:
2224

23-
- Middleware pipeline configuration:
25+
- Middleware pipeline configuration.
2426
- Middleware classes or service names.
2527
- Error-handling middleware, which should have the lowest priority.
2628
- Middleware groups or nested arrays.
2729
- Dependency injection mappings.
2830
- Request Handlers.
2931

30-
Example structure used in Dotkernel:
32+
Example in Dotkernel, which is an approach similar to Laminas/Mezzio:
3133

32-
```php
34+
```
3335
class ConfigProvider
3436
{
3537
public function __invoke(): array
3638
{
37-
return [ /* ... */ ];
39+
return [
40+
'dependencies' => $this->getDependencies(),
41+
'templates' => $this->getTemplates(),
42+
];
3843
}
3944
4045
public function getDependencies(): array
4146
{
42-
return [
43-
'factories' => [ /* ... */ ],
44-
'invokables' => [ /* ... */ ],
47+
return ,
48+
'invokables' => ,
4549
];
4650
}
4751
4852
public function getTemplates(): array
4953
{
50-
return [
51-
'paths' => [ /* ... */ ],
52-
'error' => [ /* ... */ ],
54+
return ,
55+
'error' => ,
5356
];
5457
}
5558
}
5659
```
5760

58-
What each item means:
61+
What each item above means:
62+
63+
- `dependencies` is used by the dependency injector (like [laminas-servicemanager](https://docs.mezzio.dev/mezzio/v3/features/container/laminas-servicemanager/)) to construct every requested service.
64+
- `factories` will have the factory build the service.
65+
- `invokables` will use `new` directly.
66+
- You can also use `aliases` to redirect to another service name and `delegators` to wrap the original service.
67+
- `templates` defines the paths for the template files.
68+
69+
## How the ConfigProvider works
5970

60-
| Item | Meaning |
61-
|---|---|
62-
| `dependencies` | Used by the dependency injector (e.g. laminas-servicemanager) to construct every requested service. |
63-
| `factories` | The factory builds the service. |
64-
| `invokables` | The service is built with `new` directly. |
65-
| `aliases` | Redirects to another service name. |
66-
| `delegators` | Wraps the original service. |
67-
| `templates` | Defines the paths for the template files. |
71+
The ConfigProvider is automatically picked up by the framework during application bootstrap. Let's look at it step by step:
72+
73+
- **Merge the global configuration** - All ConfigProviders are merged into one array.
74+
- **Read the configuration array** - The call is similar to the below and expects an array of entries:
75+
76+
```
77+
$config = $container->get('config') ?? [];
78+
```
6879

69-
## How the ConfigProvider Works
80+
- **Resolve item** - `$app->pipe()` is called to resolve one of the below instances:
81+
- Resolve the service name from the container
82+
- Wrap the middleware, if an array is provided
83+
- Call the closure or invokable object.
84+
- **Handle errors** - This middleware is the last one in the pipeline to make sure it handles any exceptions.
85+
- **Execute at runtime** - [Laminas Stratigility](https://docs.laminas.dev/laminas-stratigility/) iterates over the pipeline in the order it was registered.
86+
- Each middleware can **handle** the request and return a response, or **delegate** execution to the next middleware in the pipeline, until a `ResponseInterface` is returned to the client.
7087

71-
The ConfigProvider is automatically picked up by the framework during application bootstrap:
88+
Below you can see how Mezzio and Dotkernel merge and use ConfigProviders to build the middleware pipeline and dependencies.
7289

73-
1. **Merge the global configuration** - All ConfigProviders are merged into one array.
74-
2. **Read the configuration array** - A call similar to `$config = $container->get('config') ?? [];` reads an array of entries.
75-
3. **Resolve item** - `$app->pipe()` is called to resolve one of the following: resolve the service name from the container, wrap the middleware if an array is provided, or call the closure or invokable object.
76-
4. **Handle errors** - The error-handling middleware is the last one in the pipeline, to make sure it can handle any exceptions.
77-
5. **Execute at runtime** - Laminas Stratigility iterates over the pipeline in the order it was registered. Each middleware can handle the request and return a response, or delegate execution to the next middleware in the pipeline, until a `ResponseInterface` is returned to the client.
90+
![](/uploads/article/019f8a80-cc92-7277-92c8-c0e68d81615f/ConfigProvider2.png)
7891

7992
## Benefits
8093

81-
- **Centralized setup** - Instead of hardcoding bootstrap code, it's declared in a config provider so it's easy to read, change, or extend.
82-
- **Modular** - Each package can ship with its own config without interfering with others.
83-
- **Container-friendly** - Works well with frameworks using DI containers like Laminas ServiceManager, PHP-DI, or Pimple.
84-
- **Standardized service definitions** - Consistent rules for object creation, separate from business logic.
85-
- **Auto-Discovery** - In Laminas/Mezzio, the ConfigAggregator automatically loads and merges all ConfigProviders.
86-
Dotkernel is an exception: new ConfigProviders have to be added manually in `config/config.php`, because all the initial ConfigProviders required to install the applications are already injected.
87-
- **Environment-agnostic** - Returns an array that defines dev, test, or prod environments.
88-
- **Testability** - The consistent, central configuration promotes isolated (e.g. per-module) testing, easier swapping of dependencies, and assertion of pipeline setup (e.g. checking if a config key is present).
94+
- Centralized setup – Instead of hardcoding bootstrap code, you declare it in a config provider so it's easy to read, change, or extend.
95+
- Modular – Each package can ship with its own config without interfering with others.
96+
- Container-friendly – It works well with frameworks using DI containers like Laminas ServiceManager, PHP-DI, or Pimple.
97+
- Standardized service definitions - It has consistent rules for object creation that are separate from business logic.
98+
- Auto-Discovery - In Laminas/Mezzio, the [ConfigAggregator](https://docs.laminas.dev/laminas-config-aggregator/) automatically loads and merges all ConfigProviders.
99+
100+
> Dotkernel is an exception to this rule: new ConfigProviders have to be added manually in `config/config.php`, because all the initial ConfigProviders required to install the applications are already injected.
101+
102+
- Environment-agnostic - It returns an array that defines dev, test, or prod environments.
103+
- Testability - The consistent, central configuration promotes isolated (e.g. per-module) testing, easier swapping of dependencies and the assertion of pipeline setup (e.g. check if a config key is present).
104+
105+
## Additional Resources
106+
107+
- [Mezzio Container](https://docs.mezzio.dev/mezzio/v3/features/container/config/)
108+
- [Laminas Config Aggregator](https://docs.laminas.dev/laminas-config-aggregator/config-providers/)
109+
- [PSR-15 (HTTP Server Request Handlers)](https://www.php-fig.org/psr/psr-15/)
89110

90111
## FAQ
91112

@@ -96,20 +117,13 @@ A: It is a class that is part of an application's bootstrap process: a class or
96117
A: In the Laminas/Mezzio ecosystem, it's literally an array of configuration, settings, or anything else the application needs, and each module or package may contain its own ConfigProvider returning middleware pipeline configuration, dependency injection mappings, and request handlers.
97118

98119
**Q: What is the difference between 'factories' and 'invokables' in the dependencies array?**
99-
A: `factories` will have the factory build the service, while `invokables` will use `new` directly.
100-
You can also use `aliases` to redirect to another service name and `delegators` to wrap the original service.
120+
A: factories will have the factory build the service, while invokables will use new directly. You can also use aliases to redirect to another service name and delegators to wrap the original service.
101121

102122
**Q: How does the ConfigProvider get used during application bootstrap?**
103-
A: It is automatically picked up by the framework during bootstrap: all ConfigProviders are merged into one array, the configuration array is read, each item is resolved via `$app->pipe()`, the error-handling middleware is placed last in the pipeline, and at runtime Laminas Stratigility iterates over the pipeline in the order it was registered.
123+
A: It is automatically picked up by the framework during bootstrap: all ConfigProviders are merged into one array, the configuration array is read (similar to $config = $container->get('config') ?? [];), each item is resolved via $app->pipe(), the error-handling middleware is placed last in the pipeline, and at runtime Laminas Stratigility iterates over the pipeline in the order it was registered.
104124

105125
**Q: Are new ConfigProviders auto-discovered in Dotkernel?**
106-
A: Dotkernel is an exception to the usual auto-discovery rule: new ConfigProviders have to be added manually in `config/config.php`, because all the initial ConfigProviders required to install the applications are already injected.
126+
A: Dotkernel is an exception to the usual auto-discovery rule: new ConfigProviders have to be added manually in config/config.php, because all the initial ConfigProviders required to install the applications are already injected.
107127

108128
**Q: What are the benefits of using a ConfigProvider?**
109129
A: Benefits include centralized setup instead of hardcoded bootstrap code, modularity so each package can ship its own config, container-friendliness with DI containers like Laminas ServiceManager, PHP-DI or Pimple, standardized service definitions, environment-agnostic configuration for dev/test/prod, and better testability of the pipeline setup.
110-
111-
## Resources
112-
113-
- [Mezzio Container](https://docs.mezzio.dev/mezzio/v3/features/container/config/)
114-
- [Laminas Config Aggregator](https://docs.laminas.dev/laminas-config-aggregator/config-providers/)
115-
- [PSR-15 (HTTP Server Request Handlers)](https://www.php-fig.org/psr/psr-15/)

0 commit comments

Comments
 (0)