Serverless PHP on App Engine + Cloud Firestore with Firevel
In recent decades the PHP community has gone through some major changes. First, we saw billion-dollar platforms like Facebook adopting PHP as a primary language. Then tools like the Laravel framework quickly rose in popularity as it enabled the community to quickly build modern applications. Finally, PHP 7 gave the language a bright future with performance improvements and features like type hinting.
Benefits of Serverless
Serverless apps are usually simple to set up, cheap (or free) with low traffic, and can scale up to handle high loads extremely quickly. Another benefit is that you also don’t need to worry about server administration as these new services provide fully managed infrastructure. The main reason I started to work on a serverless PHP solution was because of the time I was wasting bootstrapping every new microservice. In addition, once the service was set up it would continue to cost money from machines idling (for example staging, or services used only during office hours).
After analyzing a wide spectrum of database solutions from different providers and running some benchmark tests I found that Google BigQuery is the best serverless solution for data warehousing and Firestore is the best NoSQL database for production queries.
In both cases, the key benefits are simplicity and performance.
PHP 7’s release in Google App Engine Standard Environment was the first puzzle piece that allowed the serverless project to start. Google App Engine scales down to zero and it’s eligible for GCP’s free tier. Another bonus, it’s integrated with Google Firestore so you don’t need to set up credentials to access your database.
I wanted to make sure that I could use Laravel in this project so I developed several packages (together named Firevel) that makes the framework Google App Engine friendly. Some examples of these changes are disabling writes outside of the tmp directory, allowing a Google proxy, and setting up a Stackdriver log channel.
100% serverless Laravel Framework. Contribute to firevel/firevel development by creating an account on GitHub.
The packages included with Firevel are:
- Firestore Cache Driver
- Firestore Session Driver
- Stack driver log channel
- Laravel Firestore wrapper
By default, all exceptions appear in your App Engine Application Errors, and session data is stored inside a collection in Firestore called ‘sessions’.
If you use the Firestore Cache driver you can use all the Laravel Cache features you are used to. The cache is stored in a Firestore collection named cache.
>>> Cache::set('foo', 'bar');=> true>>> Cache::get('foo');=> "bar"
Firestore Client can be used for direct Firestore calls and is accessible by Firestore facade. Authentication is handled by App Engine behind the scenes.
->set(['name' => 'Los Angeles', 'state' => 'CA']);
Eloquent on Firestore
If you ever worked with Laravel before you can probably agree that code is very extension friendly. There are plenty of ways to build custom drivers, extensions, plugins etc. However, I don’t think I can say the same about the heart of Laravel — the Eloquent ORM. Eloquent is one of the main reasons Laravel is so successful. It’s a beautiful and simple ActiveRecord implementation designed to work with SQL databases, but it wasn’t designed with NoSQL in mind. So I built Firequent which is the Eloquent replacement for Firevel and it’s currently in beta. I managed to reach general functionality and support for methods like
limit(), but it’s not yet ready to work with relationships or any advanced queries.
You can create a Firequent model simply by extending
Firevel\Firequent\Model. In the Firestore NoSQL world, you don't need database schemas so instead of creating migrations, you can use mass assignments.
<?phpnamespace App;use Firevel\Firequent\Model;class Post extends Model
* The attributes that are mass assignable.
* @var array
public $fillable = ['name', 'description'];}
You also assign attributes on the fly directly inside the model:
$post = Post::make(['name' => 'Foo', 'description' => 'Bar']);
$post->public = true;
Why this is awesome?
The coolest part of Firevel is the simple setup. If you have the gcloud CLI installed on your machine, you can set up an entire app with
composer create-project firevel/firevel and then deploy it with a
gcloud app deploy command. Using this you can build a scalable web app in mere minutes. It’s also a great tool for building microservices with integrated Firebase Auth and the simple deployment lets you build a new microservice without all the painful infrastructure setup.
If your code is limited to a simple CRUD application and your index queries are just filtering by values you might build your app and not even notice any difference from the standard Laravel experience. But with more advanced use cases you can’t simply replace MySQL with NoSQL unless you update your approach to code structure.
Firestore offers us great scalability, flexibility, and simplicity, but everything comes with a cost so keep in mind that:
- It’s great for heavy reads but not so good for heavy updates. You need to keep that in your mind while working with caching. At the time of writing this article, you should not update an individual document more than once per second.
- Search queries are limited. The most noticeable limitations are the inability to use “or” operators, and searching that’s limited to “query by full match” (no “row LIKE %”). If you need full-text search I recommend Algolia (compatible with Firevel/Laravel Scout). To learn more about Cloud Firestore querying, I recommend watching this video.
Firevel is a 100% serverless framework. It currently has limitations and requires more production case studies before it becomes mature. But I’ve found it to be a joy to work with and can save you a lot of time.
To me — the possibility of running apps at scale, entirely in PHP, without expensive to manage servers, is like finding a unicorn.