Subscribe: Planet PHP
http://www.planet-php.org/rss/
Added By: Feedage Forager Feedage Grade B rated
Language: English
Tags:
day  developer  docker  event  factory  file  full stack  function  myfilter  new  password  redis  run  server  sms  weather 
Rate this Feed
Rate this feedRate this feedRate this feedRate this feedRate this feed
Rate this feed 1 starRate this feed 2 starRate this feed 3 starRate this feed 4 starRate this feed 5 star

Comments (0)

Feed Details and Statistics Feed Statistics
Preview: Planet PHP

Planet PHP



People blogging about PHP



 



Hello, Laravel? Communicating with PHP through SMS! - SitePoint PHP

Fri, 23 Jun 2017 16:00:19 +0000

In this article, we will modify our Laravel-powered phone-capable weather forecast app so that it is accessible via SMS (text message) in addition to the voice telephone system. It is recommended you read the previous post if you haven't done so yet - it's a 10 minute read for an excellent outcome. Note: If you're confused by the development environment we're using, it's Homestead Improved and you can learn more about it here, or go in detail by buying our book about PHP environments. Adding Routes To allow for SMS communication, we need some more routes. Open up the routes/web.php file and append the following code to it: Route::group(['prefix' => 'sms', 'middleware' => 'twilio'], function () { Route::post('weather', 'SmsController@showWeather')->name('weather'); }); The prefix for the route is sms, so that routes will have a path like /sms/weather, as the one in the example. This is the only route we need for SMS, as Twilio will call the same route over and over again. Twilio will access it via HTTP POST. We could also do this without the prefix, but it's more flexible this way if we decide to add more functionality to the SMS side later. Service Layer Next, we'll modify the service we wrote previously. Open up the app/Services/WeatherService.php file and remove the current getWeather method, then replace it with the one below: public function getWeather($zip, $dayName, $forSms = false) { $point = $this->getPoint($zip); $tz = $this->getTimeZone($point); $forecast = $this->retrieveNwsData($zip); $ts = $this->getTimestamp($dayName, $zip); $tzObj = new \DateTimeZone($tz->timezoneId); $tsObj = new \DateTime(null, $tzObj); $tsObj->setTimestamp($ts); foreach ($forecast->properties->periods as $k => $period) { $startTs = strtotime($period->startTime); $endTs = strtotime($period->endTime); if ($ts > $startTs and $ts < $endTs) { $day = $period; break; } } $weather = $day->name; $weather .= ' the ' . $tsObj->format('jS') . ': '; $response = new Twiml(); if ($forSms) { $remainingChars = 140 - strlen($weather); if (strlen($day->detailedForecast) > $remainingChars) { $weather .= $day->shortForecast; $weather .= '. High of ' . $day->temperature . '. '; $weather .= $day->windDirection; $weather .= ' winds of ' . $day->windSpeed; } else { $weather .= $day->detailedForecast; } $response->message($weather); } else { $weather .= $day->detailedForecast; $gather = $response->gather( [ 'numDigits' => 1, 'action' => route('day-weather', [], false) ] ); $menuText = ' '; $menuText .= "Press 1 for Sunday, 2 for Monday, 3 for Tuesday, "; $menuText .= "4 for Wednesday, 5 for Thursday, 6 for Friday, "; $menuText .= "7 for Saturday. Press 8 for the credits. "; $menuText .= "Press 9 to enter in a new zipcode. "; $menuText .= "Press 0 to hang up."; $gather->say($weather . $menuText); } return $response; } This function is very similar to the old one. The only difference is that it takes into consideration that the weather request might be coming form a telephone device via SMS, so it makes sure that the weather forecast isn't too long and tries to limit it to less than 140 characters. The response for SMS is still TwiML, just formatted for SMS. Continue reading %Hello, Laravel? Communicating with PHP through SMS!% [...]



PHP 7.2.0 Alpha 2 Released - PHP: Hypertext Preprocessor

Thu, 22 Jun 2017 00:00:00 +0000

