PHP & Web Development Blogs

Search Results For: simple
Showing 1 to 5 of 20 blog articles.
1721 views · 1 months ago

![Ideas to help your PHP dev team grow their skills](https:/ /cdn.filestackcontent.com/LcqSW9KZSZarYYZWaQVH)

> Your biggest asset is also your biggest risk... your developers

Your business thrives because of the incredible work and innovation of your developers. With simple keystrokes your developers can completely transform your business, add new features, and drive new sales.

But those same keystrokes can take down production, create security back doors, and put your business at risk. That's why it's more important than ever for your team members to be up to speed with the latest technology, especially around performance and security.

Of course, some things are easier said than done - after all everyone is super busy these days. So how can you help keep your team members learning, and putting your business first in the process?

## Conference Parties

There's nothing better than attending a [PHP or programming conference](https:/ /www.php.net/conferences/) in person - the chance to meet speakers face to face, to network, the knowledge, and the hallway track. However, many companies aren't able to afford multiple (or even one) conference for their developers - especially ones that require airfare and hotel.

However, that doesn't mean you shouldn't still participate in these conferences. The good news is that roughly once a quarter [Nomad PHP](/live) streams talks from a conference right to your computer. This means that your team members can all participate in a multi-day conference from the comfort of your office (or their home) - and you can provide this for your team for [less than the cost](/teams) of a single conference ticket!

Make the conference party even more special by providing lunch during the lunch break, bringing in party gifts, having give-aways during the conference, and planning activities during longer breaks for your team.

Since many conferences take place on Friday, not only are you providing invaluable training and an incredible work benefit, but ending the week on a super positive note that your team members will appreciate (and your risk assessment teams will greatly appreciate as new security practices and compliance practices are put into place).

## Monthly Lunch and Learns

Every month Nomad PHP offers [live virtual talks](/live) by the industry's top experts. With talks at 11am Pacific, and 6pm Pacific it's a perfect time to grab a conference room and order a couple pizzas for lunch (or if Eastern, grab some snacks and maybe a beer) and play the monthly meeting on the large screen.

Your team members will have the opportunity to take notes, discuss with each other, and perhaps most importantly ask the speaker real-world questions that directly impact your business, providing tangible solutions to the problems they are facing.

And since every Nomad PHP Pro meeting [is recorded](/videos), your team members can refer back to the video at any time, watching sections relevant to them or digging in for more information.

## Developer Book Club

Encourage your team members to share what they're learning with others, and help build each other up. Not only are you helping grow skills and ensure your team is following the latest best practices, but you're also fostering a mentor-mentality within your team - where each team member feels invested in the growth of other members.

With Nomad PHP you receive a new issue of [php[architect]](/books) each month and have several [additional books](/books) available to read on demand - providing the latest updates and an invaluable resource to help your book club get started.

## Developer Movie Nights

Sometimes we all just want to get away, grab some popcorn, and watch a movie. Similar to lunch and learns, give your developers a night or two where they can get together and watch one of the [250+ training videos](/videos) available on Nomad PHP. You can even make it a movie marathon!

Whether it's pizza, popcorn, sodas, beers - your team members will have the chance to kick back, relax a bit, build team camaraderie, and learn valuable skills to help your business succeed. Essentially, turning a training day into a fun team-bonding activity.

## Learning Path Challenges

Every company has challenges, and areas they need their team members to master. Whether it's [DevOps](/videos/devops) and [containerization](/videos/containerization), [security](/videos/security), [performance](/videos/performance), [management](/search/videos/soft-skills?search_query=manage), [modernization](/videos/upgrading), or [soft skills](/videos/soft-skills) - work with your team to determine what skills will help them succeed and work with your team members to put together video learning paths.

Your team members can watch through these [videos on-demand](/videos), go back and replay to refresh their knowledge, and work their way towards mastery in the subjects that will help your company succeed.

## Certification

Show that you are invested in your developers by helping them earn [Professional Certification](/certification). These certifications demonstrate that your team members have a fundamental grasp of the technology they are working with and understand when and how to use this technology.

With [free certification exams](/certification) included with Nomad PHP - you no longer have to worry about failed exams or expensive test credits. Your team members can take the exams at their own pace, discover the areas they need to improve, and take the exam again when they are ready. After all, shouldn't the goal of certification be to help your developers learn these skills and prove their expertise?

You can go even further with certifications by having a special [company award](https:/ /amzn.to/359HSLd), [framing their certificate](https:/ /amzn.to/2SnEOpV), or calling out newly certified developers at team meetings or all-hands.

## Learning Incentives/ Rewards

