Skip to content

Commit

Permalink
Automated deployment: Thu Mar 21 12:00:28 UTC 2024 master
Browse files Browse the repository at this point in the history
  • Loading branch information
froschdesign committed Mar 21, 2024
1 parent e62ebe4 commit f18e630
Show file tree
Hide file tree
Showing 13 changed files with 122 additions and 136 deletions.
166 changes: 73 additions & 93 deletions getting-started/database-and-models/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -570,11 +570,11 @@ <h2 id="the-model-files">The model files</h2>
public $artist;
public $title;

public function exchangeArray(array $data)
public function exchangeArray(array $array): void
{
$this-&gt;id = !empty($data['id']) ? $data['id'] : null;
$this-&gt;artist = !empty($data['artist']) ? $data['artist'] : null;
$this-&gt;title = !empty($data['title']) ? $data['title'] : null;
$this-&gt;id = ! empty($array['id']) ? $array['id'] : null;
$this-&gt;artist = ! empty($array['artist']) ? $array['artist'] : null;
$this-&gt;title = ! empty($array['title']) ? $array['title'] : null;
}
}</code></pre>
<p>Our <code>Album</code> entity object is a PHP class. In order to work with laminas-db's
Expand Down Expand Up @@ -661,71 +661,82 @@ <h2 id="the-model-files">The model files</h2>
of these methods is, hopefully, self-explanatory.</p>
<h2 id="using-servicemanager-to-configure-the-table-gateway-and-inject-into-the-albumtable">Using ServiceManager to configure the table gateway and inject into the AlbumTable</h2>
<p>In order to always use the same instance of our <code>AlbumTable</code>, we will use the
<code>ServiceManager</code> to define how to create one. This is most easily done in the
<code>Module</code> class where we create a method called <code>getServiceConfig()</code> which is
automatically called by the <code>ModuleManager</code> and applied to the <code>ServiceManager</code>.
We'll then be able to retrieve when we need it.</p>
<code>ServiceManager</code> to define how to create one.
This is most easily done by adding a <code>ServiceManager</code> configuration to the <code>module.config.php</code>
which is automatically loaded by the <code>ModuleManager</code> and applied to the <code>ServiceManager</code>.
We'll then be able to retrieve the <code>AlbumTable</code> when we need it.</p>
<p>To configure the <code>ServiceManager</code>, we can either supply the name of the class to
be instantiated or a factory (closure, callback, or class name of a factory
class) that instantiates the object when the <code>ServiceManager</code> needs it. We start
by implementing <code>getServiceConfig()</code> to provide a factory that creates an
<code>AlbumTable</code>. Add this method to the bottom of the <code>module/Album/src/Module.php</code>
file:</p>
be instantiated and a factory (closure, callback, or class name of a factory
class) that instantiates the object when the <code>ServiceManager</code> needs it. </p>
<p>Add a <code>service_manager</code> configuration to <code>module/Album/config/module.config.php</code>:</p>
<!-- markdownlint-disable MD033 -->
<pre class="language-php" data-line="3-6,13-30"><code>
<pre class="language-php" data-line="3,38-41"><code>
namespace Album;

// Add these import statements:
use Album\Model\AlbumTableFactory;
use Laminas\Router\Http\Segment;
use Laminas\ServiceManager\Factory\InvokableFactory;

return [
'controllers' => [
// ...
],

'router' => [
// ..
],
'view_manager' => [
// ...
],
'service_manager' => [
'factories' => [
Model\AlbumTable::class => AlbumTableFactory::class,
],

],
];
</code></pre>
<!-- markdownlint-enable MD033 -->

<p>This method returns an array of <code>factories</code> that are all merged together by the
<code>ModuleManager</code> before passing them to the <code>ServiceManager</code>. When requesting the <code>ServiceManager</code>
to create <code>Album\Model\AlbumTable</code>, the <code>ServiceManager</code> will invoke the <code>AlbumTableFactory</code> class, which we need to create next.</p>
<p>Let's create the <code>AlbumTableFactory.php</code> factory in <code>module/Album/src/Model</code>:</p>
<pre class="highlight"><code class="language-php">namespace Album\Model;

