Band-Aid Fabric Tough Strips

I cook all the meals in my household and have worked in a bunch of manual jobs, from welding to construction, so I have a lot of experience with cuts, abrasions, and burns. After much experience and unwilling experiment, I highly recommend Band-Aid Tough Strips without exception or qualification.

Every other variety I have tried, including the plastic “waterproof” Tough Strips and the regular plastic and fabric Band-Aids, have, in a word, stunk. Why the fabric Tough Strips stay on through sweat and multiple soapings, I don’t know. The adhesive does seem to be of a different sort. But the fact is they do stay on through everyday and not-so-everyday abuse, and no other bandage I’ve tried comes close. Also they’re a little bigger than regular bandages, and the extra bit often makes the difference between not-quite and fully covering a wound. Be sure to apply them to dry skin while trying to avoid getting any antibiotic ointment on the sticky part as that stuff is like adhesive kryptonite.

— Tim Heffernan

[This is a Cool Tools Favorite from 2011]

Band-Aid Fabric Tough Strips ($6+)

Available from Amazon

via Cool Tools
Band-Aid Fabric Tough Strips

“Gun Crime” is a Made Up Word from the Anti-Gun World, Here are the Real Numbers

Opinion

U.S. Murder Concentrations by Local
U.S. Murder Concentrations by Local, IMAGE Crime Prevention Research Center

USA – -(AmmoLand.com)- When we talk about firearms,there is a LOT of misinformation and … outright lies told by the gun grabbing left.

For the left gun control is a means to an end, a way to gain power. Not to save lives. This is one of the reasons their programs fail. They don’t want to stop shootings but use them to retain power.

Here are the facts they choose to ignore. Facts YOU can use.

There are approximately 120,000,000 gun owners in the US. We are the majority of voting adults.

53% of all shooting are by black men under 30. So, 3% of the US population does more than ½ the killing. 83% of all shooting are gang and drug-related.

Only about 7% of all shootings from a rifle or shotgun and less than 40% of that 7% are involve Modern Sporting Rifles.

The U.S. ranks 11th in mass shootings for industrialized nations. 50% of the counties in the US will not have a murder with-in their boundary. 2% of the counties had 53% of all murders in the U.S.

Both Japan and Korea have much higher suicide rates than the US. Both nations virtually ban private gun ownership. 75% of all gun deaths are attributed to suicide. Guns are not the cause, just the means.

An Obama administration study showed guns are used over 500,000 time a year to save a life or prevent crime or assault.

U.S. Numbers

  • Total Number of gun deaths: 38,000
  • Suicides: 28,500
  • Gand and Drug: 7,885
  • Remaining: 1,615

If not for gangs and drugs, the number of murders by guns is below 1,700 in a county of 330,000,000 people. Remove the gangs and drugs, the US is one of the SAFEST countries in the world.

So fellow firearms owners – here are facts – the REAL facts

You’re reading this online, so share it. SHIFT the paradigm. For the left to face the reality that gun ownership is not the cause of violence. It is the lefts failed social programs of welfare that destroys families, and open borders that bring in opioid that destroys lives that are the real cause of gun deaths.

Use these facts, fight for our rights with EDUCATION and the TRUTH!

We have a country to save.

Oh, where did I get these facts? The FBI unified crime report. They’re all there for ANYONE to see.

Also check out the Crime Prevention Research Center.


About Don McDougall

Don McDougall
Don McDougall

Don McDougall is an NRA instructor and member of the Los Padres “Friends of the NRA” committee. If he’s not at the range, you will find him setting the record straight with on gun issues and gun safety on AmmoLand Shooting Sports News.

The post “Gun Crime” is a Made Up Word from the Anti-Gun World, Here are the Real Numbers appeared first on AmmoLand.com.

via AmmoLand.com
“Gun Crime” is a Made Up Word from the Anti-Gun World, Here are the Real Numbers

Searchman – MYSQL Driver For Laravel Scout

laravel-searchman

MySql Driver for Laravel Scout

Requirements

  • Requires Laravel Installed ^5.6
  • Requires Laravel Scout ^7.0

Installation

composer require nwogu\laravel-searchman

Setup

Searchman Provides a Mysql Driver for Laravel Scout, for full text search
with indexing priorities and sql where expressions.

Laravel Scout Documentation

After installing Searchman, you can publish the configuration
using the vendor:publish Artisan command. This command will publish the searchman.php
configuration file to your config directory:

php artisan vendor:publish --provider="Nwogu\SearchMan\Provider\SearchableServiceProvider"

Add the Nwogu\SearchMan\Traits\SearchMan trait to the model you would like to make searchable. This trait uses Laravel’s Scout Searchable and adds extra methods required by the engine:

<?php namespace App; use Illuminate\Database\Eloquent\Model; use Nwogu\SearchMan\Traits\SearchMan; class Meeting extends Model { use SearchMan; } 

As with Scout, you can overide the searchableAs method in your model to change
the default index table name.

Queuing

As at v1.0.1, Searchman has not been effectively tested with queues.

Migrations

Run the command php artisan searchman:make-index {Model} to generate the index
for the specific model.

php artisan searchman:make-index "App\Meeting"

A migration file will be created in laravel’s default base migrations folder.

run the migration with php artisan migrate to publish the migration.

At the point, you can now start indexing your models.

Laravel Scout Documentation

Priority Handlers

