diff --git a/web/export.json b/web/export.json new file mode 100644 index 0000000..703e435 --- /dev/null +++ b/web/export.json @@ -0,0 +1,1585 @@ +{ + "articles": [ + { + "title": "Testing Workshop at DrupalCamp London 2020", + "path": "/articles/drupalcamp-london-testing-workshop", + "is_draft": "false", + "created": "1580860800", + "excerpt": "This year, I\u2019m teaching a workshop at DrupalCamp London.", + "body": "
<\/p>\n\n
This year, I\u2019m teaching a workshop at DrupalCamp London.<\/p>\n\n
The subject will be automated testing and test driven development in Drupal 8, and it will be on Friday 13th March 2020, between 9am and 1pm.<\/p>\n\n
In the workshop, I\u2019ll cover the methodology, approaches and terminology involved with automated testing, look at some examples and work through some exercises, and then take a test driven development approach to creating a new Drupal module.<\/p>\n\n
There are also other workshops on topics including Composer, Drupal Commerce, profiling, and chatbots.<\/p>\n\n
For more information and to register, go to the DrupalCamp London website<\/a>.<\/p>\n",
+ "tags": ["drupal"
+ ,"drupalcamp"
+ ,"testing"
+ ]
+ }, {
+ "title": "Using PSR-4 Autoloading for your Drupal 7 Test Cases",
+ "path": "/articles/psr4-autoloading-test-cases-drupal-7",
+ "is_draft": "false",
+ "created": "1580774400",
+ "excerpt": "How to use the PSR-4 autoloading standard for Drupal 7 Simpletest test cases.",
+ "body": " How to use the PSR-4 autoloading standard for Drupal 7 Simpletest test cases.<\/p>\n\n The typical way of including test cases in Drupal 7 is to add one or more classes within a In order to load the files, each file would need to be declared within the There is a convention that if you have multiple tests for your project, these can be split into different files and grouped within a Whilst splitting tests into separate files makes things more organised, each file needs to be loaded separately.\nThis can be made simpler by using the Xautoload module<\/a>, which supports wildcards when declaring files.<\/p>\n\n This would load all of the Another option is to use PSR-4 (or PSR-0) autoloading.<\/p>\n\n This should be a lot more familiar to those who have worked with Drupal 8, Symfony etc, and means that each test case is in its own file which is cleaner, files have the To do this, create a This also supports subdirectories, so you can group classes within If you want to see an real-world example, see the Drupal 7 branch of the Override Node Options module<\/a>.<\/p>\n\n This is the code within It looks for a the tests directory ( You can still run the tests from within the Simpletest UI, or from the command line using If you want to run a specific test case using the Inspired by Matt Stauffer<\/a>'s live blogging of the keynote<\/a> at Laracon US, I\u2019m going to do the same for the sessions that I\u2019m attending at SymfonyLive London 2019<\/a>...<\/p>\n\n Embrace the Linux philosophy<\/strong><\/p>\n\n Building flexible high-level abstractions on top of low-level ones<\/strong><\/p>\n\n Notifier\n* send messages via a unified api\n* send to one or many receivers\n* Default configu or custom one<\/p>\n\n Failed Messages Listener - 10 lines of glue code<\/p><\/li>\n Experimental component in 5.0<\/strong><\/p><\/li>\n Symfony validation - can be used on messages, not just forms.<\/p><\/li>\n Cache everything<\/p>\n\n Tip: put Command and CommandHandlers in the same directory<\/p><\/li>\n<\/ul>\n\n Robust and failsafe by default<\/p><\/li>\n Streamable uploads - donwload a file<\/p>\n\n Responses are lazy, requests are concurrent<\/p><\/li>\nThe Traditional Way<\/h2>\n\n
.test<\/code> file - e.g.
opdavies.test<\/code>.\nThis would typically include all of the different test cases for that module, and would be placed in the root of the module\u2019s directory alongside the
.info<\/code> and
.module<\/code> files.<\/p>\n\n
.info<\/code> file for the module.<\/p>\n\n
tests<\/code> directory.<\/p>\n\n
; Load a test file at the root of the module\nfiles[] = opdavies.test\n\n; Load a test file from within a subdirectory\nfiles[] = tests\/foo.test\nfiles[] = tests\/bar.test\n<\/code><\/pre>\n\n
Using the xautoload Module<\/h2>\n\n
files[] = tests\/**\/*.test\n<\/code><\/pre>\n\n
.test<\/code> files within the tests directory.<\/p>\n\n
Using PSR-4 Autoloading<\/h2>\n\n
.php<\/code> extension which is more standard, and the name of the file matches the name of the test class for consistency.<\/p>\n\n
src\/Tests<\/code> (PSR-4) or
lib\/Drupal\/{module_name}\/Tests<\/code> (PSR-0) directory within your module, and then add or move your test cases there.\nAdd the appropriate namespace for your module, and ensure that
DrupalWebTestCase<\/code> or
DrupalUnitTestCase<\/code> is also namespaced.<\/p>\n\n
\/\/ src\/Tests\/Functional\/OliverDaviesTest.php\n\nnamespace Drupal\\opdavies\\Tests\\Functional;\n\nclass OliverDaviesTest extends \\DrupalWebTestCase {\n \/\/ ...\n}\n<\/code><\/pre>\n\n
Functional<\/code> and
Unit<\/code> directories if you like.<\/p>\n\n
Digging into the simpletest_test_get_all function<\/h3>\n\n
simpletest.module<\/code> that makes this work:<\/p>\n\n
\/\/ simpletest_test_get_all()\n\n\/\/ ...\n\n$module_dir = DRUPAL_ROOT . '\/' . dirname($filename);\n\n\/\/ Search both the 'lib\/Drupal\/mymodule' directory (for PSR-0 classes)\n\/\/ and the 'src' directory (for PSR-4 classes).\nforeach (array(\n 'lib\/Drupal\/' . $name,\n 'src',\n) as $subdir) {\n\n \/\/ Build directory in which the test files would reside.\n $tests_dir = $module_dir . '\/' . $subdir . '\/Tests';\n\n \/\/ Scan it for test files if it exists.\n if (is_dir($tests_dir)) {\n $files = file_scan_directory($tests_dir, '\/.*\\\\.php\/');\n if (!empty($files)) {\n foreach ($files as $file) {\n\n \/\/ Convert the file name into the namespaced class name.\n $replacements = array(\n '\/' => '\\\\',\n $module_dir . '\/' => '',\n 'lib\/' => '',\n 'src\/' => 'Drupal\\\\' . $name . '\\\\',\n '.php' => '',\n );\n $classes[] = strtr($file->uri, $replacements);\n }\n }\n }\n}\n<\/code><\/pre>\n\n
src\/Tests<\/code> or
lib\/Drupal\/{module_name}\/Tests<\/code>) within the module, and then finds any
.php<\/code> files within it. It then converts the file name into the fully qualified (namespaced) class name and loads it automatically.<\/p>\n\n
Running the Tests<\/h3>\n\n
run-tests.sh<\/code>.<\/p>\n\n
--class<\/code> option, you will now need to include the fully qualified name.<\/p>\n\n
php scripts\/run-tests.sh --class Drupal\\\\opdavies\\\\Tests\\\\Functional\\\\OliverDaviesTest\n<\/code><\/pre>\n",
+ "tags": ["drupal"
+ ,"drupal-planet"
+ ,"drupal-7"
+ ,"testing"
+ ,"simpletest"
+ ,"php"
+ ,"psr"
+ ]
+ }, {
+ "title": "Live Blogging From SymfonyLive London 2019",
+ "path": "/articles/live-blogging-symfonylive-london",
+ "is_draft": "false",
+ "created": "1568332800",
+ "excerpt": "",
+ "body": "
Keynote (Back to the basics)<\/h2>\n\n
\n
dump<\/code> and
var_dump<\/code>)<\/li>\n
What's next?<\/h3>\n\n
\n
\n
inky-extra<\/code> package (Twig 1.12+)<\/li>\n
cssinliner-extra<\/code> package (Twig 1.12+)<\/li>\n
SystemEmail<\/code> class extends templated email<\/li>\n
Sending SMS messages<\/h3>\n\n
\n
Texter<\/code> and
SmsMessage<\/code> class for sending SMS messages<\/li>\n
twilio:\/\/<\/code> and
nemxo:\/\/<\/code><\/li>\n
$sms->setTransport('nexmo')<\/code><\/li>\n
SystemEmail<\/code> and do what you want<\/li>\n
Sending Messages<\/h3>\n\n
\n
ChatMessage<\/code><\/li>\n
$message->setTransport('telegram')<\/code>,
$bus->dispatch($message)<\/code><\/li>\n
SlackOptions<\/code> and
TelegramOptions<\/code> for adding emojis etc<\/li>\n
TransportInterface<\/code>,
MessageInterface<\/code><\/li>\n
New component - SymfonyNotifier<\/h3>\n\n
\n
InvoiceNotification<\/code> extends
Notification<\/code>.
getChannels<\/code>\n\n
\n
ChatNotificationInterface<\/code> -
asChatMessage()<\/code><\/li>\n<\/ul><\/li>\n
\n
composer req twilio-notifier telegram-notifier<\/code><\/li>\n<\/ul><\/li>\n
\n
What about a SystemNotification?<\/h3>\n\n
\n
new SystemNotification<\/code>,
Notifier::getSystemReceivers<\/code><\/li>\n
ExceptionNotification<\/code> - get email with stack trace attached<\/li>\n<\/ul>\n\n
\u00a0How can we leverage this new infrastructure?<\/h3>\n\n
\n
Monolog NotifierHandler<\/code> - triggered on
Error<\/code> level logs<\/li>\n
Queues, busses and the Messenger component (Tobias Nyholm)<\/h2>\n\n
\n
2013<\/h3>\n\n
\n
CurrentUserProvider<\/code> service to core, should be passed as an argument. Cannot test.<\/li>\n
\n
CommandHandler<\/code><\/li>\n<\/ul>\n\n
What did we win?<\/h4>\n\n
\n
\n
2016<\/h3>\n\n
\n
Symfony Messenger<\/h3>\n\n
\n
composer req symfony\/messager<\/code> - best MessageBus implementation<\/li>\n
messenger:message_hander<\/code> tag in config<\/li>\n
MessageHandlerInterface<\/code><\/li>\n
MESSENGER_DSN<\/code> added to
.env<\/code><\/li>\n
bin\/console messager:consume-messages<\/code>. Time limit with
--time-limit 300<\/code><\/li>\n
Issues<\/h3>\n\n
\n
FooTransformer implements TransformerInterface<\/code>.<\/li>\n
Multiple buses<\/h4>\n\n
\n
Envelope<\/h4>\n\n
\n
Failures<\/h4>\n\n
\n
Creating entities<\/h4>\n\n
\n
\n
\u00a0HttpClient (Nicolas Grekas)<\/h2>\n\n
\n
\n
HttpClient::create()<\/code>.
$client->get()<\/code><\/li>\n
Client<\/code> for
HttpClientInterface<\/code><\/li>\n
toArray()<\/code><\/li>\n
What can we do with the Response?<\/h3>\n\n
\n
getStatusCode(): int<\/code><\/li>\n
getHeaders(): array<\/code><\/li>\n
getContent(): string<\/code><\/li>\n
toArray(): array<\/code><\/li>\n
cancel(): void<\/code><\/li>\n
getInfo(): array<\/code> - metadata<\/li>\n
What about PSR-18?<\/h3>\n\n
\n
What about the remaining 20%?<\/h3>\n\n
\n
Some of the options<\/h4>\n\n
\n
timeout<\/code> - control inactivity periods<\/li>\n
proxy<\/code> - get through a http proxy<\/li>\n
on_progress<\/code> - display a progress bar \/ build a scoped client<\/li>\n
base_url<\/code> - resolve relative URLS \/ build a scoped client<\/li>\n
resolve<\/code> - protect webhooks against calls to internal endpoints<\/li>\n
max_redirects<\/code> - disable or limit redirects<\/p><\/li>\n
$mimeParts->toIterable()<\/code>.<\/p><\/li>\n
foreach ($client->stream($response) as $chunk) {\n \/\/ ... \n}\n<\/code><\/pre><\/li>\n
foreach ($client->stream($responses) as $response => $chunk) {\n if ($chunk->isLast()) {\n \/\/ a $response completed\n } else {\n \/\/ a $response's got network activity or timeout\n }\n}\n<\/code><\/pre>\n\n
\n
Stream<\/code> has second argument, max number of seconds to wait before yielding a timeout chunk<\/li>\n
ResponseInterface::getInfo()<\/code> - get response headers, redirect count and URL, start time, HTTP method and code, user data and URL\n\n
\n
getInfo('debug')<\/code> - displays debug information<\/li>\n<\/ul><\/li>\n<\/ul>\n\n
The components<\/h3>\n\n
\n