Of course there are even more ways you can help your developers learn new skills, grow their careers, and build loyalty within your company. With Nomad PHP there are numerous ways for your team members to grow their skills, and numerous ways you can reward/ incentivize them - from rewards for the most active learner, to setting goals for learning new skills, to obtaining certifications, to attending streams, to watching videos on-demand. All of these are included with our [Professional Nomad PHP Team subscriptions](/teams).

### Want to learn more about getting a Nomad Team Subscription for your developers? Give us a call (844) CODE-PHP

**Have more ideas on how to help your developers grow their skills or help employers make education more accessible? Please leave your ideas in the comments below!**

963 views · 1 months ago

![](https:/ /cdn.filestackcontent.com/Ve0Q3jp4S4KuL2N4Mub7)

#### Welcome back! If you’re new to this series have a look at [Part 1 here](https:/ /nomadphp.com/blog/1925/code-with-me-challenge-custom-cms-development-with-php-and-mysql)

Today’s focus is on templating, the aesthetic that will make or break your web application.

Having a clean design with well defined CSS that’s responsive and user friendly goes a long way.

Developers often stick to their lane but delving into templating will bode in your favor, you can indeed

create a functional and launch-worthy application all on your own!

Let’s jump into it!

## Structured structure

Everything you tackle should be found with ease down the line. Therefore careful planning is fundamental to the success and sustainability of your project. You’ll also find that clearly defining your work lends itself to more productivity overall as you spend less that explaining your work during a handover / looking for a specific piece of code or resource. You’ll probably end up spending more time on actual work.

Finding your own unique pattern with file structure and CSS identifiers will also work in your favor as something unique to your process will most likely be easier to remember and form a tactile relationship with.

Our project’s current structure looks like this:

![](https:/ /cdn.filestackcontent.com/yvGBC8qbRMmsHklihrq2)

>If you need to backtrack, [Part 1](https:/ /nomadphp.com/blog/1925/code-with-me-challenge-custom-cms-development-with-php-and-mysql) is a great place to start!

In part 1, we created our index.php which displays info from our database.

Let’s take this a step further and create a header and a footer for our index.php

Create a file called header.php and save this to your includes folder.

Next, create a file called footer.php and save this to your includes folder.

Your file structure should now look like this.

![](https:/ /cdn.filestackcontent.com/8xTDBQkrTtSoZHC1aW5o)

### A header above all the rest

The header file will be a file we reuse throughout your web application. This file will contain important information that’s vital to the functionality and aesthetic of your website.

The type of info you’ll expect to see in a header.php file:

Script includes

Such as JQuery and important libraries

CSS includes

CSS files loaded from internal or external sources

Meta information

Contains important information that’s readable by search engines.

The basic structure of the beginning of your app, including your menu, and your logo.

For now, how header is going to have a basic layout.

Let’s get our HTML on!

```

<html>

<head>

<title>My Awesome CMS – Page Title</title>

</head>

<body>

```

### A footer that sets the bar

Create a file called footer.php and save it to your includes folder (yourcms/includes/footer.php).

Add this code to your new file.

```

</body>

</html>

```

### Next, let’s focus on the gravy… The CSS

CSS, when written beautifully, can truly set you apart.

You can tell your web application to load various styles to specific elements by defining unique identifiers.

Styles that are only used once are denoted with a # (a CSS “ID”) whereas styles that are reused multiple times are denoted with a . (a CSS “class”)

The best way to delve into the realm of CSS is to learn by experience.

### Let’s create!

First, we need to create and load our CSS file. Remember our nifty new pal header.php? This created a convenient way to load our CSS file!

Add the following code to your header.php just above the `</head>` tag.

```

<link href=”../assets/css/style.css” type=”text/css” rel=”stylesheet”/>

```

The ../ in the link to our stylesheet means we have to leave the current directory (the directory that header.php is in) and look for the assets/css/ directories.

Go ahead and create the css folder under your assets folder.

Next we’re going to create some simple CSS to test things out.

### It’s time to add some style!

We are going to create two divs.

A div is a divider / section in HTML.

Add this to your index.php (located in your CMS’ root folder) above the `<?php` tag.

```

<div id="myfirstid"></div>

<div class="myfirstclass"></div>

<div class="myfirstclass"></div>

<div class="myfirstclass"></div>

<div class="myfirstclass"></div>

<div class="myfirstclass"></div>

```

Then, create a CSS file

Add this:

```

#myfirstid{

Background:lightblue;

Font-family:Arial;

Font-size:44px;

Font-weight: Bold;

}

.myfirstclass{

Font-size:15px;

Color: darkblue;

}

```

Save your newly created CSS to assets/css/ as style.css.

### Pulling it all together, let’s see what we can do!

Let’s apply what we just learned to our index.php. But first, we should add our header.php and footer.php files.

### Including everyone