Searchman is built around indexing priorities. By default, two priority handlers
are available for use

  • Nwogu\SearchMan\PriorityHandlers\LocationPriorityHandler
  • Nwogu\SearchMan\PriorityHandlers\LongTextPriorityHandler

You can specify which handler to use for your indexing by defining the method
getIndexablePriorities on your indexable model. It should return an array
specifing the column name and the handler.

 public function getIndexablePriorities() { return [ 'minutes' => LongTextPriorityHandler::class, 'email' => LocationPriorityHandler::class ]; } 

By default, the LocationPriorityHandler is used for all indexing. you can
overide this in the searchman config file.
Building your own handlers is easy. Implement the Priority handler Interface and you are good to go.

Searching

Laravel Scout only suports strict where clauses. but with Searchman, you can specify the operation of
your where statements using :.

App\Meeting::search("discussion on health")->where("attendance:>", 10)->get(); 

For more on search, look up the Laravel Scout Documentation

Results

Calling get on your query would return an Eloquent collection of models. However using raw would
return an eloquent collection ordered by priorities.

 {#3017 +"id": 9, +"society_id": 1, +"name": "General Meeting Thursday, 21 Mar, 2019", +"type": "general meeting", +"minute": "<p>tjlkj;km;</p>", +"start_time": "2019-03-18 14:00:00", +"end_time": "2019-03-18 17:00:00", +"presider": 1, +"total_attendance": 1, +"created_at": "2019-03-18 19:16:01", +"updated_at": "2019-03-18 19:16:01", +"meeting_date": "2019-03-21 20:19:00", +"priority": 3.0, +"document_id": 9, } 

via Laravel News Links
Searchman – MYSQL Driver For Laravel Scout

Previewing mail notifications in Laravel just got easier

Previewing mail notifications in Laravel just got easier

Since Laravel 5.8.16 the MailMessage class created by a Mail Notification implements the Renderable interface. This makes previewing it in a browser for testing much simpler. Rather than jumping through the hoops required before you can now do this:

Route::get('mail-preview', function () { $invoice = App\Invoice::find(1); return (new App\Notifications\InvoicePaid($invoice)) ->toMail(null); }); 

This is now much more in line with the ability to preview Mailable classes in the browser.

Thanks to Avraham Appel for making the pull request to make this possible.

via Laravel News Links
Previewing mail notifications in Laravel just got easier

Laravel S3 Tools

Overview

This Laravel package contains additional functionality not currently in Laravel for interfacing with Amazon’s S3 service. In particular, there are methods for dealing with versioned objects within S3. It simply extends the existing core classes to add support for versioning in S3, and is tied into the Storage facade for convenience. It was designed to be a drop-in replacement, and is backwards compatible with the core functionality, so there shouldn’t be any conflicts. I developed this package originally for my own need to deal with versioned objects in S3 and wanted the convenience of Laravel’s Storage facade.

With this package, you can easily:

  • Manage versioned objects stored in S3
    • Get a list of versions for a given object stored in S3
    • Retrieve a specific version of an object stored in S3
    • Delete a specific version of an object stored in S3
  • Set or clear Amazon S3/API option values
  • Execute other Amazon S3/API commands against your objects

Other methods and conveniences may be added in the future, depending largely upon either my own needs, or suggestions from the community. Pull requests, bug reports, etc. are welcome! 🙂

NOTE: Yes, I know that you can make use of the underlying Amazon S3 API package to do these sorts of things. But I wanted the convenience of tying them into the Storage facade, as well as for some potential additional functionality down the road. So, if you’d rather do this:

// Instantiate an Amazon S3 client. $s3 = new S3Client([  'version' => 'latest',  'region' => 'us-west-2' ]);  // Fetch the latest version of a file try {  $s3->putObject([  'Bucket' => 'my-bucket',  'Key' => 'myfile.png',  'VersionId' => 'fiWFsPPFwbvlGh37rB9IaZYkO4pzOgWGz'  ]); } catch (Aws\S3\Exception\S3Exception $e) {  echo "There was an error retrieving the file.\n"; }

… instead of this:

$file = Storage::disk('s3-tools')->getVersion($versionId)->get('myfile.png');

… then that’s on you. Have fun. 🙂

Requirements

This package assumes you have already installed the following packages:

Laravel should already have the league/flysystem package installed, but you may need to install the others. I’ve added them as dependencies to this package, so it should be all automatic for you anyway.

Installation

You can install the package via composer:

composer require incursus/laravel-s3-tools

Once it is installed, you will need to add the service provider, as usual, to your config/app.php file:

 ...  'providers' => [  ...  Incursus\LaravelS3Tools\S3ToolsServiceProvider::class,  ...  ],  ...

Configuration

Environment Variables

AWS Environment Variables

The laravel-s3-tools package makes use of the existing AWS/S3 configuration within Laravel, so if you’ve already configured your app to use S3, you are good to go! Of course, provided you are using the most recent AWS/S3 config statements (these were changed not too long ago in Laravel). To make sure, check your .env file for the following:

AWS_ACCESS_KEY_ID=<YOUR KEY> AWS_SECRET_ACCESS_KEY=<YOUR SECRET> AWS_DEFAULT_REGION=<DEFAULT REGION> AWS_BUCKET=<YOUR BUCKET NAME> 

If you aren’t sure what value to use in AWS_DEFAULT_REGION, check this page for more information (use the value shown in the Region column in the table on that page.

S3 Tools Disk Name

By default, this package will use a disk name of s3-tools. If you’d like to rename it to something else, you can use the S3_TOOLS_DISK_NAME environment variable in your .env file, as show below.

S3_TOOLS_DISK_NAME="diskname" 

Disk Configuration

The laravel-s3-tools package requires that you setup a new disk configuration in your config/filesystems.php file. It’s pretty simple, really. Just copy the entry below and paste it into your config/filesystems.php file. It will automatically look in your .env file for a custom disk name, and if not found, will fall back to the default value of simply s3-tools. This disk name will be the disk you use in the Storage facade whenever you want to utilize the functionality of this package. Th new disk configuration can also be used for normal, non-versioned S3 operations, or you can just use the original ‘s3’ configuration for that. Up to you!

So, your config/filesystems.php file should look something like this:

 <?php  return [   ...   'disks' => [   ...   's3' => [  'driver' => 's3',  'key' => env('AWS_ACCESS_KEY_ID'),  'secret' => env('AWS_SECRET_ACCESS_KEY'),  'region' => env('AWS_DEFAULT_REGION'),  'bucket' => env('AWS_BUCKET'),  'url' => env('AWS_URL'),  ],   // Add this entry  env('S3_TOOLS_DISK_NAME', 's3-tools') => [  'driver' => env('S3_TOOLS_DISK_NAME', 's3-tools'),  'key' => env('AWS_ACCESS_KEY_ID'),  'secret' => env('AWS_SECRET_ACCESS_KEY'),  'region' => env('AWS_DEFAULT_REGION'),  'bucket' => env('AWS_BUCKET'),  'url' => env('AWS_URL'),  ],  ],  ...

Usage

Summary of Methods

This it the TL;DR section. The following are the methods available to you with the laravel-s3-tools package. Each is described in more detail, with examples, below:

Method Name Arguments Description
setOption() $optionName, $optionValue Sets the value of a single AWS/S3 API option
setOptions() $optionArray Sets multiple AWS/S3 API option values
clearOption() $optionName Resets/clears a single AWS/S3 API option
clearOptions() N/A Resets/clears all AWS/S3 API options that you’ve set through either setOption() or setOptions()
getObjectVersions() $objectPath Fetches a list of versions of the specified object stored in S3
getVersion() $versionId Shortcut for setOption('VersionId', $versionString)
has() $objectPath Works the same as the normal has() method in Laravel, but provides support for checking for existence of a specific version of an object.
delete() $objectPath Works the same as the normal delete() method in Laravel, but provides support for deleting a specific version of an object.

Get a list of versions for a given object

A list of available versions of an object (file) stored in S3 can be retrieved and processed as follows. The returned list of versions will appear in reverse-chronological order based on the date last modified. The most recent version (the latest version) will always be the first element (0th) in the returned array.

$versions = Storage::disk('s3-tools')->getVersions('myfile.png');  foreach($versions as $v) {  echo '<li> Version ID: ' . $v['versionId'];  echo '<li> File Size: ' . $v['fileSize'] . ' bytes';  echo '<li> Is Latest Version?: ' . $v['isLatest']; // Will be true or false (boolean)  echo '<li> Date Modified: ' . $v['dateModified'];  echo '<li> ----------------------------------------------'; }

The output from the above code will appear similar to the following:

- Version ID: WX6q0O9qkcAcqld3DidZo2m5z68uGKnn - File Size: 132645 bytes - Is Latest Version?: 1 - Date Modified: 2019-03-21T19:35:29+00:00 ---------------------------------------------- - Version ID: nMw5IAmOPdMK0MR3eXtkSPVQTd18Vucd - File Size: 3631 bytes - Is Latest Version?: - Date Modified: 2019-03-21T19:16:26+00:00 ---------------------------------------------- ... 

Retrieve the latest version of an object

To retrieve the latest version of the a given object, simply use the Storage facade as usual. Here is an example of retrieving the latest version of an image from S3.

// Fetch the latest version of the file from S3 $file = Storage::disk('s3-tools')->get('myfile.png');   // Show the image in the browser return response($file)->header('Content-Type', 'image/png');

Fetch a specific version of an object

However, unlike Laravel, it can also be used to specify a specific version of an object that you wish to retrieve. The versionId field returned by getVersions() can be used to retrieve a specific version of an object from S3:

// Fetch the image from S3 $versionId = 'fiWFsPPFwbvlGh37rB9IaZYkO4pzOgWGz'; $file = Storage::disk('s3-tools')->getVersion($versionId)->get('myfile.png');   // Show the image in the browser return response($file)->header('Content-Type', 'image/png');

Delete the latest version of an Object

Without specifying a specific version, the latest version of an Object will be deleted:

$result = Storage::disk('s3-tools')->delete('some/longer/S3/path/business-plan.pdf');

The above operation will actually not "delete" the file from S3 if versioning is enabled for the bucket. By default, S3 will place a DeleteMarker for that version of the file. However, you are charged a nominal fee by Amazon for DeleteMarker storage. To fully delete a file, and leave no DeleteMarker in its place, you need to delete the specific version of the file as demonstrated below.

Alternatively, you can do the following to help manage your DeleteMarkers in S3:

  • Login to the S3 Console
  • Select your Bucket
  • Open Properties
  • Click Lifecycle
  • Create a rule set to Permanently Delete n days after the object’s creation date

Delete a specific version of an Object

If you specify a versionId, you can delete just that particular version of the object, assuming it exists. This operation will also not leave behind a DeleteMarker – think of it as a "hard delete" operation.

$versionId = 'fiWFsPPFwbvlGh37rB9IaZYkO4pzOgWGz'; $result = Storage::disk('s3-tools')->getVersion($versionId)->delete('some/longer/S3/path/business-plan.pdf');

Setting AWS/S3 API Options

At times, you may need to provide additional options for a given request. The options for each API call are well-documented on Amazon’s API Reference site. As an example, consider this request which does the same thing as the built-in getVersion() method in this package:

$result = Storage::disk('s3-tools')->setOption('VersionId', $versionString)->get('myfile.png');

You can also use the plural version called setOptions() to pass in an array of options:

$options = [  'VersionId' => 'fiWFsPPFwbvlGh37rB9IaZYkO4pzOgWGz',  'IfModifiedSince' => '2 days ago' ];  $result = Storage::disk('s3-tools')->setOptions($options)->delete('myfile.png');

The clearOption() method will reset a specific option, while the clearOptions() method will reset them all. If you experience any weirdness while doing complex operations into and out of S3, it may behoove you call clearOptions() to reset things prior to making certain API calls.

 // Retrieve a specific version of a file $versionId = 'fiWFsPPFwbvlGh37rB9IaZYkO4pzOgWGz'; $file = Storage::disk('s3-tools')->setOption('VersionId', $versionId)->get('myfile.png');  // Clear out ll of our options $file = Storage::disk('s3-tools')->clearOptions();  // or alternatively, just clear the 'VersionId' option //$file = Storage::disk('s3-tools')->clearOption('VersionId');  // Get the latest version of another file ... $file = Storage::disk('s3-tools')->get('myfile.png'); 

Execute Other Amazon S3 API Commands

Using the command() method, you can execute any other API call to S3 as well, and there are a great number of them. However, you will be responsible for not only passing in all of the appropriate options, but also parsing the response. All responses returned via this method are sent back to you in raw format. In some senses, this is a bit extraneous, since you could just use the offical S3 API to execute them, but I’ve included it here just to provide a method of consistency should you decide to use this package for other things.

Consider the following example which does the same thing as the built-in getVersions() method of this package:

$result = Storage::disk('s3-tools')->command('ListObjectVersions', [  'Prefix' => 'some/longer/S3/path/business-plan.pdf' ]);

Here is the same command above, but using a different bucket name:

$result = Storage::disk('s3-tools')->command('ListObjectVersions', [ 'Bucket' => 'MyBucketName', 'Prefix' => 'some/longer/S3/path/business-plan.pdf' ]); 

Here is an example of creating a new S3 bucket. Remember, bucket names in S3 must conform to DNS naming conventions, so:

  • Should not contain uppercase characters
  • Should not contain underscores
  • Should be between 3 and 63 characters long
  • Should not end with a dash
  • Cannot contain two, adjacent periods
  • Cannot contain dashes next to periods (e.g., "my-.bucket.com" and "my.-bucket" are invalid)
$result = Storage::disk('s3-tools')->command('CreateBucket', [ 'Bucket' => 'my-terrific-bucket-name', 'ACL' => 'private' ]); 

Here is a final example for you. Removing multiple objects in a single API call. In this example, we delete the latest version of myfile.png and business-plan.pdf, as well as a specific version of a fictitious spreadsheet.

$result = Storage::disk('s3-tools')->command('DeleteObjects', [ 'Delete' => [ [ 'Key' => 'myfile.png' ], [ 'Key' => 'some/longer/S3/path/business-plan.pdf' ], [ 'Key' => 'some/longer/S3/path/financial-planning-spreadsheet.xlsx', 'VersionId' => 'fiWFsPPFwbvlGh37rB9IaZYkO4pzOgWGz' ] ] ]); 

Notes on Storage::command Usage

  • When using the Storage::command method, the only "option" value that WILL actually default is Bucket … it will default to the value of AWS_BUCKET from your .env file if a bucket name isn’t passed in directly.

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email scott@incurs.us instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

via Laravel News Links
Laravel S3 Tools

Getting started quickly with logging in Laravel

You probably know that feeling when something is broken and you don’t know why. It might be a simple bug, but it also might be something more serious. That uncertainty can be frustrating and nerve-wracking.

We can improve our situation with logs. For any application you build, it’s important you ensure you have effective logging configured, regardless of the language or framework that you use. When you set your logs up properly, you can use them to quickly debug problems and monitor performance.

To help you get there, Scalyr created a series on logging with different techs. Some of the earlier articles in this series looked at the basics of getting started with logging in Python, Angular, and PHP. And in this article, I’m going to help you get started quickly with logging in Laravel.

What Is Laravel?

Before we get started with logging, let’s take a moment to talk about what Laravel actually is.

Laravel is a popular PHP framework that focuses on making the lives of developers as productive as possible (at least while coding). The creator of Laravel, Taylor Otwell, has worked hard to ensure that the syntax is clean and clear, allowing anyone who uses the framework to move from idea to solution as quickly as possible. The framework has excellent documentation and a strong, helpful developer community.

Like other features of the framework, logging in Laravel is expressive and easy to use—and it works straight out of the box. The services provided allow you log to local files, send an email, or even message your whole team in Slack. Also, Laravel leverages a powerful PHP logging library called Monolog, which provides powerful handlers for logs. You can use the developer-friendly configuration of Laravel to leverage these handlers and create a bespoke logging experience.

Getting Our Project Up and Running

Before you can get started with logging, you need to get a local version of Laravel up and running on your machine. There are full installation details on the Laravel website to help you do this, but let me share some advice here, too.

The smoothest way to install is first to set up PHP and Composer on your machine. Composer is the package manager for PHP, and if you’ve used npm for Node packages or pip for Python then this will be familiar. With Composer installed, you can install the Laravel installer globally as follows:

composer global require laravel/installer

Once you’ve installed the utility, you can use it to get your project up and running. For this article, I’m going to call my project logging.

laravel new logging

And there it is—a completed application installed:

Once all of the dependencies have been pulled down and installed, you can change directory and use Artisan to serve your project locally. Artisan is the command-line tool for Laravel—it’s incredibly powerful and is an essential tool in any Laravel developer’s toolkit.

php artisan serve

Now, navigate to the address listed, 127.0.0.1:8000, and you should see the Laravel base project display in your browser.

The Simplest Laravel Logging That Could Possibly Work

Now that your application is up and running, let’s do the simplest possible logging. In your text editor, open up the routing file routes/web.php. To log, you’re going to use the Log facade (we’ll see more of this later). So just below the opening PHP tag, add this:

use Illuminate\Support\Facades\Log;

The only other piece of code in the file is the route:

Route::get('/', function () { return view('welcome'); });

This code is saying when the route / receives a GET HTTP request, it should resolve the function. As you can see, that function is simply returning the welcome view, which is the page you saw above. To log every time that a user arrives at this page, simply update the code to something like this:

Route::get('/', function () { Log::info('A user has arrived at the welcome page.'); return view('welcome'); });

Check your application is still serving and visit 127.0.0.1:8000 again. If all has gone well, nothing should have changed for the user, but Laravel will have logged this event. And if you open up storage/logs/laravel.log, you’ll be able to find a line to this effect:

[2019-05-08 14:16:39] production.INFO: A user has arrived at the welcome page.

And that’s it! You have successfully logged an event in Laravel.

Laravel Project Structure

You’ll find that Laravel is quite opinionated about the structure of the projects you create with it. The framework follows a model-view-controller (MVC) architecture, and if you stick to the structure, then all of the auto-discovery features will work seamlessly.

Here’s the Laravel file structure:

While we’ll look at other parts of the framework throughout this article, the most relevant file for us will be the logging.php file in the config directory. Let’s open that up now and take a look.

logging.php: The Config File

<?php use Monolog\Handler\StreamHandler; use Monolog\Handler\SyslogUdpHandler; return [ 

The config file for logging starts by importing the Monolog handlers. These will be used throughout the logging process, but it’s mostly the framework itself that will use them. Laravel has some helpful methods that will allow you to log without interacting much with this library directly.

Once the config file has imported Monolog, the rest of this file returns an associative array that defines the configuration options for logging in this project.

The first top-level key is default, which, as the name suggests, sets the default logging channel: As we’ll see later, you can configure this using environment variables, allowing different solutions for your development and production systems. If you’ve been following along, here is what the default key looks like in the app created above:

'default' => env('LOG_CHANNEL', 'stack'),

The second is the configuration for log channels.

Log Channels in Laravel

In Laravel, a channel is a log driver with some configuration. You can provide as many different channels for your logs as you would like.

Here, we’re using the single driver to manage my ‘not-urgent’ channel, while we’re using the slack driver to look after my ‘really-urgent’ channel:

'channels' => [ 'not-urgent' => [ 'driver' => 'single' ], 'really-urgent' => [ 'driver' => 'slack' ] ]

The initial configuration gives the scaffolding for a wide variety of channels covering most of the common use cases. Here are the available channel drivers and a brief description of what they do, as described in the Laravel documentation:

The Log Stack Channel

You may want certain log messages to go to more than one place. Let’s say you want to send a message to Slack, log the message in your rotating daily logs, and have an email sent to your client. Laravel provides the stack driver for this purpose:

 'stack' => [ 'driver' => 'stack', 'channels' => ['daily', 'slack'], 'ignore_exceptions' => false, ],

The channel name can be anything you’d like, but in the default configuration, this is simply set to stack. In the configuration array, you pass the driver as stack and an array of the channels you’d like to send to. As can be seen in my example above, I’m sending to the daily channel and the Slack channel. You have to define both of these in the configuration file to be valid. Now, any log message sent to the stack channel will go to the channels in the array.

You may notice the extra configuration option set in the array. Since the aim of the Laravel maintainers is to be as expressive as possible, the purpose of the new option won’t surprise you. By default, Laravel will ignore exceptions in PHP. So you’ll use this option to log exceptions to help with debugging.

As you can imagine, there are more options to change logs than we will explore here. For a more comprehensive exploration, the Laravel documentation is a good place to start.

Log Levels

At this point, let’s talk about log levels. Monolog supports all eight of the logging levels defined in the RFC 5424 specification: emergency, alert, critical, error, warning, notice, info, and debug. If you’re not familiar, it’s a list of descending seriousness. The framework itself declares logging events at different levels, and as you’ll see, you can too.

return [ ... 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => 'critical', 'days' => 14, ], ... ];

When configuring a logging channel, you can set the minimum level of event you want to log. The configuration above will log events that are emergency, alert, and critical, but it will discard any events at the lower levels.

Logging in the Environment File

You’ll no doubt have different needs depending on the environment you’re logging in. It makes sense to log all events to a local file while you’re debugging locally. But on a production machine, this can quickly get unwieldy. A large log file that lists everything that has happened may not be useful in diagnosing a problem quickly and effectively.

Likewise, you probably won’t want to send a Slack message to your team every time you forget a semicolon. To help with these environment-specific configurations, we have the .env file in the root of the directory.

In this file, there’s a list of keys and values. By convention, these are in all caps, and words are separated by underscores, like this:

LOG_CHANNEL=stack

When set, any part of the Laravel application will be able to access this through the env() function. This function returns the value of an environment variable. You can set it to return a default but pass a second parameter. Otherwise, it will return null.

return [ ... 'default' => env('LOG_CHANNEL', 'daily') .. ];

In this case, the default channel will be whatever you have assigned in the environment file. If the relevant key, LOG_CHANNEL, is not present, then the env function will return the second parameter, daily.

Note that there will be cases in which you don’t want to pass a default value:

return [ ... 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel Log', 'emoji' => ':boom:', 'level' => 'critical', ], ... ]; 

In this instance, we only want to send to Slack when the webhook URL has been defined in the .env file. This key doesn’t exist by default. And so to set up Slack, we’ll need to add a new line to that file with this key and the correct URL from Slack.

Laravel’s Default Logging Configuration

In a moment, we’re going to talk about sending messages to the log channels. But before we do, let’s recap. So far, we’ve explored all of the basic configuration options, as well as some of the more advanced ones. Now, I want to follow the thread of how the application we set up is configured out of the box.

return [ 'default' => env('LOG_CHANNEL', 'stack'), 'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => ['daily'], 'ignore_exceptions' => false, ], ... 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => 'debug', 'days' => 14, ], ... ];

I’ve extracted the relevant parts from the configuration array above. We can see the default channel is set using the environment variable. Or if that key is missing, it will default to stack.

The stack channel is only pushing messages to a single channel—the daily channel.

The daily channel is configured with a path where log messages will be written to. Its level is set to debug, so it will log all levels of error. The days setting lets Laravel know how many days’ worth of logs to store before it starts to delete them.

So, when we log a message, we’ll navigate to the storage and be able to find them in the directory defined above with the filename laravel-YYYY-MM-DD.log.

The Logging Facade

Now your logs are configured and ready to be used. In order to write to the logs, we’re going to use the Log facade. A facade in Laravel is a static-like interface used to call classes within the framework that are available from the service container. Facades provide a more expressive and readable way for developers to use methods while allowing the underlying classes to be as testable and flexible as possible.

All of the facades in Laravel are available in the Illuminate\Support\Facades namespace, so to use the Log facade, you’ll need to include the following use statement at the top of the PHP file you’ll log from.

For our example, I’m going to use the routes/web.php file to be able to add logging to my routes. After the opening PHP tag, add the following:

use Illuminate\Support\Facades\Log;

Once imported, you can use the facade to log an event at any of the levels mentioned above:

Route::get('/', function () { Log::info('This is an info message that someone has arrived at the welcome page.'); return view('welcome'); });

You can place these log statements anywhere, and they can serve as a helpful tool to accurately understand what’s working (or not working) in your application.

[2019-05-04 14:21:52] production.INFO: This is an info message that someone has arrived at the welcome page.

As you can see, the log message begins with the timestamp. Following this is the application environment, which the APP_ENV key defines in the .env file. After that, there’s the level of the log message, followed by the message itself.

Logging to a Particular Channel

Sometimes it may be necessary to bypass the default channel and send a message to a specific channel. The Log facade makes that really straightforward:

Log::channel('slack')->info('This is an informative Slack message.');

This would log to Slack with a level of info.

Now, what if you wanted to create a multi-channel stack on the fly? It’s possible to declare this in a really expressive way, as follows:

Log::stack(['single', 'email'])->critical('I need ice-cream!');

You can pass the array of channels to the stack command and chain the log message with the required level.

Sending Contextual Information

A log message on its own may not be very useful, which is why we can also pass contextual information along with the message. This is passed as an array along with the message, and it’ll be formatted and added to the log message.

Log::alert('This page was loaded', ['user' => 3, 'previous_page' => 'www.google.com']);

This will produce a log message that will give you more information to work out the root cause of any potential problems that may be lying within your application. If you have a theory about what might be causing the problem, then you can use logs to gather some evidence and to help you fix it. You can see that demonstrated here:

[2019-05-03 13:21:58] testing.ALERT: This page was loaded {"user":3,"previous_page":"www.google.com"}

Formatting Log Messages

Monolog provides lots of different ways to be able to format your log messages. I’ve left this until the end because it’s not as critical as the other functionality that we’ve discussed so far. The default formatter is the LineFormatter, which in general does a great job of providing readable and helpful messages. If you’d like something more custom, that’s also very possible.

The Monolog documentation gives a full list of the formatters available, ordered roughly in order of use. This is a great jumping off point if you want to make changes to how your log messages look. You can then pass the formatter key and formatter_with key in the configuration array as you define a given channel.

Here’s how you might configure the daily driver to use the HtmlFormatter:

return [ ... 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => 'debug', 'days' => 14, 'formatter' => MonologFormatterHtmlFormatter::class, 'formatter_with' => [ 'dateFormat' => 'Y-m-d', ], ], ... ];

Conclusion

For a starter’s Laravel logging guide, it feels like we’ve covered a lot. We explored in depth how to configure logs and how to send messages to different channels. Plus, we even briefly dipped into how to format and understand those logs.

As I mentioned before, the Laravel documentation is very helpful and readable. I’m always finding my way back to reread how to do something. Also, the source code itself is a really helpful source of learning. Feel free to open up the Log facade file and to explore what you find. As you pull on the threads of the code, you will find your understanding deepen and grow.

Lastly, the community of developers around Laravel is incredibly helpful. Reach out and ask for help—we’re all learning!

Good luck with implementing logs in your own projects, using them to speed up your development, understand your problems quickly, and make awesome things!

This post was written by Kevin Cunningham. Kevin is a full-stack developer working with PHP and Python on the backend and Vanilla JS and Vue on the front end. He loves taking ideas and making something tangible from them that adds value to businesses and lives. He spent 12 years teaching high school mathematics and still loves doing puzzles when he’s not hanging out with his wife and sons on the beach in Brighton, England.

via Laravel News Links
Getting started quickly with logging in Laravel

Laravel Auth: After-Registration Redirect to Previous (Intended) Page

Laravel Auth features a function to redirect logged-in user to the same page they were visiting before. So, for example, if you visit /posts, you get automatically redirected to /login and then enter your data successfully, Laravel will “remember” and redirect you back to /posts instead of default /home. But it doesn’t work with new user registration, let’s see how we can change it.

Imagine the scenario:

  • You visit /posts URL;
  • System uses ‘auth’ middleware and redirects you back to /login form;
  • But you don’t have a user yet, so you click Register and land on /register URL;
  • And then, after successful registration – you get redirected where? To default /home URL, or whatever is specified in $redirectTo property in RegisterController.

So, how to customize it and make Laravel “remember” previous page for registration, too? We will dive into how Auth works internally.

In fact, it already stores that information, we just need to use it.

If you dig deeper into the LoginController logic, it uses Trait AuthenticatesUsers.php from core Laravel’s /vendor folder. And it has this method:

public function login(Request $request) { // ... if ($this->attemptLogin($request)) { return $this->sendLoginResponse($request); } // ... }

Let’s dig deeper – what is sendLoginResponse()? Within the same Trait:

protected function sendLoginResponse(Request $request) { // ... return $this->authenticated($request, $this->guard()->user()) ?: redirect()->intended($this->redirectPath()); }

As you can see, it uses redirect()->intended() method. How does it work? Official Laravel documentation describes it like this:

The intended method on the redirector will redirect the user to the URL they were attempting to access before being intercepted by the authentication middleware.

Under the hood, its logic is in /vendor/laravel/framework/src/Illuminate/Routing/Redirector.php:

public function intended($default = '/', $status = 302, $headers = [], $secure = null) { $path = $this->session->pull('url.intended', $default); return $this->to($path, $status, $headers, $secure); } 

Now, let’s take a look at app/Http/Controllers/Auth/RegisterController.php, it also uses a Trait from the core:

trait RegistersUsers { use RedirectsUsers; // ... public function register(Request $request) { $this->validator($request->all())->validate(); event(new Registered($user = $this->create($request->all()))); $this->guard()->login($user); return $this->registered($request, $user) ?: redirect($this->redirectPath()); } 

Look at the last part of redirection. As you can see, it uses simple redirect(), without intended(). So this is the part we need to change.

But we can’t edit that directly in /vendor folder, what we do is we copy-paste the same Trait’s method into RegisterController, and change the redirection part:

class RegisterController extends Controller { use RegistersUsers; // ... /** * Handle a registration request for the application. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function register(Request $request) { $this->validator($request->all())->validate(); event(new Registered($user = $this->create($request->all()))); $this->guard()->login($user); return $this->registered($request, $user) ?: redirect()->intended($this->redirectPath()); } }

And, that’s it – now, after registration user will be redirected to the page they were visiting before ‘auth’ middleware restricted their access.

You can read more Auth “tricks” in these articles:

via Laravel News Links
Laravel Auth: After-Registration Redirect to Previous (Intended) Page

How Bowling Balls Are Made

How Bowling Balls Are Made

Link

We recently saw what the insides of a bowling ball looked like. Now see those balls get that way in this clip from How It’s Made, starting out with a soupy goo for its core, wrapped in polymer and polyurethane layers, and then sanded. We were most surprised by the odd shape of the core.

via The Awesomer
How Bowling Balls Are Made

Laravel Auth: After-Registration Redirect to Previous (Intended) Page

Laravel Auth features a function to redirect logged-in user to the same page they were visiting before. So, for example, if you visit /posts, you get automatically redirected to /login and then enter your data successfully, Laravel will “remember” and redirect you back to /posts instead of default /home. But it doesn’t work with new user registration, let’s see how we can change it.

Imagine the scenario:

  • You visit /posts URL;
  • System uses ‘auth’ middleware and redirects you back to /login form;
  • But you don’t have a user yet, so you click Register and land on /register URL;
  • And then, after successful registration – you get redirected where? To default /home URL, or whatever is specified in $redirectTo property in RegisterController.

So, how to customize it and make Laravel “remember” previous page for registration, too? We will dive into how Auth works internally.

In fact, it already stores that information, we just need to use it.

If you dig deeper into the LoginController logic, it uses Trait AuthenticatesUsers.php from core Laravel’s /vendor folder. And it has this method:

public function login(Request $request) { // ... if ($this->attemptLogin($request)) { return $this->sendLoginResponse($request); } // ... }

Let’s dig deeper – what is sendLoginResponse()? Within the same Trait:

protected function sendLoginResponse(Request $request) { // ... return $this->authenticated($request, $this->guard()->user()) ?: redirect()->intended($this->redirectPath()); }

As you can see, it uses redirect()->intended() method. How does it work? Official Laravel documentation describes it like this:

The intended method on the redirector will redirect the user to the URL they were attempting to access before being intercepted by the authentication middleware.

Under the hood, its logic is in /vendor/laravel/framework/src/Illuminate/Routing/Redirector.php:

public function intended($default = '/', $status = 302, $headers = [], $secure = null) { $path = $this->session->pull('url.intended', $default); return $this->to($path, $status, $headers, $secure); } 

Now, let’s take a look at app/Http/Controllers/Auth/RegisterController.php, it also uses a Trait from the core:

trait RegistersUsers { use RedirectsUsers; // ... public function register(Request $request) { $this->validator($request->all())->validate(); event(new Registered($user = $this->create($request->all()))); $this->guard()->login($user); return $this->registered($request, $user) ?: redirect($this->redirectPath()); } 

Look at the last part of redirection. As you can see, it uses simple redirect(), without intended(). So this is the part we need to change.

But we can’t edit that directly in /vendor folder, what we do is we copy-paste the same Trait’s method into RegisterController, and change the redirection part:

class RegisterController extends Controller { use RegistersUsers; // ... /** * Handle a registration request for the application. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function register(Request $request) { $this->validator($request->all())->validate(); event(new Registered($user = $this->create($request->all()))); $this->guard()->login($user); return $this->registered($request, $user) ?: redirect()->intended($this->redirectPath()); } }

And, that’s it – now, after registration user will be redirected to the page they were visiting before ‘auth’ middleware restricted their access.

You can read more Auth “tricks” in these articles:

via Laravel Daily
Laravel Auth: After-Registration Redirect to Previous (Intended) Page

PHP Implode Example | PHP implode() Function Tutorial

PHP implode() Function Example

PHP Implode Example | PHP implode() Function Tutorial is today’s topic. The implode function in PHP is used to join the elements of an array with a string. The implode() function returns the string from the elements of the array. The function is binary-safe. The implode() function returns a string containing the string representation of all the array items in the same order, with a glue string between each element. We join the array elements with the string. Just like join() function, implode() function also returns the string formed from the elements of the array.

PHP Implode Example

If we have an array of elements, we can use the implode() function to join them all to form one string. See the syntax of PHP implode() function.

Syntax

implode(separator,array)

The separator parameter is optional and specifies what to put between the array elements.

The array parameter is required, and it is the array to join to the string.

See the following example.

<?php

// app.php

$frontend = ['Svelete','Angular','React', 'Vue'];
echo implode("|", $frontend);

See the below output.

PHP Implode Example

 

The implode() function accept its parameters in either order. However, for consistency with the explode() function, you should use the documented order of arguments.

One thing you can note that an array with one or no elements works fine. For example, see the code.

<?php

// app.php

$arrA = ["Asylum","House","Coven"];
$arrB = ["AHS"];
$arrC = [];

echo implode("|", $arrA)."\n";
echo implode("|", $arrB)."\n";
echo implode("|", $arrC);

See the below output.

PHP implode() Function Tutorial

 

The implode() function in PHP is easily remembered as “array to a string,” which means that it takes an array and returns a string. It rejoins any array elements and returns the resulting string, which may be put in a variable.

PHP implode() function on Associative Arrays

The implode function acts on array “values,” disregarding any keys. See the following example.

<?php

// app.php

$devs = ['1st' => 'CloudArchitecht',
        '2nd' => 'DevOps',
        '3rd' => 'DataScientists'];

echo implode(" | ", $devs)."\n";

See the below output.

PHP implode() function on Associative Arrays

 

The implode() function also be used for building tags or complex lists, like the following.

<?php

$elements = array('a', 'b', 'c');

echo "<ul><li>" . implode("</li><li>", $elements) . "</li></ul>";

Also, it is quite handy in INSERT statements.

<?php

 // array containing data
 $array = array(
  "name" => "Krunal",
  "surname" => "Lathiya",
  "email" => "krunal@appdividend.com"
);

// build query...
$sql  = "INSERT INTO table";

// implode keys of $array...
$sql .= " (`".implode("`, `", array_keys($array))."`)";

// implode values of $array...
$sql .= " VALUES ('".implode("', '", $array)."') ";

// execute query...
$result = mysql_query($sql) or die(mysql_error());

If you want to implode the array of booleans, you will get strange result. See the following code.

<?php

// app.php

var_dump(implode('', array(false, true, false, false, true)));

The output is following.

PHP Implode Example Tutorial

 

It is worth noting that if you call implode on the string rather than the array, you do not get your string back, you get NULL.

The implode() function returns a string

 

The null values are imploded too. You can use an array_filter() to sort out the null values.

<?php

$ar = array("krunal", null, "lathiya");

print(implode(',', array_filter($ar, function($v){ return $v !== null; })));

Finally, PHP Implode Example | PHP implode() Function Tutorial is over.

The post PHP Implode Example | PHP implode() Function Tutorial appeared first on AppDividend.

via Planet MySQL
PHP Implode Example | PHP implode() Function Tutorial