use Laminas\Db\Adapter\AdapterInterface;
use Laminas\Db\ResultSet\ResultSet;
use Laminas\Db\TableGateway\TableGateway;
use Laminas\ModuleManager\Feature\ConfigProviderInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Psr\Container\ContainerInterface;

class Module implements ConfigProviderInterface
class AlbumTableFactory implements FactoryInterface
{
// getConfig() method is here

// Add this method:
public function getServiceConfig()
public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null): AlbumTable
{
return [
'factories' => [
Model\AlbumTable::class => function($container) {
$tableGateway = $container->get(Model\AlbumTableGateway::class);
return new Model\AlbumTable($tableGateway);
},
Model\AlbumTableGateway::class => function ($container) {
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Model\Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
],
];
$dbAdapter = $container-&gt;get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
$resultSetPrototype-&gt;setArrayObjectPrototype(new Album());
$tableGateway = new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
return new AlbumTable($tableGateway);
}
}
</code></pre>
<!-- markdownlint-enable MD033 -->

<p>This method returns an array of <code>factories</code> that are all merged together by the
<code>ModuleManager</code> before passing them to the <code>ServiceManager</code>. The factory for
<code>Album\Model\AlbumTable</code> uses the <code>ServiceManager</code> to create an
<code>Album\Model\AlbumTableGateway</code> service representing a <code>TableGateway</code> to pass to
its constructor. We also tell the <code>ServiceManager</code> that the <code>AlbumTableGateway</code>
service is created by fetching a <code>Laminas\Db\Adapter\AdapterInterface</code>
implementation (also from the <code>ServiceManager</code>) and using it to create a
}</code></pre>
<p>The <code>AlbumTableFactory</code> factory uses the <code>ServiceManager</code> to fetch a <code>Laminas\Db\Adapter\AdapterInterface</code>
implementation (also from the <code>ServiceManager</code>) and use it to create a
<code>TableGateway</code> object. The <code>TableGateway</code> is told to use an <code>Album</code> object
whenever it creates a new result row. The <code>TableGateway</code> classes use the
prototype pattern for creation of result sets and entities. This means that
instead of instantiating when required, the system clones a previously
instantiated object. See
instantiated object. Then, finally, the factory creates a <code>AlbumTable</code> object passing it the <code>TableGateway</code> object.
See
<a href="https://dbglory.wordpress.com/2012/03/10/php-constructor-best-practices-and-the-prototype-pattern/">PHP Constructor Best Practices and the Prototype Pattern</a>
for more details.</p>
<blockquote>
<h3 id="factories">Factories</h3>
<p>The above demonstrates building factories as closures within your module
class. Another option is to build the factory as a <em>class</em>, and then map the
class in your module configuration. This approach has a number of benefits:</p>
<p>The above demonstrates building factories as a <em>class</em> and mapping the
class factory in your module configuration. Another option would have been to use a closure that contains
the same code a the <code>AlbumTableFactory</code>. Using a class for the factory has a number of benefits:</p>
<ul>
<li>The code is not parsed or executed unless the factory is invoked.</li>
<li>You can easily unit test the factory to ensure it does what it should.</li>
Expand Down Expand Up @@ -808,62 +819,31 @@ <h2 id="back-to-the-controller">Back to the controller</h2>
</code></pre>
<!-- markdownlint-enable MD033 -->

<p>Our controller now depends on <code>AlbumTable</code>, so we will need to create a factory
for the controller. Similar to how we created factories for the model, we'll
create it in our <code>Module</code> class, only this time, under a new method,
<code>Album\Module::getControllerConfig()</code>:</p>
<p>Our controller now depends on <code>AlbumTable</code>, so we will need to update the factory
for the controller so that it will inject the <code>AlbumTable</code>.</p>
<p>We will use the <code>ReflectionBasedAbstractFactory</code> factory to build the <code>AlbumController</code>.
<code>ReflectionBasedAbstractFactory</code> provides a reflection-based approach to instantiation, resolving constructor dependencies to the relevant services. Since the <code>AlbumController</code> constructor has an <code>AlbumTable</code> parameter, the factory will instantiate an <code>AlbumTable</code> instance and pass it to the <code>AlbumController</code>constructor.</p>
<p>Then we can modify the <code>controllers</code> section of the <code>module.config.php</code> to
use <code>ReflectionBasedAbstractFactory</code>:</p>
<!-- markdownlint-disable MD033 -->
<pre class="language-php" data-line="12-24"><code>
<pre class="language-php" data-line="3,10"><code>
namespace Album;