Add this to the top of your index.php file:

```

include(‘includes/header.php’);

```

Remove the `<divs>` we used for practice earlier, we have something better in store!

Add this to the bottom of your index.php:

```

include(‘includes/footer.php’);

```

Next, let’s modify our code so we can add some style to the data we retrieve from our database.

Modify the following line:

```

foreach($getmydata as $mydata){ echo "Title: "; echo $mydata['title']; echo "<br/>"; echo "Content: "; echo $mydata['content']; echo "<br/>"; echo "Author: "; echo $mydata['author']; echo "<br/>"; echo "<br/>";

```

as follows:

```

?>

<div id=”myfirstid”>

<?php

foreach($getmydata as $mydata){

echo "<div class=”myfirstclass”>Title: ";

echo $mydata['title'];

echo "<br/>";

echo "Content: ";

echo $mydata['content'];

echo "<br/>";

echo "Author: ";

echo $mydata['author'];

echo "</div><br/><br/>";

}?>

</div>

<?php

```

Your full index.php should now look like this:

```

<?php

include('includes/header.php');

include('includes/conn.php');

if ($letsconnect -> connect_errno) { echo "Error " . $letsconnect -> connect_error;

}else{

$getmydata=$letsconnect -> query("SELECT * FROM content");

?>

<div id="myfirstid">

<?php

foreach($getmydata as $mydata){

echo "<div class=”myfirstclass”>Title: ";

echo $mydata['title'];

echo "<br/>";

echo "Content: ";

echo $mydata['content'];

echo "<br/>";

echo "Author: ";

echo $mydata['author'];

echo "</div><br/><br/>";

}

?>

</div>

<?php

}

$letsconnect -> close();

include('includes/footer.php');

?>

```

## Go ahead, test it out!

There’s a lot to unpack and I will break things down a little more during our next tutorial!

## Challenge

Study the final index.php and try to form a few theories about why closing a php tag is necessary before adding raw html.

## Next Up: #CodeWithMe Part 4: Building A Good Base

4211 views · 1 years ago

![Why Cloudways is the Perfect Managed Hosting for PHP Applications](https://images.ctfassets.net/vzl5fkwyme3u/3VLCUBagZPfSLyxyt1AvvP/89e3b904a450454545eb885e2e0e76b4/cloudways.jpg?w=1000)

#### The following is a sponsored blogpost by [Cloudways](https://www.cloudways.com/en/?id=431739)

Developing an application is not the sole thing you should bank on. You must strive to find the best hosting solution to deploy that application also. The application’s speed is dependent on the hosting provider, that is why I always advise you to go for the best hosting solution to get the ultimate app performance.

Now a days, it is a big challenge to choose any web hosting, as each hosting has its own pros and cons which you must know, before considering it finally for the deployment. I don’t recommend shared hosting for PHP/Laravel based applications, because you always get lot of server hassles like downtime, hacking, 500 errors, lousy support and other problems that are part and parcel of shared hosting.

For PHP applications, you must focus on more technical aspects like caching, configs, databases, etc. because these are essential performance points for any vanilla or framework-based PHP application. Additionally, if the app focuses on user engagement (for instance, ecommerce store), the hosting solution should be robust enough to handle spikes in traffic.

Here, I would like to introduce Cloudways [PHP server hosting](https://www.cloudways.com/en/php-cloud-hosting.php?id=431739) to you which provides easy, developer and designer friendly managed hosting platform. With Cloudways, you don't need to focus on PHP hosting, but must focus on building your application. You can easily launch cloud servers on five providers including DigitalOcean, Linode, Vultr, AWS and GCE.

### Cloudways ThunderStack

Being a developer, you must be familiar with the concept of stack - an arrangement of technologies that form the underlying hosting solution.

To provide a blazing fast speed and a glitch-free performance, Cloudways has built a PHP stack, known as ThunderStack. This stack consists of technologies that offer maximum uptime and page load speed to all PHP applications. Check out the following visual representation of ThunderStack and the constituent technologies:

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/5v08m0nwsFPv7niXjmRX0M/ca3aba8d814578baf676bd58c3933dc8/cloudways_image1.png?w=1000)

As you can see, ThunderStack comprises of a mix of static and dynamic caches with two web servers, Nginx and Apache. This combination ensures the ultimate experience for the users and visitors of your application.

### Frameworks and CMS

The strength and popularity of PHP lies in the variety of frameworks and CMS it offers to the developers. Realizing this diversity, Cloudways offers a hassle-free installation of major PHP frameworks including Symfony, Laravel, CakePHP, Zend, and Codeigniter. Similarly, popular CMS such as WordPress, Bolt, Craft, October, Couch, and Coaster CMS - you can install these with the 1-click option. The best part is that if you have a framework or CMS that is not on the list, you can easily install it through Composer.

### 1-Click PHP Server & Application Installation

Setting up a stack on an unmanaged VPS could take an entire day!

When you opt for Cloudways managed cloud hosting, the entire process of setting up the server, installation of core PHP files and then the setup of the required framework is over in a matter of minutes.

Just [sign up at Cloudways](https://www.cloudways.com/en/?id=431739), choose your desired cloud provider, and select the PHP stack application.

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/2Dp11Kg9FOkHkFbjUub7Tj/f0c4c125a8c683c51a548fdd287c8330/cloudways_image2.png?w=1000)

As you can see, your LAMP stack is ready for business in minutes.

Many PHP applications fail because essential services are either turned off or not set up properly. Cloudways offers a centralized location where you can view and set the status of all essential services such as:

* Apache

* Elasticsearch

* Memcached

* MySQL

* PHP-FPM

* Nginx

* New Relic

* Redis

* Varnish

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/1zvZI0b7zuPbBacp4ALAax/a5150babfbe2972c96beca3ac71395f2/cloudways_image3.png?w=1000)