The PHP development team announces the immediate availability of PHP 7.2.0 Alpha 2. This release contains fixes and improvements relative to Alpha 1. All users of PHP are encouraged to test this version carefully, and report any bugs and incompatibilities in the bug tracking system.THIS IS A DEVELOPMENT PREVIEW - DO NOT USE IT IN PRODUCTION!For information on new features and other changes, you can read the NEWS file, or the UPGRADING file for a complete list of upgrading notes. These files can also be found in the release archive.For source downloads of PHP 7.2.0 Alpha 2 please visit the download page, Windows sources and binaries can be found on windows.php.net/qa/.The third and final alpha will be released on the 6th of July. You can also read the full list of planned releases on our wiki.Thank you for helping us make PHP better.






What Is Snapshot Testing, and Is It Viable in PHP? - SitePoint PHP

Wed, 21 Jun 2017 16:00:29 +0000

Ah-ha moments are beautiful and rare in programming. Every so often, we're fortunate enough to discover some trick or facet of a system that forever changes how we think of it. For me, that's what snapshot testing is. You probably write a lot of PHP code, but today I want to talk about something I learned in JavaScript. We'll learn about what snapshot testing is and then see how it can help us write better PHP applications. Building Interfaces Let's talk about React. Not the kick-ass async PHP project, but the kick-ass JavaScript project. It's an interface-generation tool in which we define what our interface markup should look like as discrete parts: function Tweet(props) { return (
(image)
{props.user.handle}
{props.content}
) } function Tweets(props) { return (
{props.tweets.map((tweet, i) => { return ( ) })}
) } This doesn't look like vanilla Javascript, but rather an unholy mix of html and Javascript. It's possible to create React components using regular Javascript syntax: function Tweet(props) { return React.createElement( "div", { className: "tweet" }, React.createElement("img", { src: props.user.avatar }), React.createElement( "div", { className: "text" }, React.createElement( "div", { className: "handle" }, props.user.handle ), React.createElement( "div", { className: "content" }, props.content ) ) ); } To make this code, I pasted the Tweet function (above) into the Babel REPL. That's what all React code is reduced to (minus the occasional optimization) before being executed by a browser. Before I talk about why this is cool, I want to address a couple of issues... "Why Are You Mixing html and Javascript?!" We've spent a lot of time teaching and learning that markup shouldn't be mixed with logic. It's usually couched in the phrase "Separation of Concerns". Thing is, splitting html and the Javascript which makes and manipulates that html is largely without value. Splitting that markup and Javascript isn't so much separation of concerns as it is separation of technologies. Pete Hunt talks about this in more depth in this video. "This Syntax Is Very Strange" That may be, but it is entirely possible to reproduce in PHP and works out the box in Hack: class :custom:Tweet extends :x:element { attribute User user; attribute string content; protected function render() { return (
(image) :user->avatar} />
{$this->:user->handle}
{$this->:content}
); } } I don't want to in detail about this wild syntax except to say that this syntax is already possible. Unfortunately, it appears the official XHP module only supports HHVM and old versions of PHP... Testing Interfaces There are many testing approaches – some more effective than others. An effective way to test interface code is by faking (or making) a web request and inspecting the output for the presence and content of specific elements. Perhaps you've heard of things like Selenium and Behat? I don't want to dwell too much on them. Let's just say that Selenium is a tool we can use to pretend to be a browser, and Behat is a business-friendly language for scripting such pretense. Unfortunately, a lot of browser-based testing can be brittle. It's tied to the exact structTruncated by Planet PHP, read more at the original (another 2019 bytes)[...]



Simple way to add a filter to Zend-InputFilter - Rob Allen

Wed, 21 Jun 2017 10:02:04 +0000