use Laminas\Db\Adapter\AdapterInterface;
use Laminas\Db\ResultSet\ResultSet;
use Laminas\Db\TableGateway\TableGateway;
use Laminas\ModuleManager\Feature\ConfigProviderInterface;

class Module implements ConfigProviderInterface
{
// getConfig() and getServiceConfig() methods are here

// Add this method:
public function getControllerConfig()
{
return [
'factories' => [
Controller\AlbumController::class => function($container) {
return new Controller\AlbumController(
$container->get(Model\AlbumTable::class)
);
},
],
];
}
}
</code></pre>
<!-- markdownlint-enable MD033 -->

<p>Because we're now defining our own factory, we can modify our
<code>module.config.php</code> to remove the definition. Open
<code>module/Album/config/module.config.php</code> and remove the following lines:</p>
<!-- markdownlint-disable MD033 -->
<pre class="language-php" data-line="3-4,7-12"><code>
namespace Album;

// Remove this:
use Laminas\ServiceManager\Factory\InvokableFactory;
use Laminas\ServiceManager\AbstractFactory\ReflectionBasedAbstractFactory;
use Album\Model\AlbumTableFactory;
use Laminas\Router\Http\Segment;

return [
// And remove the entire "controllers" section here:
'controllers' => [
'factories' => [
Controller\AlbumController::class => InvokableFactory::class,
Controller\AlbumController::class => ReflectionBasedAbstractFactory::class
],
],

/* ... */
// the rest of the code
];

</code></pre>
<!-- markdownlint-enable MD033 -->

<p>We can now access the property <code>$table</code> from within our controller whenever we
need to interact with our model.</p>
Expand Down
15 changes: 9 additions & 6 deletions getting-started/forms-and-actions/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,9 @@ <h2 id="adding-new-albums">Adding new albums</h2>
<code>module/Album/src/Form/AlbumForm.php</code> with the following contents:</p>
<pre class="highlight"><code class="language-php">namespace Album\Form;

use Laminas\Form\Element\Hidden;
use Laminas\Form\Element\Submit;
use Laminas\Form\Element\Text;
use Laminas\Form\Form;

class AlbumForm extends Form
Expand All @@ -524,25 +527,25 @@ <h2 id="adding-new-albums">Adding new albums</h2>

