Matthias NobackContext passing (24.4.2018, 07:52 UTC)

I'm working on another "multi-tenant" PHP web application project and I noticed an interesting series of events. It felt like a natural progression and by means of a bit of dangerous induction, I'm posing the hypothesis that this is how things are just bound to happen in such projects.

In the beginning we start out with a framework that has some authentication functionality built-in. We can get the "current user" from the session, or from some other session-based object. We'll also need the "current company" (or the "current organization") of which the current user is a member.

In the web controller, we take this information out of the session (which we can possibly reach through the "request" object passed to the controller action as an argument). Then we start doing the work; making queries, making changes, sending mails, etc. All on behalf of the current user and the current organization. These valuable pieces of information are passed to basically any method, because everything has to happen in the context of the user/company.

Soon this starts to feel like a code smell known as a Data Clump: the same data hanging around together. This results in the first step in the eternal progression of events:

1. Injecting the session

Classes that need the current user, etc. will get the session injected, so they can take the relevant contextual information out of it to do their work.

It may be a bit optimistic to assume that the first solution that comes to mind is injecting the session. I'm afraid that many projects will have some global static method from which you can retrieve the context data.

Injecting the session is almost as bad as getting it from some globally available place. It couples every bit of your project to the framework, which is a bad place to be in (I'll write about it some other time).

Magic solutions

Talking about frameworks (and libraries) - they usually offer developers some magic alternative solutions. For example, Doctrine ORM has the concept of "filters", which can automatically modify queries to only return records owned by the current user, company, etc. Of course, these filter classes need to have access to the session too.

I really don't think that filters are a good solution for the problem at hand - the fact that the query gets modified behind the scenes is nowhere visible in the regular flow of your code, which is dangerous. I favor a more explicit approach here (see below: "Passing contextual values on a need-to-know basis").

Besides framework coupling, sessions will certainly be annoying to work with if at some point you'll feel the irrational urge to write tests for your code. At this point, you'll have to consider different solutions. Back to the Data Clump code smell:

If you always see the same data hanging around together, maybe it belongs together. Consider rolling the related data up into a larger class.

Coding Horror - Code Smells

The suggested solution is to combine that data into a new class. This class often ends up being called...

2. The Context class

It gets instantiated once, after the facts are known, and gets passed along from method to method so you'll always know where to look for the current user, company, etc.

As a solution, the Context class may remind you of the concept of a value object (from Domain-Driven Design), to combine values that naturally belong together into a conceptual whole. However, there are several things about a Context class that start to smell very quickly.

Entities in the Context

The first thing that ends up in the Context class is the User object, representing the authenticated user. Unfortunately, this user is often modeled as an entity. So now the Context class will contain a complete entity. This way, we expose quite a large API of not only query methods, but also command methods, which would make it possible to modify the state of the User entity that gets passed around. We don't want this kind of Indecent Exposure. Now every class that retrieves the Context, also implicitly knows about the API of User and sooner or later it will start depending on it. This kind of exposure needs to be prevented at all cost, because it basically couples everything to everything.

By

Truncated by Planet PHP, read more at the original (another 4553 bytes)

Link
Paul M. JonesAtlas.ORM “Cassini” (v3) Early-Access Alpha Release (23.4.2018, 14:02 UTC)

For those of you who don’t know, Atlas is an ORM for your persistence model, not your domain model. Atlas 1 “Albers” (for PHP 5.6) was released in April 2017. Atlas 2 “Boggs” (for PHP 7.1) came out in October 2017.

And now, in April 2018, we have an early-access release of Atlas 3 “Cassini”, the product of several lessons from a couple of years of use.

Architecture and Composition

One big architectural change is that Atlas 3 no longer uses the older Aura packages for SQL connections and queries; instead, Atlas has adopted these packages as its own, and upgraded them for PHP 7.1 using strict typing and nullable returns. Another big architectural change is that the table data gateway and data mapper implementations are now available as packages in their own right.

The end result is a mini-framework built from a stack of packages, where any “lower” package can be used indepdendently of the the ones “above” it. The package hierarchy, from bottom to top, looks like this:

  • Atlas.Pdo: Descended from Aura.Sql, this provides a database Connection object and a ConnectionLocator. If all you need is convenience wrapper around PDO with fetch and yield methods, this is the package for you.

  • Atlas.Query: Descended from Aura.SqlQuery, this is a query builder that wraps an Atlas.Pdo Connection. If you just want to build and perform SQL queries using an object-oriented approach, the Atlas query objects can handle that.

  • Atlas.Table: Extracted from Atlas 2, this is a table data gateway implementation that uses Atlas.Query under the hood. If you don’t need a full data mapper system and only want to interact with individual tables and their row objects, this will do the trick.

  • Atlas.Mapper: Also extracted from Atlas 2, this is a data mapper implementation that models the relationships between tables. It allows you to build Record and RecordSet objects whose Row objects map naturally back to Table objects; you can write them back to the database one by one, or persist an entire Record graph back to the database in one go.

  • Atlas.Orm: Finally, at the top of the hierarchy, the overarching ORM package provides a convenience wrapper around the Mapper system, and provides several strategies for transaction management.

There are also two “side” packages:

  • Atlas.Info: Descended from Aura.SqlSchema, this inspects the database to get information about tables, columns, and sequences.

  • Atlas.Cli: This command-line interface package uses Atlas.Info to examine the database, then create skeleton classes for your persistence model from the database tables.

Separation, Completion, and Hierarchy

One goal for Atlas 3 was to split up the Table and Mapper subsystems into their own packages, so they could be used in place of the full transactional ORM if needed. Along with that, I wanted better IDE autocompletion, especially at the query-building level, particularly in support of different SQL dialects (e.g., PostgreSQL has a RETURNING clause, but nothing else does).

The first idea long these lines was to have parallel packages, one for each SQL driver: Atlas.Query-Mysql, Atlas.Query-Pgsql, Atlas.Query-Sqlite, etc. However, I shortly realized that typehinting at higher levels would have been a problem. If a generic Table class returns a TableSelect that extends a generic Select object, then providing a driver-speific MysqlSelect had to return a MysqlTableSelect for a MysqlTable. That in turn would have meant parallel packages for each driver all the way up the hierarchy: Table, Mapper, and Orm. Generics at the language level might have solved this, but PHP doesn’t have them, so that idea was out.

Then the idea was to have a single

Truncated by Planet PHP, read more at the original (another 11901 bytes)

Link
Stefan KoopmanschapSurface Book 2 For Development (22.4.2018, 14:12 UTC)

Over the past month and a half I've been trying to fully switch to a new work machine. Instead of my trusty MacBook Pro, I've mostly been working with a Microsoft Surface Book 2. Here's my lessons of this period.

Context

Let's start with a bit of context. Over the past 10+ years I've been using Apple laptops exclusively for work. It started when I started my job at Ibuildings and I got the opportunity to choose between a PC laptop and a Mac. I'd heard good things about Mac so I decided to give it a try. When I came home from work after that first day I told my wife "If I ever leave Ibuildings, I'm going to have to buy myself a Mac". I was impressed. The ease of use, the intuitiveness and the user experience were all so nice. So much better than Linux, which I'd been using in the years before. Or even Windows, which I'd been using until Windows ME came out and forced me into the stable hands of Linux.

I've been a full-on Apple fanboi ever since. Until a couple of years ago, there was nothing Apple did that would stop me from using their stuff. The platforms they built were stable and because they control both hardware and software, everything was tuned to each other.

But in the past couple of years I've been a bit more unhappy with Apple's decisions. Their platforms are becoming less stable, less reliable, and more than once I've felt their decisions were based mostly on economics, on money, and not on usability which had been their focus until then (or at least that's how it felt).