Similarly, you can manage SMTP add-ons without any fuss.

### Staging Environment

With Cloudways, you can test your web applications for possible bugs and errors before taking it live.

Using the staging feature, developers can first deploy their web sites on test domains where they can analyze the applications performance and potential problems. This helps site administrators to fix those issues timely and view the application performance in real-time.

A default sub domain comes pre-installed with the newly launched application, making it easy for the administrators to test the applications on those testing subdomains. Overall, it's a great feature which helps developers know about the possible errors that may arise during the live deployment.

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/5gTrIsw9KjhocjtZMWVePB/a8274899ee55d7068329c551af362fdf/cloudways_image4.png?w=1000)

### Pre-Installed Composer & Git

PHP development requires working with external libraries and packages. Suppose you are working with Laravel and you need to install an external package. Since Composer has become the standard way of installing packages, it comes preinstalled on the Cloudways platform. Just launch the application and start using Composer in your project.

Similarly, if you are familiar with Git and maintain your project on GitHub or BitBucket, you don’t need to worry about Git installation. Git also comes pre-configured on Cloudways. You can start running commands right after application launch.

### Cloudways MySQL Manager

When you work with databases in PHP, you need a database manager. On the Cloudways platform, you will get a custom-built MySQL manager, in which you can perform all the tasks of a typical DB manager.

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/415qced8tKK8FWEsWGPhAm/ec1947d0b21ac8cd572613d0a1fa88dc/cloudways_image5.png?w=1000)

However, if you wish to install and use another database manager like PHPMyAdmin, you can install it by following this simple guide on installing [PHPMyadmin](https://www.cloudways.com/blog/installation-phpmyadmin/?id=431739).

### Server & Application Level SSH

If you use Linux, you typically use SSH for accessing the server(s) and individual applications. A third-party developer requires application and server level access as per the requirements of the client. Cloudways offers SSH access to fit the requirements of the client and users.

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/1IpSR4TrckMFJjYQ1m5upz/030f71f106b7db97ce16de10aba2c17b/cloudways_image6.png?w=1000)

### PHP-FPM, Varnish & Cron Settings

Cloudways provides custom UI panel to set and maintain PHP-FPM and Varnish settings. Although the default configuration is already in place, you can easily change all the settings to suit your own, particular development related requirements. In Varnish settings, you can define URL that you want to exclude from caching. You can also set permissions in this panel.

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/2W8XQvGa3CZAPBwUY4sqca/8a6b041c6dc850cc2715bb19eb17a464/cloudways_image7.png?w=1000)

Cron job is a very commonly used component of PHP application development process. On Cloudways platform, you can easily set up Cron jobs in just a few clicks. Just declare the PHP script URL and the time when the script will run.

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/32fN2IkC1X3HEC2Ly685nz/6fb9607bab9beaa81bff1b7fe4061edf/cloudways_image8.png?w=1000)

### Cloudways API & Personal Assistant Bot

Cloudways provides an internal API that offers all important aspects of the server and application management. Through Cloudways API, you can easily develop, integrate, automate, and manage your servers and web apps on Cloudways Platform using the RESTful API. Check out some of the [use cases developed](https://www.cloudways.com/blog/category/use-cases/api/?id=431739) using Cloudways API. You just need your API key and email for authentication of the HTTP calls on API Playground and custom applications.

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/5Uxx5XySaV2um2AnJjvbcg/0a4e997995d6644aa90c850a41db2720/cloudways_image9.png?w=1000)

Cloudways employs a smart assistant named CloudwaysBot to notify all users about server and application level issues. CloudwaysBot sends the notifications on pre-approved channels including email, Slack and popular task management tools such as Asana and Trello.