Using Zend-InputFilter is remarkably easy to use: use Zend\InputFilter\Factory as InputFilterFactory; // set up InputFilter $specification = [ 'my_field' => [ 'required' => false, 'filters' => [ ['name' => 'StringTrim'], ], ], ]; $factory = new InputFilterFactory(); $inputFilter = $factory->createInputFilter($specification); // use InputFilter on some data $data['my_field] = 'Some string'; $inputFilter->setData($data); if ($inputFilter->isValid()) { Return false; } return $inputFilter->getValues(); // my_field is now trimmed How do you add your filter to it though? This is the world's most simple filter that does absolutely nothing: We'll call it MyFilter and store it in App\Filter\MyFilter.php: getDefaultFilterChain()->getPluginManager(); $filterPluginManager->setFactory(MyFilter::class, InvokableFactory::class); $filterPluginManager->setAlias('MyFilter', MyFilter::class); } } This class extends the standard Factory class and registers our filter into the filter chain's plugin manager. Note that we have to register the factory for the fully qualified filter classname and also we register an alias for the short form ('MyFilter') as that's much nicer to use in the specification. To use our new factory, we change the use statement to use our new factory: use App\InputFilter\Factory as InputFilterFactory; Now we can use 'MyFilter' in our specification: $specification = [ 'my_field' => [ 'required' => false, 'filters' => [ ['name' => 'StringTrim'], ['name' => 'MyFilter'], ], ], ]; Update your container's factory If you're already injecting the InputFilter's Factory to the class that's specifying the InputFilter, then it's easier to update that factory. For Pimple, this looks something like: getDefaultFilterChain()->getPluginManager(); $filterPluginManager->setFactory(MyFilter::class, InvokableFactory::class); $filterPluginManager->setAlias('MyFilter', MyFilter::class); $inputFilter = $factory->createInputFilter($specification); return $factory; }; We don't need to change anything else and we can use 'MyFilter' in our specification: $specification = [ 'my_field' => [ 'required' => false, 'filters' => [ ['name' => 'StringTrim'], ['name' => 'MyFilter'], ], ], ]; [...]



How to make Sculpin skip certain sources - Matthias Noback

Tue, 20 Jun 2017 19:30:00 +0000