$this-&gt;add([
'name' =&gt; 'id',
'type' =&gt; 'hidden',
'type' =&gt; Hidden::class,
]);
$this-&gt;add([
'name' =&gt; 'title',
'type' =&gt; 'text',
'type' =&gt; Text::class,
'options' =&gt; [
'label' =&gt; 'Title',
],
]);
$this-&gt;add([
'name' =&gt; 'artist',
'type' =&gt; 'text',
'type' =&gt; Text::class,
'options' =&gt; [
'label' =&gt; 'Artist',
],
]);
$this-&gt;add([
'name' =&gt; 'submit',
'type' =&gt; 'submit',
'type' =&gt; Submit::class,
'attributes' =&gt; [
'value' =&gt; 'Go',
'id' =&gt; 'submitbutton',
Expand Down Expand Up @@ -792,8 +795,8 @@ <h3 id="form-method">Form method</h3>
<code>formCollection($form)</code> with the open and close form tags. This helps reduce the
complexity of your view script in situations where the default HTML rendering of
the form is acceptable.</p>
<p>You should now be able to use the "Add new album" link on the home page of the
application to add a new album record, resulting in something like the
<p>You should now be able to use the "Add new album" page of the
application at <code>http://localhost:8080/album/add</code> to add a new album record, resulting in something like the
following:</p>
<p><img alt="Add Album Form" src="../../images/user-guide.forms-and-actions.album-form-add-original.png" class="img-responsive"/></p>
<p>This doesn't look all that great! The reason is because Bootstrap, the CSS
Expand Down
12 changes: 8 additions & 4 deletions getting-started/routing-and-controllers/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -700,23 +700,27 @@ <h4 id="conventions-not-strictly-enforced">Conventions not strictly enforced</h4
</thead>
<tbody>
<tr>
<td><code>http://laminas-mvc-tutorial.localhost/album</code></td>
<td><code>http://localhost:8080/album</code></td>
<td><code>Album\Controller\AlbumController::indexAction</code></td>
</tr>
<tr>
<td><code>http://laminas-mvc-tutorial.localhost/album/add</code></td>
<td><code>http://localhost:8080/album/add</code></td>
<td><code>Album\Controller\AlbumController::addAction</code></td>
</tr>
<tr>
<td><code>http://laminas-mvc-tutorial.localhost/album/edit</code></td>
<td><code>http://localhost:8080/album/edit</code></td>
<td><code>Album\Controller\AlbumController::editAction</code></td>
</tr>
<tr>
<td><code>http://laminas-mvc-tutorial.localhost/album/delete</code></td>
<td><code>http://localhost:8080/album/delete</code></td>
<td><code>Album\Controller\AlbumController::deleteAction</code></td>
</tr>
</tbody>
</table></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If you are using self-hosted Apache, replace <code>http://localhost:8080/</code> by <code>http://laminas-mvc-tutorial.localhost/</code></p>
</div>
<p>We now have a working router and the actions are set up for each page of our
application.</p>
<p>It's time to build the view and the model layer.</p>
Expand Down
7 changes: 3 additions & 4 deletions getting-started/skeleton-application/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ <h3 id="prompts-and-default-values">Prompts and default values</h3>
<pre class="highlight"><code class="language-text"> Would you like to install database support (installs laminas-db)? y/N</code></pre>
<p>We <em>will</em> be using laminas-db extensively in this tutorial, so hit "y" followed by
"Enter". You should see the following text appear:</p>
<pre class="highlight"><code class="language-text"> Will install laminas/laminas-db (^2.8.1)
<pre class="highlight"><code class="language-text"> Will install laminas/laminas-db (^2.17.0)
When prompted to install as a module, select application.config.php or modules.config.php</code></pre>
<p>The next prompt is:</p>
<pre class="highlight"><code class="language-text"> Would you like to install forms support (installs laminas-form)? y/N</code></pre>
Expand All @@ -543,12 +543,11 @@ <h3 id="prompts-and-default-values">Prompts and default values</h3>
<p>At this point, we can answer "n" to the remaining features:</p>
<pre class="highlight"><code class="language-text"> Would you like to install JSON de/serialization support? y/N
Would you like to install logging support? y/N
Would you like to install MVC-based console support? (We recommend migrating to symfony/console, or Aura.CLI) y/N
Would you like to install command-line interface support? y/N
Would you like to install i18n support? y/N
Would you like to install the official MVC plugins, including PRG support, identity, and flash messages? y/N
Would you like to use the PSR-7 middleware dispatcher? y/N
Would you like to install sessions support? y/N
Would you like to install MVC testing support? y/N
Would you like to install the laminas-di integration for laminas-servicemanager? y/N</code></pre>
<p>At a certain point, you'll see the following text:</p>
<pre class="highlight"><code class="language-text">Updating root package
Expand All @@ -561,7 +560,7 @@ <h3 id="prompts-and-default-values">Prompts and default values</h3>
Please select which config file you wish to inject 'Laminas\Db' into:
[0] Do not inject
[1] config/modules.config.php
Make your selection (default is 0):</code></pre>
Make your selection (default is 1):</code></pre>
<p>We want to enable the various selections we made in the application. As such,
we'll choose <code>1</code>, which will then give us the following prompt:</p>
<pre class="highlight"><code class="language-text"> Remember this option for other packages of the same type? (y/N)</code></pre>
Expand Down
Binary file modified images/user-guide.database-and-models.album-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/user-guide.forms-and-actions.add-album-form.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/user-guide.forms-and-actions.album-form-add-original.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/user-guide.skeleton-application.404.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/user-guide.skeleton-application.hello-world.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -965,5 +965,5 @@ <h5 class="modal-title">Search</h5>

<!--
MkDocs version : 1.5.3
Build Date UTC : 2024-01-26 09:26:03.341628+00:00
Build Date UTC : 2024-03-21 12:00:26.837643+00:00
-->
2 changes: 1 addition & 1 deletion search/search_index.json

Large diffs are not rendered by default.

Loading

0 comments on commit f18e630

Please sign in to comment.