### Run Your APIs on PHP Stack

Do you have your own API which you want to run on the PHP stack? No problem, because you can do that, too with Cloudways! You can also use REST API like [Slim](https://www.cloudways.com/blog/simple-rest-api-with-slim-micro-framework/?id=431739&utm_source=phpjabber&utm_medium=referral), [Silex](https://www.cloudways.com/blog/create-rest-api-silex/?utm_source=phpjabber&utm_medium=referral&id=431739), [Lumen](https://www.cloudways.com/blog/creating-rest-api-with-lumen/?utm_source=phpjabber&utm_medium=referral&id=431739), and others. You can use APIs to speed up performance and require fast servers with lots of resources. So, if you think that your API response time is getting slower due to the large number of requests, you can easily scale your server(s) with a click to address the situation.

### Team Collaboration

When you work on a large number of applications with multiple developers, you need to assign them on any specific application. Cloudways provides an awesome feature of team collaboration through which you can assign developers to specific application and give access to them. You can use this tool to assign one developer to multiple applications. Through team feature, you can connect the team together and work on single platform. Access can be of different type; i.e. billing, support and console. You can either give the full access or a limited one by selecting the features in Team tab.

![alt_text](https://images.ctfassets.net/vzl5fkwyme3u/3Yn7GSeHrLvSbPf42RTR2n/269328c371e80f3ac87984cf46b6e9ac/cloudways_image10.png?w=1000)

### Final Words

Managed cloud hosting ensures that you are not bothered by any hosting or server related issues. For practical purposes, this means that developers can concentrate on writing awesome code without worrying about underlying infrastructure and hosting related issues. Do [sign up](https://www.cloudways.com/en/?id=431739) and check out Cloudways for the best and the most cost-effective cloud hosting solution for your next PHP project!

3281 views · 1 years ago

![Midwest PHP and Nomad PHP Join Forces!](https://tessakriesel.com/wp-content/uploads/midwest-php.png)

### [Interested in sponsoring? Check out the prospectus](https://drive.google.com/file/d/1ZYDi9dKCI47caU9vr69dvdhH0Enm2XcM/view)

### A little history

Several years ago I had the distinct privilege of founding Midwest PHP with Jonathan Sundquist. The goal was simple, to bring an affordable PHP conference to Minnesota and the midwest region.

Midwest PHP was created for one simple reason - there weren't a lot of alternatives, especially affordable ones. At the time, your choices were ZendCon in Silicon Valley, php[tek] in Chicago, or Northeast PHP in Boston. While Northeast PHP formed the blueprint of a community conference - it still required a flight and a costly hotel in Boston. I wanted something where local attendees, college students, and those just beginning in their PHP careers could go to learn, network, and become part of the PHP community.

Shortly after Midwest PHP was formed (originally we were using the name PHPFreeze - until Sundquist told me what a horrible idea it was), Adam Culp launched Sunshine PHP which has become one of the top community focused PHP conferences (but still requires that flight and hotel in Miami). Sundquist and I knew that any reasonable developer would still prefer to attend a conference in a blizzard than enjoy the beautiful Floridian weather (ok, that might not be it, but we still understood the need that existed).

After moving to California for my new job, Jonathan Sundquist continued to run Midwest PHP as more community conferences appeared. With his efforts, and the torch being passed to Mike Willbanks, Midwest PHP celebrated it's seventh consecutive year, becoming the longest continuously running PHP conference (if you go by formed date, if you go by actual conference date Sunshine PHP beats us out by a month).

### A renewed focus

![Developers at Midwest PHP](https://pbs.twimg.com/profile_banners/735022608/1416087272/1500x500)

Because of the incredible work Jonathan and Mike have done, Midwest PHP has stood the test of time - and the peaks and valleys that come with any conference. With the shifts in the PHP community and the sad loss of several community conferences - we realized the need for Midwest PHP is more now than ever, and to meet that need we needed to reimagine the way the conference operated.

We also realized that the best way to make Midwest PHP accessible was to combine forces, creating a seamless partnership between Nomad PHP and Midwest PHP. Through this partnership we're not only able to stream the event to make it more accessible ($19.95/mo), but also expand the conference.

This year, taking place on **April 2-4, 2020 - Midwest PHP will bring together over 800 developers** both in-person and virtually! Making this year truly unique, however, and staying with our purpose of helping new developers be part of the PHP community is a **brand new, FREE, beginner track**. I'm excited to say we will be giving away 200 tickets to those wishing to attend our Beginner or Learn PHP track!!!

We will also work to keep prices as low as possible as we offer our standard PHP tracks (Everyday PHP and PHP Performance & Security) starting at $250/ person, and **a brand new enterprise track** geared at developers facing challenges at unprecedented scale starting at $450/ person.

Last but not least, it is our goal with the help of our sponsors to include the workshop day as part of your ticket price - allowing you to get one day of in-depth training, and two more full days of sessions. On top of this, we're also excited to make the Nomad PHP and Nomad JS video libraries available for Standard and Enterprise attendees, providing over 220 additional virtual sessions on demand!

### For sponsors

Sponsoring a conference is hard. We understand the challenge of gauging ROI, planning travel, and coordinating outreach. With the combined forces of Midwest PHP and Nomad PHP, we're able to offer sponsors unique plans that maximize their investment - while ensuring the funds go back into the event to create an amazing experience for our attendees.

Beyond Midwest PHP's goal to be the largest PHP conference this year - the included Nomad PHP advertising will help you reach a much larger and broader audience, allowing for follow up advertisements and consistent engagement with the PHP community.

### [Interested in sponsoring? Check out the prospectus](https://drive.google.com/file/d/1ZYDi9dKCI47caU9vr69dvdhH0Enm2XcM/view)

### Next steps

For more information, please visit the [Midwest PHP](https://midwestphp.org) website. The venue, call for papers, and additional information will all be posted there soon.

5949 views · 1 years ago

![Introduction to Gitlab CI for PHP developers](https://images.ctfassets.net/vzl5fkwyme3u/5EUoVwcn2inEG3LsNJFAYp/14e5c704d91665c0de6ffd506a283ec3/AdobeStock_90389954.png?w=1000)

As a developer, you've probably at least heard something about [CI - Continuous integration](https://en.wikipedia.org/wiki/Continuous_integration). And if you haven't - you better fix it ASAP, because that's something awesome to have on your skill list and can get extremely helpful in your everyday work. This post will focus on CI for PHP devs, and specifically, on CI implementation from [Gitlab](https://docs.gitlab.com/ee/ci/README.html). I will suppose you know the basics of [Git](https://git-scm.com/), [PHP](https://php.net/), [PHPUnit](https://phpunit.de/), [Docker](https://www.docker.com/) and unix shell. Intended audience - intermediate PHP devs.

Adding something to your workflow must serve a purpose. In this case the goal is to automate routine tasks and achieve better quality control. Even a basic PHP project IMO needs the following:

* [linter](https://en.wikipedia.org/wiki/Lint_(software)) checks (cannot merge changes that are invalid on the syntax level)

* Code style checks

* Unit and integration tests

All of those can be just run eventually, of course. But I prefer an automated CI approach even in my personal projects because it leads to a higher level of discipline, you simply can't avoid following a set of rules that you've developed. Also, it reduces a risk of releasing a bug or regression, thus improving quality.

Gitlab is as generous as giving you their CI for free, even for your private repos. At this point it is starting to look as advertising, therefore a quick comparison table for [Gitlab](https://about.gitlab.com/pricing/), Github, [Bitbucket](https://bitbucket.org/product/pricing). AFAIK, Github does not have a built-in solution, instead it is easily integrated with third parties, of which [Travis CI](https://github.com/marketplace/travis-ci/plan/MDIyOk1hcmtldHBsYWNlTGlzdGluZ1BsYW43MA==#pricing-and-setup) seems to be the most popular - I will therefore mention Travis here.

### Public repositories (OSS projects). All 3 providers have a free offer for the open-source community!

| Provider | Limits |

|---|---|

| Gitlab | 2,000 CI pipeline minutes per group per month, shared runners |

| Travis | Apparently unlimited |

| Bitbucket| 50 min/month, max 5 users, File storage <= 1Gb/month |

### Private repositories

| Provider | Price | Limits |

|---|---|---|

| Gitlab | Free | 2,000 CI pipeline minutes per group per month, shared runners |

| Travis | $69/month | Unlimited builds, 1 job at a time |

| Bitbucket| Free | 50 min/month, max 5 users, File storage <= 1Gb/month |

## Getting started

I made a small project based on Laravel framework and called it "ci-showcase". I work in Linux environment, and the commands I use in the examples, are for linux shell. They should be pretty much the same on Mac and nearly the same on Windows though.

```sh

composer create-project laravel/laravel ci-showcase

```

Next, I went to gitlab website and created a new public project: https://gitlab.com/crocodile2u/ci-showcase. Cloned the repo and copied all files and folders from the newly created project - the the new git repo. In the root folder, I placed a `.gitignore` file:

```

.idea

vendor

.env

```

Then the `.env` file:

```

APP_ENV=development

```

Then I generated the application encryption key: `php artisan key:generate`, and then I wanted to verify that the primary setup works as expected: `./vendor/bin/phpunit`, which produced the output `OK (2 tests, 2 assertions)`. Nice, time to commit this: `git commit && git push`

[At this point](https://gitlab.com/crocodile2u/ci-showcase/tree/step-1), we don't yet have any CI, let's do something about it!

### Adding .gitlab-ci.yml

Everyone going to implement CI with Gitlab, is strongly encouraged to bookmark this page: https://docs.gitlab.com/ee/ci/README.html. I will simply provide a short introduction course here plus a bit of boilerplate code to get you started easier.

First QA check that we're going to add is PHP syntax check. PHP has a built-in linter, which you can invoke like this: `php -l my-file.php`. This is what we're going to use. Because the `php -l` command doesn't support multiple files as arguments, I've written a small wrapper shell script and saved it to `ci/linter.sh`:

```sh

#!/bin/sh

files=`sh ci/get-changed-php-files.sh | xargs`

last_status=0

status=0

# Loop through changed PHP files and run php -l on each

for f in "$files" ; do message=`php -l $f` last_status="$?" if [ "$last_status" -ne "0" ]; then # Anything fails -> the whole thing fails echo "PHP Linter is not happy about $f: $message" status="$last_status" fi

done

if [ "$status" -ne "0" ]; then echo "PHP syntax validation failed!"

fi

exit $status

```

Most of the time, you don't actually want to check each and every PHP file that you have. Instead, it's better to check only those files that have been changed. The Gitlab pipeline runs on every push to the repository, and there is a way to know which PHP files have been changed. Here's a simple script, meet `ci/get-changed-php-files.sh`:

```sh

#!/bin/sh

# What's happening here?

#

# 1. We get names and statuses of files that differ in current branch from their state in origin/master.

# These come in form (multiline)

# 2. The output from git diff is filtered by unix grep utility, we only need files with names ending in .php

# 3. One more filter: filter *out* (grep -v) all lines starting with R or D.

# D means "deleted", R means "renamed"

# 4. The filtered status-name list is passed on to awk command, which is instructed to take only the 2nd part

# of every line, thus just the filename

git diff --name-status origin/master | grep '\.php$' | grep -v "^[RD]" | awk '{ print $2 }'

```

These scripts can easily be tested in your local environment ( at least if you have a Linux machine, that is ;-) ).

Now, as we have our first check, we'll finally create our `.gitlab-ci.yml`. This is where your pipeline is declared using [YAML notation](https://yaml.org/):

```yml

# we're using this beautiful tool for our pipeline: https://github.com/jakzal/phpqa

image: jakzal/phpqa:alpine

# For this sample pipeline, we'll only have 1 stage, in real-world you would like to also add at least "deploy"

stages: - QA

linter:

stage: QA

# this is the main part: what is actually executed

script: - sh ci/get-changed-php-files.sh | xargs sh ci/linter.sh

```

The first line is `image: jakzal/phpqa:alpine` and it's telling Gitlab that we want to run our pipeline using a PHP-QA utility by [jakzal](https://github.com/jakzal). It is a docker image containing PHP and a huge variety of QA-tools. We declare one stage - QA, and this stage by now has just a single job named `linter`. Every job can have it's own docker image, but we don't need that for the purpose of this tutorial. Our project reaches [Step 2](https://gitlab.com/crocodile2u/ci-showcase/tree/step-2). Once I had pushed these changes, I immediately went to the [project's CI/CD page](https://gitlab.com/crocodile2u/ci-showcase/pipelines). Aaaand.... the pipeline was already running! I clicked on the `linter` job and saw the following happy green output:

```

Running with gitlab-runner 11.9.0-rc2 (227934c0) on docker-auto-scale ed2dce3a

Using Docker executor with image jakzal/phpqa:alpine ...

Pulling docker image jakzal/phpqa:alpine ...

Using docker image sha256:12bab06185e59387a4bf9f6054e0de9e0d5394ef6400718332c272be8956218f for jakzal/phpqa:alpine ...

Running on runner-ed2dce3a-project-11318734-concurrent-0 via runner-ed2dce3a-srm-1552606379-07370f92...

Initialized empty Git repository in /builds/crocodile2u/ci-showcase/.git/

Fetching changes...

Created fresh repository.

From https://gitlab.com/crocodile2u/ci-showcase * [new branch] master -> origin/master * [new branch] step-1 -> origin/step-1 * [new branch] step-2 -> origin/step-2

Checking out 1651a4e3 as step-2...

Skipping Git submodules setup

$ sh ci/get-changed-php-files.sh | xargs sh ci/linter.sh

Job succeeded

```

It means that our pipeline was successfully created and run!

### PHP Code Sniffer.

[PHP Code Sniffer](https://github.com/squizlabs/PHP_CodeSniffer) is a tool for keeping app of your PHP files in one uniform code style. It has a hell of customizations and settings, but here we will only perform simple check for compatibilty with [PSR-2](https://www.php-fig.org/psr/psr-2/) standard. A good practice is to create a configuration XML file in your project. I will put it in the root folder. Code sniffer can use a few file names, of which I prefer `phpcs.xml`:

```xml

<?xml version="1.0"?>

/resources

```

I also will append another section to `.gitlab-ci.yml`:

```yml

code-style: stage: QA script: # Variable $files will contain the list of PHP files that have changes - files=`sh ci/get-changed-php-files.sh` # If this list is not empty, we execute the phpcs command on all of them - if [ ! -z "$files" ]; then echo $files | xargs phpcs; fi

```

Again, we check only those PHP files that differ from master branch, and pass their names to `phpcs` utility. That's it, [Step 3](https://gitlab.com/crocodile2u/ci-showcase/tree/step-3) is finished! If you go to see the pipeline now, you will notice that `linter` and `code-style` jobs run in parallel.

## Adding PHPUnit

Unit and integration tests are essential for a successful and maintaiable modern software project. In PHP world, [PHPUnit](https://phpunit.de/) is de facto standard for these purposes. The PHPQA docker image already has PHPUnit, but that's not enough. Our project is based on [Laravel](https://laravel.com/), which means it depends on a bunch of third-party libraries, Laravel itself being one of them. Those are installed into `vendor` folder with [composer](https://getcomposer.org/). You might have noticed that our `.gitignore` file has `vendor` folder as one of it entries, which means that it is not managed by the Version Control System. Some prefer their dependencies to be part of their Git repository, I prefer to have only the `composer.json` declarations in Git. Makes the repo much much smaller than the other way round, also makes it easy to avoid bloating your production builds with libraries only needed for development.

Composer is also included into PHPQA docker image, and we can enrich our `.gitlab-ci.yml`:

```yml

test: stage: QA cache: key: dependencies-including-dev paths: - vendor/ script: - composer install - ./vendor/bin/phpunit

```

PHPUnit requires some configuration, but in the very beginning we used `composer create-project` to create our project boilerplate. **laravel/laravel** package has a lot of things included in it, and `phpunit.xml` is also one of them. All I had to do was to add another line to it:

```xml

```

APP_KEY enironment variable is essential for Laravel to run, so I generated a key with `php artisan key:generate`.

`git commit` & `git push`, and we have all three jobs on the **QA** stage!

## Checking that our checks work

In [this branch](https://gitlab.com/crocodile2u/ci-showcase/tree/failing-checks) I intentionally added changes that should fail all three job in our pipeline, take a look at [git diff](https://gitlab.com/crocodile2u/ci-showcase/compare/step-4...failing-checks). And we have this out from the pipeline stages:

**Linter**:

```

$ ci/linter.sh

PHP Linter is not happy about app/User.php:

Parse error: syntax error, unexpected 'syntax' (T_STRING), expecting function (T_FUNCTION) or const (T_CONST) in app/User.php on line 11

Errors parsing app/User.php

PHP syntax validation failed!

ERROR: Job failed: exit code 255

```

**Code-style**:

```

$ if [ ! -z "$files" ]; then echo $files | xargs phpcs; fi

FILE: ...ilds/crocodile2u/ci-showcase/app/Http/Controllers/Controller.php

----------------------------------------------------------------------

FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE

---------------------------------------------------------------------- 13 | WARNING | Line exceeds 120 characters; contains 129 characters

----------------------------------------------------------------------

Time: 39ms; Memory: 6MB

ERROR: Job failed: exit code 123

```

**test**:

```

$ ./vendor/bin/phpunit

PHPUnit 7.5.6 by Sebastian Bergmann and contributors.

F. 2 / 2 (100%)

Time: 102 ms, Memory: 14.00 MB

There was 1 failure:

1) Tests\Unit\ExampleTest::testBasicTest

This test is now failing

Failed asserting that false is true.

/builds/crocodile2u/ci-showcase/tests/Unit/ExampleTest.php:17

FAILURES!

Tests: 2, Assertions: 2, Failures: 1.

ERROR: Job failed: exit code 1

```

Congratulations, our pipeline is running, and we now have much less chance of messing up the result of our work.

## Conclusion

Now you know how to set up a basic QA pipeline for your PHP project. There's still a lot to learn. Pipeline is a powerful tool. For instance, it can make deployments to different environments for you. Or it can build docker images, store artifacts and more! Sounds cool? Then spend 5 minutes of your time and leave a comment, you can also tell me if there is a pipeline topic you would like to be covered in next posts.

SPONSORS