Whenever I run the Sculpin generate command to generate a new version of the static website that is this blog, I notice there are a lot of useless files that get copied from the project's source/ directory to the project's output/ directory. All the files in the output/ directory will eventually get copied into a Docker image based on nginx (see also my blog series on Containerizing a static website with Docker). And since I'm on a hotel wifi now, I realized that now was the time to shave off any unnecessary weight from this Docker image. My biggest mistake was not googling for the quickest way to skip certain sources from getting copied to output/. Instead, I set out to hook into Sculpin's event system. I thought it would be a good idea to create an event subscriber and make it subscribe to the Sculpin::EVENT_BEFORE_RUN event. Event subscribers for this event will receive a so-called SourceSetEvent, allowing them to mark certain sources as "should be skipped". Sculpin is built on many Symfony components and it turned out to be quite easy to set up a traditional event subscriber, which I called SkipSources: final class SkipSources implements EventSubscriberInterface { /** * @var string[] */ private $patterns = []; public function __construct(array $patterns) { $this->patterns = $patterns; } public function skipSourcesMatchingPattern(SourceSetEvent $event): void { // see below } public static function getSubscribedEvents(): array { return [ Sculpin::EVENT_BEFORE_RUN => ['skipSourcesMatchingPattern'] ]; } } You can create your own Symfony-style bundles for a Sculpin project, but in this case defining a simple service in sculpin_kernel.yml seemed to me like a fine option too: # in app/config/sculpin_kernel.yml services: skip_sources: class: SculpinTools\SkipSources arguments: # more about this below - ["components/*", "_css/*", "_js/*"] tags: - { name: kernel.event_subscriber } Due to the presence of the kernel.event_subscriber tag Symfony will make sure to register this service for the events returned by its getSubscribedEvents() method. Looking for a way to use glob-like patterns to filter out certain sources, I stumbled on the fnmatch() function. After that, the code for the skipSourcesMatchingPattern() method ended up being quite simple: foreach ($event->allSources() as $source) { foreach ($this->patterns as $pattern) { if (fnmatch($pattern, $source->relativePathname())) { $source->setShouldBeSkipped(); } } } It matches a source with each of the patterns based on the source's relative pathname, as nothing outside of the source/ directory is relevant anyway. The patterns themselves are passed in as the event subscriber's first constructor argument. It's simply a list of glob-like string patterns. My solution turned out to be quite an effective way to mark certain files as "should be skipped", which was my goal. La grande finale Just like in my previous blog post, I finally ran into another possible solution, that's actually built in to Sculpin - a simple ignore configuration key allowing you to ignore certain sources using glob-like patterns. It does use a rather elaborate pattern matching utility based on code from Ant. Not sure if this library and fnmatch() have "feature parity" though. Turns out, all my extra work wasn't required after all. A simple Google search would have sufficed! So I removed all of this code and configuration from my project. But I still wanted to share my journey with you. And who knows, it could just be useful to have an example lying around of how to register an event subscriber and hook into Sculpin's build lifecycle... [...]



Making a Docker image ready for use with Swarm Secrets - Matthias Noback

Mon, 19 Jun 2017 19:30:00 +0000

Here's what I wanted to do: Run the official redis image as a service in a cluster set up with Docker Swarm. Configure a password to be used by connecting clients. See also Redis's AUTH command. The relevant command-line option when starting the redis server would be --requirepass. This is just a quick post, sharing what I've figured out while trying to accomplish all of this. I hope it's useful in case you're looking for a way to make a container image (an official one or your own) ready to be used with Docker Secrets. I started out with this docker-compose.yml configuration file, which I provided as an option when running docker stack deploy: version: '3.1' services: redis: image: redis command: redis-server --requirepass $(cat /run/secrets/db_password) secrets: - db_password secrets: db_password: file: db_password.txt This configuration defines the db_password secret, the (plain text) contents of which should be read from the db_password.txt file on the host machine. The (encrypted) secret will be stored inside the cluster. When the redis service gets launched on any node in the cluster, Docker shares the (decrypted) secret with the container, by means of mounting it as a file (i.e. /run/secrets/db_password) inside that container. The naive solution above looked simple and I thought that it might just work. However, I got this error message: Invalid interpolation format for "command" option in service "redis": "redis-server --requirepass $(cat /run/secrets/db_password)" Docker Compose does variable substitution on commands and thinks that $(...) is invalid syntax (it's expecting ${...}). I escaped the '$' by adding another '$' in front of it: redis-server --requirepass $$(cat /run/secrets/db_password). New errors: Reading the configuration file, at line 2 >>> 'requirepass "$(cat" "/run/secrets/db_password)"' Bad directive or wrong number of arguments Bad stuff. I thought I'd just have to wrap the values into quotes: redis-server --requirepass "$(cat /run/secrets/db_password)". Now, everything seemed to be fine, the Redis service was up and running, except that the password wasn't set to the contents of the db_password. Instead, when I tried to connect to the Redis server, the password seemed to have become literally "$(cat /run/secrets/db_password)"... At this point I decided: let's not try to make this thing work from inside the docker-compose.yml file. Instead, let's define our own ENTRYPOINT script for a Docker image that is built on top of the existing official redis image. In this script we can simply read the contents of the db_password file and use it to build up the command. The Dockerfile would look something like this: FROM redis:3.2.9-alpine COPY override_entrypoint.sh /usr/local/bin/ ENTRYPOINT ["override_entrypoint.sh"] And the override_entrypoint.sh script mentioned in it could be something like this: #!/usr/bin/env sh -eux # Read the password from the password file PASSWORD=$(cat ${REDIS_PASSWORD_FILE}) # Forward to the entrypoint script from the official redis image docker-entrypoint.sh redis-server --requirepass "${PASSWORD}" Building the image, tagging it, pushing it, and using it in my docker-compose.yml file, I could finally make this work. I was almost about to conclude that it would be smart not to try and fix everything in docker-compose.yml and simply define a new image that solves my uses case perfectly. However, the advantage of being able to pull in an image as it is is quite big: I don't have to rebuild my images in case a new official image is released. This means I won't have to keep up with changes that make my own modifications break in some unexpected ways. Also, by adding my own entrypoint script, I'm ruining some of the logic in the existing entrypoint script. For example, with my new script it's impossible to run the Redis CLI. La grande finale [...]



Hello, Laravel? Communicating with PHP through Phone Calls! - SitePoint PHP

Mon, 19 Jun 2017 16:00:25 +0000

Twilio is a SaaS application which enables developers to build telephone applications using web technologies. In this two-part series, we will leverage Twilio to build a weather forecast app that is accessed using the telephone system. The backend will be written with the Laravel framework (an exploratory video course is available for purchase here, or in the form of written tutorials here). In this part, we will create a simple program that will allow a user to call a phone number that we buy from Twilio, enter a zipcode, and receive the current weather forecast. The user can also get the weather for any day of the week via the voice menu prompts. In the second part of this series, we will leverage what was built in this article to allow the user to interact with the app via SMS (text message). Prerequisites Development Environment This article assumes Homestead Improved is installed. It is not necessary to use it, but the commands might differ slightly if you use a different environment. If you are not familiar with Homestead and want to produce similar results as this article aims to produce, please visit this SitePoint article that shows how to set up Homestead, and if you need a crash course in Vagrant, please see this post. Additionally, if this whets your appetite and you feel like exploring PHP development environments in depth, we have a book about that available for purchase. Dependencies We will create a new Laravel project and then add the Twilio PHP SDK and Guzzle HTTP client library to the project: cd ~/Code composer create-project --prefer-dist laravel/laravel Laravel 5.4.* cd Laravel composer require "twilio/sdk:^5.7" composer require "guzzlehttp/guzzle:~6.0" Development Let's go through all the steps, one by one. Routes Open up the routes/web.php file and add the following ones: Route::group(['prefix' => 'voice', 'middleware' => 'twilio'], function () { Route::post('enterZipcode', 'VoiceController@showEnterZipcode')->name('enter-zip'); Route::post('zipcodeWeather', 'VoiceController@showZipcodeWeather')->name('zip-weather'); Route::post('dayWeather', 'VoiceController@showDayWeather')->name('day-weather'); Route::post('credits', 'VoiceController@showCredits')->name('credits'); }); In this app, all requests will be under the /voice path. When Twilio first connects to the app, it will go to /voice/enterZipcode via HTTP POST. Depending on what happens in the telephone call, Twilio will make requests to other endpoints. This includes /voice/zipcodeWeather for providing today's forecast, /voice/dayWeather, for providing a particular day's forecast, and /voice/credits for providing information on where the data came from. Service Layer We are going to add a service class. This class will hold a lot of the business logic that will be shared between the voice telephone app and the SMS app. Create a new sub-folder called Services inside the app folder. Then, create a file called WeatherService.php and put the following content into it:



Being a Full Stack Developer - SitePoint PHP

Fri, 16 Jun 2017 15:00:02 +0000

A full stack developer who can get from a prototype to full MVP (minimum viable product) is often considered a jack of all trades, master of none, and with good reason. To define the modern full stack developer, we first need to focus on what the full stack developer used to be. Full Stack Developers Then Long ago, circa 2000 (in Internet-time, 17 years is a very long time ago), a full stack developer was someone who could: whip up a web page in some Adobe tools like Photoshop or Fireworks turn this design into html, CSS, and hotspots on images (aw, remember those?) write some basic PHP 4.0 scripts (no object oriented PHP was on the horizon back then) to handle the server-side of the logic store all dynamic data into MySQL, maybe do a bit of optimizing upload it all to a server via FTP and collect the paycheck Note that we're talking about PHP here - a full stack Flash or Coldfusion developer had a different (but only slightly different) workflow. Those were simple times, life was good. One-man agencies were a dime a dozen, and people still had time to spend with their family after work. What about now? What Does a Full Stack Developer Need to Know Now? These days, we have horrors like these happening - how did it come to this? To succeed in a now-saturated market, we developers - who are often perfectionists - hesitate to delegate and often live by the "if you want something done right" motto. This forces us into a corner where we have to learn everything, so that being a full stack developer often ends up encompassing the following. Server Admin / Devops A developer must know how to do basic server management. This includes but is not limited to: connecting to remote servers through the terminal, in non-GUI environments basic shell scripting managing users and groups on a server managing server programs like Apache and Nginx for serving apps managing firewalls and permissions installing new software and updating the distribution src="https://giphy.com/embed/dbtDDSvWErdf2" width="480" height="261" frameborder="0" class="giphy-embed" allowfullscreen=""/> via GIPHY Apart from these basics, a developer should know how to create good, healthy, isolated development environments, in either Docker or virtual machines like with Vagrant. If all of the above is something you're unfamiliar with, we have an excellent book about it for sale here. The developer should also be intimately familiar with version control systems in order to be able to reliably produce backups and shareable, collaborative collections of code, tracked for changes across time. No modern developer workflow is complete without version control these days. We have a fantastic video course about this for purchase here. Cloud Apart from actual managed or virtualized servers, a developer might need to know about the cloud - hosting on platforms like Heroku, Google Cloud, Azure, AWS, and others. src="https://giphy.com/embed/fnjzX4eGNUglq" width="480" height="349" frameborder="0" class="giphy-embed" allowfullscreen=""/> via GIPHY There's a fair bit to be said about platforms and tools that are more hype than immediately useful, but being familiar with the services everyone is talking about can come in handy in the long run - a client could demand a switch of providers any day now, and it pays to be ready. Luckily, we have the Truncated by Planet PHP, read more at the original (another 2200 bytes)[...]