When Microsoft first announced the Surface (and later the Surface Book), I was intrigued. A tablet that is also a laptop. Everything in a single device. Powerful enough to work on, yet also easy to bring to a meeting and not have a laptop screen in front of your face. When the first rumours started that Apple was going to introduce an iPad Pro, I sincerely hoped it would be similar: An iPad device running macOS. That would be great!

The announcement of the iPad Pro was a disappointment to me. With it running iOS there was no chance I could do serious development on it. The specs were also disappointing. This was not an option anymore.

My MacBook has been slowly becoming a device that was frustrating me instead of a device that I felt happy to spend 8-12 hours a day on. So I've been looking around. In February I was visiting a Dutch Mediamarkt store to get some stuff, I noticed a Surface Book, and I started playing with it. A Mediamarkt employee came by to give me a demo of some of its features and I was pretty much convinced.

Borrowing a Surface Book

Switching platforms is a big decision however. I've got so much time, effort and money invested in the Apple platform that I'd (at least partially) lose when I switch to Windows, that I really wanted to test-drive the Surface Book before actually making a decision. So I started looking for companies that have Surface Book rental devices. I found several companies but they were all aimed at renting the device for a couple of days, for events and such. If I were to rent it for 2-3 months (which I'd need to really test-drive the device) I could just buy the device. The prices were much higher than anticipated, and long-term rental did not really seem to be a thing. So I reached out to Gerard, one of my contacts inside Microsoft Netherlands, and asked him if he knew of companies that do this. Gerard introduced me to Paul from Microsoft Netherlands, and Paul offered to lend me a device. For free. The only catch was that I'd share my experiences. Given that I was planning on sharing my experiences anyway if I'd find a rental device, I quickly agreed. This was a great opportunity!

Waiting is hard

After agreeing to lend the device, the waiting is probably the hardest. It felt just like that moment when you ordered your new MacBook Pro on the Apple website and then have to wait for it to be delivered. A shiny new device is coming your way. Luckily, the wait wasn't all that long, because a week later a parcel was delivered. Ooooohhh.

The first time

I unpacked the Surface Book 2 and booted it up. It definitely felt like I was unpacking and booting up a new MacBook in terms of experience. A nice wizard helped me set up the basics of the computer like the user, the wifi etc. The whole setup could also be done using speech with the Cortana software, but as fancy as it may seem, I somehow dislike microphones constantly listening to what I'm doing and saying, I quickly turned that off. All in all the initial setup was done in a couple of steps and a couple of minutes.

Now, to set this up as a development workstation I need some software. The initial list of things I thought I needed was:

  • Firefox
  • Docker
  • Git
  • PHPSt

Truncated by Planet PHP, read more at the original (another 11555 bytes)

Link
Nomad PHPBetter and Faster: TDD-ing a Ride-Hailing Application w/ PHPUnit, Symfony and Doctrine (21.4.2018, 16:11 UTC)

July - US
Presented By

Chris Holland
July 19, 2018
20:00 CDT

The post Better and Faster: TDD-ing a Ride-Hailing Application w/ PHPUnit, Symfony and Doctrine appeared first on Nomad PHP.

Link
Christian WeiskeGrav CMS: previous is next (20.4.2018, 19:22 UTC)

I'm using Grav CMS for a new project and am building my own theme for it.

When adding links to the previous and next blog posts, I noticed something strange: When I am on the first blog post (PageCollection::isFirst($page.path) == true), $collection.nextSibling() is empty.

Also, when I'm on the last page, $collection.prevSibling() is empty.

It turns out that those two methods do the opposite as I thought:

Post number prevSibling nextSibling
5 6 4

Other people were also confused, but Grav is used too much now that changing the behavior would break many many pages.

Link
Stefan KoopmanschapMental Health First Aid (20.4.2018, 17:25 UTC)

It was TrueNorthPHP conference in 2013 that I first saw Ed Finkler speak. It was his Open Sourcing Mental Illness talk. This talk has meant so much to me on so many levels, but one of the things I took away from that talk was the existence of Mental Health First Aid. Mental Health First Aid is basically the mental illness counterpart of regular first aid. It gives you basic information about how to handle when you encounter someone with a mental illess, especially in crisis situations. This includes approaching the person, what to do and not to do when talking to them, and how to make sure people get the right help, including a hand-off to (mental health) medical professionals.

Fast forward a few years to about two years ago. Doing the MHFA course was still on my wishlist, but there still was no option in The Netherlands to do so. Just as I was looking into options of travelling to the UK for the course, I found out that one of the Dutch regional institutes for mental health (GGZ Eindhoven) was working on bringing MHFA to The Netherlands. I contacted them to see if I could be part of the trial group they were doing, but never heard back. I put my focus on some other things I wanted to do and put MHFA on hold again.

Earlier this year I decided to add a bit more structure to the training programs within my company Ingewikkeld to enable my employees a bit better to increase their knowledge and skills, but decided I definitely also should use this new structure for my own. I looked up the MHFA options in The Netherlands and found out that there were now many options for taking the course, including in my favorite city Utrecht. I signed up for the course, and over the past 4 weeks have had 4 3-hour sessions.

The goal

In the first session we were asked for our goals. My main goal was to understand more about mental illness and get handholds on how to act in case of talking to someone with a mental illness, be it a crisis situation or not. And over all sessions, this was indeed what happened. I learned a lot about depression, fear, psychosis, substance abuse and crisis such as suicidal tendencies, self-harm, panic attacks, aggression and more. About what it was and about how to handle such situations. As we were asked at the end of todays session to summarize our experience over the past 4 weeks, my answer was:

Goals achieved

It became personal

As I've got issues with depression myself, especially the first two sessions caused a lot of self-reflection as I learned more about what happens with depression. There was a lot of familiar situations in the course material, and it was very interesting to hear more background information on those situations. Our group was a very nice and diverse group, with people with lots of different backgrounds, which gave me a lot of insight into how different people experience different situations.

As the course progressed though, other mental illnesses were handled that I had no experience with. This was definitely eye opening. I now have so much more understanding of what can happen in peoples heads, and I hope that helps me in a more empathetic response to such situations, if I ever encounter them.

Why I recommend more people taking this course

Isn't it a bit weird that we find it very normal to take regular first aid courses, but we try to stay away of anything related to mental health? Somehow there is still a taboo on mental health related problems. And yet (at least here in The Netherlands) there are news items on a more regular basis about people with mental illness crises. It seems like this is a growing problem, yet nobody wants to know how to handle in such situations?

Taking this course will make you understand more clearly what happens when someone has a mental health issue. How it affects their life, and how to handle when you encounter a situation involving a mental health issue. It will help you be more empathetic, not just in crisis situations, but also when simply talking to someone with a mental illness. I also think it will look good on your resume for potential employers. It is still a rare skill to know how to handle in this situations, and employers will benefit from you having this knowledge. So Check which local organization offers the course and register. I'm pretty sure you won't regret it.

Link
Nomad PHPThe PHP Developer Stack for Building Chatbots (20.4.2018, 04:05 UTC)

July - EU
Presented By

Ashley Hutson
July 19, 2018
20:00 CEST

The post The PHP Developer Stack for Building Chatbots appeared first on Nomad PHP.

Link
blog.phpdevPreparing for Pentesting (@ Longhorn PHP 2018) (17.4.2018, 13:57 UTC)

At this year’s Longhorn PHP conference I’ll be presenting two talks: an updated version of my “Securing Legacy Applications” session and something new and a bit different for a conference primarily aimed at development topics. I’ll be giving a tutorial on the first day (April 19th) about penetration testing. For those not familiar with the topic, penetration testing is a common security practice where you make attempts to locate the flaws in an application, usually without knowledge of the code running underneath.

For a group that’s primarily focused on “building” rather than “breaking” it might be a bit of a mind shift but I hope to at least provide my attendees with the basic concepts and tools to try it out on their own applications. There have been several sessions recently that focus on securing the code but that’s only half of the equation.

So, if you’re going to be attending my tutorial, here are a few things that can help you hit the ground running when we start. There’ll be a brief introduction to some of the basic application security concepts but we’re not going to dive too deep into those. Instead, you’ll be attacking a series of challenges I’ve created to teach the basics.

Here’s how to prepare:

– Go over the OWASP Top 10 to be familiar with the common vulnerability types (hint: several are in the challenges)
– Grab the Community Edition of the PortSwigger Burp Suite tool. We’ll be using this to help solve some of the challenges
– Check out the PHP security cheat sheet, some of the top PHP security issues and this guide to building secure PHP applications

Don’t worry if you’re not a PHP security pro – that kind of knowledge isn’t required here. The topics we’ll cover are more from the security testing side and, as an added bonus can be used on any kind of web-based application – not just PHP ones!

I hope to see you on Thursday morning – we’re going to have some fun!

Link
Matthias NobackCombing legacy code string by string (17.4.2018, 07:00 UTC)

I find it very curious that legacy (PHP) code often has the following characteristics:

  1. Classes with the name of a central domain concept have grown too large.
  2. Methods in these classes have become very generic.

Classes grow too large

I think the following happened:

The original developers tried to capture the domain logic in these classes. They implemented it based on what they knew at the time. Other developers, who worked on the code later, had to implement new features, or modify domain logic, because, well, things change. Also, because we need more things.

For instance, when a developer comes in and has to modify some of the logic related to "sales orders", they will look for classes with that name in it, like the SalesOrder entity, the SalesOrders controller, service, manager, helper, table gateway, repository, etc. Before considering the option to add more classes, most developers will first consider adding a method to one of the existing classes. Especially if the code of this class hasn't been tested.

Since this is legacy code we're talking about, it's very likely that the code hasn't been tested (if it was tested, would it be legacy code?). So most likely they will end up modifying the existing class, instead of thinking about what they really need: an object that does exactly what they need.

This is how legacy classes end up being so very large. We add more and more to it (since the new functionality is "related" to the existing code after all). It explains why legacy code has the first characteristic I mentioned at the beginning of this post ("Classes with the name of a central domain concept have grown too large."). The second characteristic still deserves some explanation though ("Methods in these classes have become very generic.").

Methods become very generic

Once we decide to take an existing class and modify it, we first analyze the code that's in the class: the method, the properties; we've all learned to take the D.R.Y. ("Don't repeat yourself") principle into account, so we're scared of redoing anything that was already done. While scanning the existing code, we may find several of the ingredients we need for the task at hand. Well, the ingredients are often somewhat useful, but not entirely what we need.

This is a crucial moment, a moment we've often experienced, a moment we've always appreciated. However, it's a moment we should fear, a moment we should fight (pardon the dramatic tone). It's the moment we change a method to fit in with our current use case.

How is this usually achieved? Most often we use one of the following tactics:

  1. Add an extra parameter (a.k.a. a parameter flag), using which we can influence the behavior of the method. Of course we provide a sensible default parameter, for backwards compatibility:

    // The original method:
    public function findAllSalesOrders()
    {
        // some complicated SQL, *almost* what we need
    }
    
    // The modified method, with a parameter flag
    public function findAllSalesOrders($excludeFinishedOrders = false)
    {
        // ...
    }
    
    
  2. Call another method first (a.k.a. decoration). This method may do some of the work, and maybe let the original method do its original work afterwards.

    // The original method:
    public function findAllSalesOrders()
    {
        // some complicated SQL, *almost* what we need
    }
    
    // The new method, which decorates the original one:
    public function findOpenSalesOrders()
    {
        // call the original method
        $salesOrders = $this->findAllSalesOrders();
    
        return array_filter($salesOrders, function(SalesOrder $order) {
            return $order->isOpen();
        };
    }
    
    

Sometimes we even combine the two, making one method more generic, and calling it from a more specific one:

// The original method:
public function findAllSalesOrders()
{
    // some complicated SQL, *almost* what we need
}

// The modified method:
public function findSpecificSalesOrders(array $statuses = [])
{
    // some complicated SQL, can do anything we need
}

// The new method, which decorates the modified original one
public function findOpenSalesOrders()
{
    return $this->findSpecificSalesOrders([SalesOrder::STATUS_OPEN]);
}

Over time, the original methods become more generic. That is, they can be used in many different scenarios. At the same time, the classes containing these methods keep growing. Every time we need a slightly different method, we add it, and use one of the tactics described. Slowly the class becomes too large to remain manageable (see

Truncated by Planet PHP, read more at the original (another 3906 bytes)

Link
Matthias NobackExceptions and talking back to the user (10.4.2018, 09:12 UTC)

Exceptions - for exceptional situations?

From the Domain-Driven Design movement we've learned to go somewhat back to the roots of object-oriented design. Designing domain objects is all about offering meaningful behavior and insights through a carefully designed API. We know now that domain objects with setters for every attribute will allow for the objects to be in an inconsistent state. By removing setters and replacing them with methods which only modify the object's state in valid ways, we can protect an object from violating domain invariants.

This style of modeling domain aggregates (entities and value objects) results in methods that modify state, but only after checking if the change is allowed and makes sense, given the rules dictated by actual domain knowledge. In terms of code, these methods may make some simple assertions about the arguments passed to it: the number of things, the range of a number, the format of a string. When anything is wrong about a provided argument, the domain object simply throws an exception. If everything is okay, the changes will be accepted by modifying any attribute involved.

So exceptions in your (object-oriented) domain model are not merely meant to signal an exceptional situation. They can be used to prevent invalid or unsupported usage of an object. By offering well-named methods (with sensible parameters) for changing the object's state, and by being very precise about throwing exceptions when invalid use is imminent, you make your domain objects usable in only one way: the way that makes sense. This is the exact opposite of how your domain objects end up looking if you generate getters and setters for every attribute.

Using exceptions for validation

You might say that, given that the object protects itself from ending up in an in valid state, it basically validates itself. However, it won't be good for our application's usability if we'd use these domain-level exceptions as messages to the user. The thing is:

  • Exceptions get thrown ad hoc, whenever something threatens the consistency of the domain object. You can only catch one of these exceptions and turn it into an error message for the user. If the user tries to fix the issue by making a change, sending the form again, and they manage to get past this exception, there may be another exception just around the corner. This will be very frustrating for the user, as it will feel like trial-and-error.
public function processDelivery(int $quantity, string $batchNumber): void {
    if ($quantity <= 0) {
        /*
         * If the user triggers this exception, they have to resubmit,
         * which may trigger another exception further down the line...
         */
        throw new InvalidArgument(
            'Quantity should be more than 0.'
        );
    }

    if (empty($batchNumber) {
        throw new InvalidArgument(
            'This delivery requires a batch number.'
        );
    }

    // ...
}

  • Domain exceptions aren't always about validating the data the user provides. They often signal that something is about to happen that can't logically happen, like a state change that isn't allowed or conceptually possible. E.g. once an order has been cancelled, it shouldn't be possible to change its delivery address, because that makes no sense:
public function changeDeliveryAddress(...): void {
    if ($this->wasCancelled) {
        throw new InvalidState('You cannot change ...');
    }

    // ...
}

  • Exception messages may contain more information than you'd like to share with the user.
  • Validation errors often require internationalization (i18n). They need localization in the sense that numbers should be formatted according to the user's locale. Of course, they often need translation too. Exceptions aren't naturally usable for translation, because they contain special values hard-coded into their messages.
throw new InvalidArgument(
    'Product 21 has a stock level of 100, but this delivery has a quantity of 200.'
);

Translation needs a template message which will be translated, after which the variables it contains will be replaced by their real values.

So exceptions thrown to protect domain invariants are not validation messages all by themselves. They are there to prevent bad things from happening to your domain objects. They are not useful if what you want is talk back to the user. If you're looking for a dialogue with the user about what they're trying to achieve, you should be having it in a layer of the application that's closer to the user.

There are several options there

Truncated by Planet PHP, read more at the original (another 6127 bytes)

Link
LinksRSS 0.92   RDF 1.
Atom Feed   100% Popoon
PHP5 powered   PEAR
ButtonsPlanet PHP   Planet PHP
Planet PHP