https://media.notthebee.com/articles/62b0b6382c0a662b0b6382c0a7.jpg
Have you ever wanted an A.I. to draw random images that will both amaze and frighten you beyond your wildest dreams?
Not the Bee
Just another WordPress site
https://media.notthebee.com/articles/62b0b6382c0a662b0b6382c0a7.jpg
Have you ever wanted an A.I. to draw random images that will both amaze and frighten you beyond your wildest dreams?
Not the Bee
https://media.notthebee.com/articles/62b073b315a0162b073b315a02.jpg
This viral video out of Phoenix quickly got people talking about lawful self-defense over the weekend, and since the politicians are pushing super hard to disarm us all, I’m glad to see it.
Not the Bee
The following is a short HOWTO about deployment and use of Benchmark-kit (BMK-kit). The main idea of this kit is to simplify your life in running various MySQL benchmark workloads with less blood and minimal potential errors.
Generally as simple as the following :
$ bash /BMK/sb_exec/sb11-Prepare_50M_8tab-InnoDB.sh 32 # prepare data $ for users in 1 2 4 8 16 32 64 128 256 512 1024 do # run OLTP_RW for 5min each load level.. bash /BMK/sb_exec/sb11-OLTP_RW_50M_8tab-uniform-ps-trx.sh $users 300 sleep 15 done
Read more… (35 min remaining to read)
Planet MySQL
https://theawesomer.com/photos/2022/06/see_through_jet_engine_t.jpg
Warped Perception has made several project vehicles that incorporate small turbojet engines. For this video, he built a custom transparent housing for one of the jets so we can see exactly how it works to create thrust. Along the way, he offers a great layperson’s explanation of jet propulsion systems.
The Awesomer
https://www.buckeyefirearms.org/sites/buckeyefirearms.org/files/styles/slideshow/public/field/image/ccwhandbook.jpg?itok=Dk6I3RZZ

As of Monday, June 13, 2022, it is legal for "qualifying adults" to carry a concealed handgun in Ohio without a license.
Attorney General Dave Yost has issued an updated manual summarizing Ohio’s concealed carry laws and explaining the two ways you may now carry in the state, with or without a license.
Click here to view or download the manual as a PDF.
Whether you plan to carry with a license or without one, I highly recommend you read this manual, which covers a number of important topics, including:
In addition to reading this manual, I urge you to take a concealed carry class from an experienced and competent instructor, even if you do not plan to apply for a license. It is vital that you are familiar with Ohio self-defense law to help you make better decisions and act legally.
You can search for classes on OhioGunClass.org, a website we host for instructors in Ohio.
Dean Rieck is Executive Director of Buckeye Firearms Association, a former competitive shooter, NRA Patron Member, #1 NRA Recruiter for 2013, business owner and partner with Second Call Defense.
Buckeye Firearms Association
https://redberry.international/wp-content/uploads/2022/04/Linting-A-Laravel-Project-Using-PHP-CS-Fixer.png
Developers, deliberately or unknowingly, build their coding standards in the process of project development. A coding standard is a style that is applied to your whole codebase to shape a coding discipline and make the codebase more consistent and readable.
The first and foremost essential factor is related to the discipline of coding. Shaping discipline and creating a coding style makes it easier not only just to understand the existing code but also makes it easier to develop the codebase further.
On top of that, discipline with the coding style is also crucial for effective collaboration within the development team. This attitude makes teamwork much more straightforward and efficient. Besides, that way, the new developers will be able to comprehend the code easily. It will also help developers not to get upset with individual code style preferences.
However, we should also note that maintaining the coding standards with bare hands might be a highly complex task requiring time and effort. Therefore, there is a Linter concept in almost every programming language. With this article, we will dig down to understand Linting and how you can apply it to your Laravel Project by using PHP CS Fixer. So let’s get started.
Linter is a common tool that helps us develop a specific coding style and find errors.
In most cases, Linters are used in conjunction with the IDE. Linters are activated once a specific event fires and suggest a correction. You can also run Linter using a CLI to highlight and/or fix the errors in your codebase.
The short answer is Yes.
Nowadays, Laravel is the most popular framework in the PHP world. However, Laravel itself frequently uses the components of the other very popular framework – Symfony. The founder of Symfony, Fabien Potencier, created a PHP Linter called CS Fixer. So let’s talk more about it.
There are several ways to install CS Fixer:
In the following example, we will discuss how we can set up PHP CS Fixer in a per-project approach and connect it to VSCode and PHPStorm. Connecting to the other IDEs is a similar process.
First of all, we need to go to our Laravel project in the terminal and install PHP CS Fixer with Composer by running the following command:
composer require friendsofphp/php-cs-fixer --dev
Then if we see executable files in our project /vendor/bin directory we will see that one of them is php-cs-fixer.
If we run this command in the root folder of our project:
./vendor/bin/php-cs-fixer
We will see that CSFixer has been installed successfully and will display the following:
We made sure that PHP CS Fixer really works 🙏
Let’s move to the VSCode.
First, we will need to install the appropriate extension for CS Fixer in VSCode.
Pay attention to the fact that the author of this extension should be Junstyle.
Then we should create a .vscode folder in our project and a settings.json file in it where we will set configurations:
There are three things we need to configure:
Consequently, JSON configuration will look like this:
The only thing left is to create a .php-cs-fixer.php file in the root folder. We can set up formatting rules with that configuration file. Here is an example rule configuration file we use for some of our projects: PHP CS Fixer Config File.
Open the desired project in PHPStorm and go into the PHPStorm settings:
Then we should find the Quality Tools under PHP; this is where the PHP CS Fixer section should be:
Click the button with the three points and point out our CS Fixer binary file address which is located in the vendor/bin folder:
Click Validate and make sure that everything works fine.
Then we should move to CS Fixer Inspection and set several parameters:
We should mark PHP CS Fixer validation. Severity should be set to Error, and we should choose Custom in the Ruleset. This means that we need to give PHP CS Fixer our rule file which defines how our codebase should be formatted.
Before we configure which file should be used as a Ruleset by PHPStorm, we should create a .php-cs-fixer.php file in our Root folder. Here is an example configuration file we use for some of our projects: PHP CS Fixer Config File.
Then we should navigate to Inspections and find our newly created configuration file in PHPStorm:
Then we can save our configuration, which means that PHPStorm will already start analyzing our codebase and format it according to our ruleset.
However, this is still not enough. For the development process to be smooth, it would be better for PHP CS Fixer to make autocorrections. This is why we need to add the File Watcher.
For this we should navigate to File Watchers in the PHPStorm settings.
Now we should choose Custom in Templates and write a new Watcher configuration.
Name: PHP CS Fixer
File Type: PHP
Program: [Your Project Path]/vendor/bin/php-cs-fixer
Arguments: fix –config=$ProjectFileDir$/.php-cs-fixer.php –cache-file=$ProjectFileDir$/.php-cs-fixer.cache $FileDir$/$FileName$
Also, we should turn off the first two checkboxes in the Advanced Options:
Click the OK button, and the Watcher File will be added.
After that, our codebase will be auto-formatted using PHP CS Fixer every time we save the files.
The first time you CMD+S, PHPStorm will alert you to approve running the Watcher.
Click Trust Project and Run once you see the Alert box.
And that’s it 😉
Laravel News Links
https://www.pewpewtactical.com/wp-content/uploads/2017/08/terminator-with-laser-sight.jpg
Sci-fi flicks have to be fueled by imagination but still seem grounded. When you dress up existing items as props, you can do both.

As such, over the years, I’ve picked apart movies and television shows that utilize real guns in fictional frames. I took my own nerdism and translated it into a list of my favorite fiction firearms with a rear firearm at their core.
Without further explanation, let’s dive into my favorites, and at the end, I hope you add your favorites.
The Moses Brothers Self-Defense Engine Frontier Model B is both a mouthful to say and the chosen sidearm of Captain Malcolm ‘Mal’ Reynolds of the Firefly-class vessel the Serenity.
We see Mal use the Model B dozens of times in the show and movie, and he appears quite proficient with the handgun. He’s a quick draw and accurate enough to shoot a rope during a high-speed chase.

The Model B looks and functions like a semi-auto handgun. As a space western, you get the classic revolver-style grips and aesthetics of a Volcano repeating lever-action pistol.
It’s free from most space-age do-dads and presents a simple appearance with simple sights, with lots of industrial age lines and ridges to make it distinctive.
Inside the Model 5 sits a Taurus Model 85 revolver with a futuristic shell built around the gun.
Prices accurate at time of writing
Prices accurate at time of writing
It’s an interesting take on a sci-fi blaster. They took a revolver and turned it into a semi-automatic and dolled it up to produce a rather fine-looking futuristic handgun.
The Model B is so closely associated with Nathan Fillion’s character that it pops up in other shows, like Castle, as a subtle reference to the classic character.
The Space Marines of 2122 carry the M41A Pulse Rifle into combat, and the squad in the film Aliens mostly packs the M41A.
This select-fire weapon fires 10mm caseless ammunition with a total magazine capacity of 99 rounds — although it’s mentioned in some lore that Marines only load the magazines to 95 rounds to prevent jamming.

Even in the future, the Colonial Marine Corps can’t perfect their rifles. Outside the 10mm main gun, the M41A rifles are fitted with pump-action 30mm grenade launchers mounted beneath the barrel.
The M41A is a short carbine and isn’t too far off from the use of the M4 with an M203 in the modern-day.
In real life, the M41A pulse rifle utilizes a Thompson SMG fitted into a futuristic shell with a bottom-mounted Remington 870 fitted with a SPAS 12 heat shield and foregrip.

The use of a Thompson makes the M41A complete a rather larger circle. Marines carried Tommy guns as early as the Banana Wars, and the circle comes complete with the famed Colonial Marines carrying the M41A.
The combination of the rifle and grenade launcher makes the M41A pulse rifle an awesome weapon for destroying alien scum. You can see it in plenty of hero shots involving Ripley, Vasquez, and Hicks.
This setup also used .45 ACP blanks, which meant massive and sweet-looking muzzle flash.
I don’t want to fill this list with guns from one series or another, but I simply couldn’t choose between the M56 Smart gun and the M41A Pulse Rifle.
What can I say; I’m a machine gunner and have a bias. After becoming a machine gunner, I saw the actual benefits of the M56 Smart gun. Also, I appreciated that the machine gun team of Vasquez and Drake were tight and worked together.

The M56 Smart gun mounts a machine gun to the body of the gunner with a harness. This allows them to better carry their heavy weapon and utilize it in the standing. An advanced sighting system allows shooters to engage from the hip with accurate fire, and the weapon can aim autonomously.
In real life, the M56 Smart Gun is an MG 42 machine gun that certainly gives the gun that old-school look and feel, but the armorers dressed it up for that future-proof design.

The MG 42 has a famously fast firing rate of 1,200 rounds per minute and earned the name Hitler’s buzzsaw by American G.I.s in World War II. It’s a medium machine gun and one of the first true general-purpose machine guns.
For the mounting system, they used a camera Steadicam mount. Heck, they used motorcycle parts with a linkage to the trigger to make it fire when carried in such an odd way.
It’s an ingenious setup, and the M56 Smart gun was all kinds of cool.
When you have a massive cyborg police officer, you give him a massive gun. You can’t give RoboCop a Glock 17 and call it a day.
A big gun was needed, and filmmakers tried the Desert Eagle…but the Desert Eagle of all weapons was still too small.

So, they went to the shop and created their own — the Auto 9. RobCop’s Auto 9 was no standard pistol but a machine pistol that seemingly integrated a targeting system into Robocop’s visor.
We see him shoot a variety of people without ever aiming with seemingly perfect accuracy.
In real life, they dressed up a Beretta 93R. The Beretta 93R took the Beretta 92 series and added a burst feature to the fun. This allowed the weapon to be selective fire with a 3-round burst or semi-automatic.
Prices accurate at time of writing
Prices accurate at time of writing
As you’d imagine, it was too small for Robocop’s hand. To make it look bigger, they made the grip and barrel longer with a full-on shroud that added higher sights and gave it a look straight out of 2028 Detroit.

Part of that shroud appears to be a compensator that would reduce recoil and muzzle rise fairly well. It also granted the filmmakers some intense muzzle flash which always looks cool on film.
The Auto 9 is the first time a machine pistol has been practical.
2012’s Dredd was a sleeper hit but an overlooked gem. This film stuck to the source material of the famed comics and created a grisly and violent world devoid of Stallone yelling that he is the LAW!
Instead, we have Karl Urban playing Judge Dredd as the brutal and efficient killer that he is. In his hand is the famed Lawgiver MKII pistol.

This sidearm features a biometric identification mode that only Judges can use. It’s more than just a handgun.
The Lawgiver also utilizes a variety of modes, including the full auto “rapid-fire” mode, an armor-piercing mode, suppressed mode, stun rounds, incendiary rounds, and high explosives. Plenty of options for any situation in which a Judge might find themselves.

To keep track of all those modes, a display shows the current ammo count, mode, and other information to use such a complicated weapon.
The Lawgiver MKII in real life is a Glock 17 Gen 4 or Gen 3. We see the finger grooves that lock it down to those two generations.
Prices accurate at time of writing
Prices accurate at time of writing
Oddly enough, the Glock 17 makes a lot of sense since Glock pistols arm the majority of police officers in the United States.
Glock’s polymer frame pistol has dominated the market since its inception and created an awesomely reliable pistol that is both simple and robust for law enforcement.
In the film Blade Runner, Deckard’s gun never gets any official designation, so we’ll just call it Deckard’s gun.
Deckard is a biological robot-hunting police officer tasked with bringing escaped “skinjobs” down.

Blade Runner is far from an action film, but Deckard’s gun is prominently shown over and over throughout the film. It’s always been a different kind of cool — bizarre but realistic. Deckard’s blaster seems to be issued by the LAPD, and we see it in the hands of another Blade Runner.
In real life, the armorer took the classic Charter Arms Bulldog and morphed it into one of the most unique weapons in film.
Prices accurate at time of writing
Prices accurate at time of writing
The Charter Arms Bulldog is a .44 Special revolver that barely clings to its compact designation. Air Marshals in the 70s apparently carried the Bulldog, and it’s easy to see why.
It fires a big, heavy, and slow round that packed a decent punch for the time. Deckard’s blaster took the Bulldog and mounted the bolt-action from a Steyr Mannlicher Model SL to the top of the gun. There was a series of LEDs, a second trigger, and a really cool grip.

Deckard’s blaster might not be named, but it has a special place in all our hearts.
I could make an entire list of real guns modified to be in Star Wars, but maybe that will be something for a later article.
Since I had to choose one, the gun I settled on comes from Star Wars’ most lovable rogue, Han Solo. He shoots first, and he does so with the DL-44 Heavy Blaster Pistol.

This handgun arms our hero through four films, and he clearly has an affection for it.
Also, interestingly enough, Solo’s gun features an optic and muzzle device, like most Gucci pistols in 2021. The DL-44 Heavy blaster pistol hits hard and makes Storm Trooper armor rather useless.
In real life, the Star Wars prop team utilized a Mauser C96 to form the distinctive pistol. The propmaster attached an early 4X optic made for German sniper rifles, a heavy barrel, and the muzzle device from an MG81 machine gun.

Ultimately, the whole package became the gun that Han Solo would wield in many a film, comic, video game, and book.
The Mauser C96 shares the pride of being an early successful semi-auto pistol – the 96 in C96 comes from 1896! This gun originally came in the 7.62 Mauser but later chambered everything from 9mm to 8mm Gasser.
Prices accurate at time of writing
Prices accurate at time of writing
It was used by both sides of World War I — sticking around for decades due to its robust design and reliable nature.
Bears. Beets. Battlestar Galactica. The early 2000s series might easily eclipse the classic series it aimed to remake. This series brought us Edward James Olmos, the Beretta CX4, and Katee Sackoff’s abs to make us feel a little bad about that last Reeses.
It also brought us the Colonial Handgun.

The Colonial Handgun takes some cues from Blade Runner and uses a revolver as its core design. It’s seen in the hands of dozens of characters and appears to be the standard-issue pistol of the Colonials.
This handgun takes a 2.5-inch Smith & Wesson 686 and propels it to the future with a CNC machine aluminum shell.
Prices accurate at time of writing
Prices accurate at time of writing
We get the classic wood grips and DA trigger, but the hammer is fully enclosed, as is the cylinder. The cylinder release has also been removed.
The S&W 686 is one of the more modern .357 Magnum revolvers on the market, and it’s an awesome pistol. Heck, you might even argue it’s the company’s current flagship revolver. It’s a 6-shooter, but a 7-shot plus model exists.

If I needed to carry a revolver on duty, it would likely be this gun.
I love the Terminator series, and as a kid, some of my favorite scenes were of the brutal future war between man and the machine.
We saw more than a few firearms shooting lasers in these short portions, and the unnamed resistance rifle always stuck out to me. We know very little about the weapon but can assume it worked well for killing Terminators.

Kyle Reese mentions that they’d be tough to kill with weapons from the 80s, and the Terminator mentioned a phased plasma rifle in the 40-watt range. So maybe it’s a plasma rifle. What we do know is that it’s a bullpup rifle outfitted with a massive scope.
In reality, the rifle of the Resistance is an AC556, a.k.a. a select-fire version of the Mini 14. The film’s armorers shoved it into a Muzzelite stock that creates a bullpup platform.

On top of the gun is an iMatronic Lasersight LS45. This is not an optic you’ll look through but a massive laser that tossed a simple red dot downrange.
To make it look more optic-like, the armorers added what appears to be eyepieces of some type or another. The combinations of this sight, the stock, and the rifle might make this the most 80s gun ever.
Prices accurate at time of writing
Prices accurate at time of writing
It offered a more traditional alternative to AR-type weapons and used a design very similar to the M14. The Mini 14 series offered a light and semi-auto rifle in .223 that wasn’t the futuristic and not-so-traditional AR-15.
They weren’t known for their accuracy but tended to be robust and handy guns.
If you’ve never handled a Muzzelite stock, don’t worry, you aren’t missing out on anything. They feel exactly how they look. They made trigger abysmal but were a true drop-in design that greatly shortened a Ruger rifle.
You can tell when a sci-fi gun isn’t based on anything real. It’s often an impractical and unergonomic mess that makes no sense from a practical perspective.

The best sci-fi guns are always gun-based on real guns, which adds a certain degree of realism to the sci-fi design.
Plus, if they didn’t use real guns, nerds like me couldn’t pick them apart to an extreme degree.
What’s your favorite fictional gun based on a real gun? Let us know in the comments below! For more movies and guns, check out the Guns of Hollywood: Which Firearms Made Their Mark?
The post Best Sci-Fi Movie Guns That Actually Exist (Kind Of) appeared first on Pew Pew Tactical.
Pew Pew Tactical
https://media.notthebee.com/articles/62ac05c64bf7462ac05c64bf75.jpg
It’s a heated discussion in my history classroom every year. Shortly after the semester break, I share an excerpt from the classic sociological study by Robert and Helen Lynd, "Middletown." The snippet I use depicts the changes that come to the quintessential American town around the turn of the century, with the introduction of the automobile into daily life.
Not the Bee
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtSGP9X7ZodLNSRkNVZJuJbHoWt8KQDCKbpTzzz2TwGL4Sou4qVJvWl1ErbIsa_JstmzGZ0vc-wpm1bnxN7Fys9R6ZktPC_VF_m4ojcbJ_AB0lGORo-vTXKUvaBhzISyDa0Y4KbeD2pWYfBs1MbTSU0odeC01Ral8frU0f2s_pc_oQixTXpOs65JnBdQ/w640-h404/90mimb_c3a06a18c0cf762291a57343244df67e_deb9101f_500.jpg

Gun Free Zone
https://laravelnews.imgix.net/images/saloon-featured.png?ixlib=php-3.3.1
We have all been there, we want to integrate with a 3rd party API in Laravel and we ask ourselves “How should I do this?”. When it comes to API integrations I am no stranger, but still each time I wonder what is going to be the best way. Sam Carré built a package early in 2022 called Saloon that can make our API integrations amazing. This article however is going to be very different, this is going to be a walk through on how you can use it to build an integration, from scratch.
Like all great things it starts with a laravel new and goes from there, so let’s get started. Now when it comes to installing Laravel you can use the laravel installer or composer – that part is up to you. I would recommend the installer if you can though, as it provides easy options to do more than just create a project. Create a new project and open it in your code editor of choice. Once we are there, we can get started.
What are we going to build? I am glad you asked! We are going to be building an integration with the GitHub API to get a list of workflows available for a repo. Now this could be super helpful if you, like me, spend a lot of time in the command line. You are working on an app, you push changes to a branch or create a PR – it goes though a workflow that could be running one of many other things. Knowing the status of this workflow sometimes has a huge impact on what you do next. Is that feature complete? Were there issues with our workflow run? Are our tests or static analysis passing? All of these things you would usually wait and check the repo on GitHub to see the status. This integration will allow you to run an artisan command, get a list of available workflows for a repo, and allow you to trigger a new workflow run.
So by now, composer should have done its thing and installed the perfect starting point, a Laravel application. Next we need to install Saloon – but we want to make sure that we install the laravel version, so run the following inside your terminal:
1composer require sammyjo20/saloon-laravel
Just like that, we are a step closer to easier integrations already. If you have any issues at this stage, make sure that you check both the Laravel and PHP versions you are using, as Saloon requires at least Laravel 8 and PHP 8!
So, now we have Saloon installed we need to create a new class. In Saloons terminology these are “Connectors” and all a connector does is create an object focused way to say – this API is connected through this class. There is a handy artisan command that allows you to create these, so run the following artisan command to create a GitHub connector:
1php artisan saloon:connector GitHub GitHubConnector
This command is split into 2 parts, the first argument is the Integration you are creating and the second is the name of the connector you want to create. This means that you can create multiple connectors for an integration – which gives you a lot of control to connect in many different ways should you need to.
This will have created a new class for you under app/Http/Integrations/GitHub/GitHubConnector.php, let’s have a look at this a moment, and understand what is going on.
The first thing we see is that our connector extends the SaloonConnector, which is what will allow us to get our connector working without a lot of boilerplate code. Then we inherit a trait called AcceptsJson. Now if we look at the Saloon documentation, we know that this is a plugin. This basically adds a header to our requests telling the 3rd party API that we want to Accept JSON responses. The next thing we see is that we have a method for defining the base URL for our connector – so let’s add ours in:
1public function defineBaseUrl(): string
2{
3 return 'https://api.github.com';
4}
Nice and clean, we could even take this a little further so we are dealing with less loose strings hanging around in our application – so let’s look at how we can do that. Inside your config/services.php file add a new service record:
1'github' => [
2 'url' => env('GITHUB_API_URL', 'https://api.github.com'),
3]
What this will do is allow us to override this in different environments – giving us a better and more testable solution. Locally we could even mock the GitHub API using their OpenAPI specification, and test against that to ensure that it works. However, this tutorial is about Saloon so I digress… Now let us refactor our base URL method to use the configuration:
1public function defineBaseUrl(): string
2{
3 return (string) config('services.github.url');
4}
As you can see we are now fetching the newly added record from our configuration – and casting it to a string for type safety – config() returns a mixed result so we want to be strict on this if we can.
Next we have default headers and default config, now right now I am not going to worry about the default headers, as we will approach auth on it’s own in a little while. But the configuration is where we can define the guzzle options for our integration, as Saloon uses Guzzle under the hood. For now let’s set the timeout and move on, but feel free to spend some time configuring this as you see fit:
1public function defaultConfig(): array
2{
3 return [
4 'timeout' => 30,
5 ];
6}
We now have our Connector as configured as we need it for now, we can come back later if we find something we need to add. The next step is to start thinking about the requests we want to be sending. If we look at the API documentation for GitHub Actions API we have many options, we will start with listing the workflows for a particular repository: /repos/{owner}/{repo}/actions/workflows. Run the following artisan command the create a new request:
1php artisan saloon:request GitHub ListRepositoryWorkflowsRequest
Again the first argument is the Integration, and the second argument is the name of the request we want to create. We need to make sure we name the integration for the request we are creating so it lives in the right place, then we need to give it a name. I called mine ListRepositoryWorkflowsRequest because I like a descriptive naming approach – however, feel free to adapt this to how you like to name things, as there is no real wrong way here. This will have created a new file for us to look at: app/Http/Integrations/GitHub/Requests/ListRepositoryWorkflowsRequest.php – let us have a look at this now.
Again we are extending a library class here, this time the SaloonRequest which is to be expected. We then have a connector property and a method. We can change the method if we need to – but the default GET is what we need right now. Then we have a method for defining the endpoint. Refactor your request class to look like the below example:
1class ListRepositoryWorkflowsRequest extends SaloonRequest
2{
3 protected ?string $connector = GitHubConnector::class;
4
5 protected ?string $method = Saloon::GET;
6
7 public function __construct(
8 public string $owner,
9 public string $repo,
10 ) {}
11
12 public function defineEndpoint(): string
13 {
14 return "/repos/{$this->owner}/{$this->repo}/actions/workflows";
15 }
16}
What we have done is add a constructor which accepts the repo and owner as arguments which we can then use within our define endpoint method. We have also set the connector to the GitHubConnector we created earler. So we have a request we know we can send, we can take a small step away from the integration and think about the Console Command instead.
If you haven’t created a console command in Laravel before, make sure you check out the documentation which is very good. Run the following artisan command to create the first command for this integration:
1php artisan make:command GitHub/ListRepositoryWorkflows
This will have created the following file: app/Console/Commands/GitHub/ListRespositoryWorkflows.php. We can now start working with our command to make this send the request and get the data we care about. The first thing I always do when it comes to console commands, is think on the signature. How do I want this to be called? It needs to be something that explains what it is doing, but it also needs to be memorable. I am going to call mine github:workflows as it explains it quite well to me. We can also add a description to our console command, so that when browsing available commands it explains the purpose better: “Fetch a list of workflows from GitHub by the repository name.”
Finally we get to the handle method of our command, the part where we actualy need to do something. In our case we are going to be sending a request, getting some data and displaying that data in some way. However before we can do that, there is one thing we have not done up until this point. That is Authentication. With every API integration, Authentication is one of the key aspects – we need the API to know not only who we are but also that we are actually allowed to make this request. If you go to your GitHub settings and click through to developer settings and personal access tokens, you will be able to generate your own here. I would recommand using this approach instead of going for a full OAuth application for this. We do not need OAuth we just need users to be able to access what they need.
Once you have your access token, we need to add it to our .env file and make sure we can pull it through our configuration.
1GITHUB_API_TOKEN=ghp_loads-of-letters-and-numbers-here
We can now extends our service in config/services.php under github to add this token:
1'github' => [
2 'url' => env('GITHUB_API_URL', 'https://api.github.com'),
3 'token' => env('GITHUB_API_TOKEN'),
4]
Now we have a good way of loading this token in, we can get back to our console command! We need to ammend our signature to allow us to accept the owner and repository as arguments:
1class ListRepositoryWorkflows extends Command
2{
3 protected $signature = 'github:workflows
4 {owner : The owner or organisation.}
5 {repo : The repository we are looking at.}
6 ';
7
8 protected $description = 'Fetch a list of workflows from GitHub by the repository name.';
9
10 public function handle(): int
11 {
12 return 0;
13 }
14}
Now we can turn our focus onto the handle method:
1public function handle(): int
2{
3 $request = new ListRepositoryWorkflowsRequest(
4 owner: $this->argument('owner'),
5 repo: $this->argument('repo'),
6 );
7
8 return self::SUCCESS;
9}
Here we are starting to build up our request by passing the arguments straight into the Request itself, however what we might want to do is create some local variables to provide some console feedback:
1public function handle(): int
2{
3 $owner = (string) $this->argument('owner');
4 $repo = (string) $this->argument('repo');
5
6 $request = new ListRepositoryWorkflowsRequest(
7 owner: $owner,
8 repo: $repo,
9 );
10
11 $this->info(
12 string: "Fetching workflows for {$owner}/{$repo}",
13 );
14
15 return self::SUCCESS;
16}
So we have some feedback to the user, which is always important when it comes to a console command. Now we need to add our authentication token and actually send the request:
1public function handle(): int
2{
3 $owner = (string) $this->argument('owner');
4 $repo = (string) $this->argument('repo');
5
6 $request = new ListRepositoryWorkflowsRequest(
7 owner: $owner,
8 repo: $repo,
9 );
10
11 $request->withTokenAuth(
12 token: (string) config('services.github.token'),
13 );
14
15 $this->info(
16 string: "Fetching workflows for {$owner}/{$repo}",
17 );
18
19 $response = $request->send();
20
21 return self::SUCCESS;
22}
If you ammend the above and do a dd() on $response->json(), just for now. Then run the command:
1php artisan github:workflows laravel laravel
This will get a list of workflows for the laravel/laravel repo. Our command will allow you to work with any public repos, if you wanted this to be more specific you could build up an option list of repos you want to check against instead of accepting arguments – but that part is up to you. For this tutorial I am going to focus on the wider more open use case.
Now the response we get back from the GitHub API is great and informative, but it will require transforming for display, and if we look at it in isolation, there is no context. Instead we will add another plugin to our request, which will allow us to transform responses into DTOs (Domain Transfer Objects) which is a great way to handle this. It will allow us to loose the flexible array we are used to getting from APIs, and get something that is more contextually aware. Let’s create a DTO for a Workflow, create a new file: app/Http/Integrations/GitHub/DataObjects/Workflow.php and add the follow code to it:
1class Workflow
2{
3 public function __construct(
4 public int $id,
5 public string $name,
6 public string $state,
7 ) {}
8
9 public static function fromSaloon(array $workflow): static
10 {
11 return new static(
12 id: intval(data_get($workflow, 'id')),
13 name: strval(data_get($workflow, 'name')),
14 state: strval(data_get($workflow, 'state')),
15 );
16 }
17
18 public function toArray(): array
19 {
20 return [
21 'id' => $this->id,
22 'name' => $this->name,
23 'state' => $this->state,
24 ];
25 }
26}
We have a constructor which contains the important parts of our workflow that we want to display, a fromSaloon method which will transform an array from a saloon response into a new DTO, and a to array method for displaying the DTO back to an array when we need it. Inside our ListRepositoryWorkflowsRequest we need to inherit a new trait and add a new method:
1class ListRepositoryWorkflowsRequest extends SaloonRequest
2{
3 use CastsToDto;
4
5 protected ?string $connector = GitHubConnector::class;
6
7 protected ?string $method = Saloon::GET;
8
9 public function __construct(
10 public string $owner,
11 public string $repo,
12 ) {}
13
14 public function defineEndpoint(): string
15 {
16 return "/repos/{$this->owner}/{$this->repo}/actions/workflows";
17 }
18
19 protected function castToDto(SaloonResponse $response): Collection
20 {
21 return (new Collection(
22 items: $response->json('workflows'),
23 ))->map(function ($workflow): Workflow {
24 return Workflow::fromSaloon(
25 workflow: $workflow,
26 );
27 });
28 }
29}
We inherit the CastsToDto trait, which allows this request to call the dto method on a response, and then we add a castToDto method where we can control how this is transformed. We want this to return a new Collection as there is more than one workflow, using the workflows part of the response body. We then map over each item in the collection – and turn it into a DTO. Now we can either do it this way, or we can do it this way where we build our collection with DTOs:
1protected function castToDto(SaloonResponse $response): Collection
2{
3 return new Collection(
4 items: $response->collect('workflows')->map(fn ($workflow) =>
5 Workflow::fromSaloon(
6 workflow: $workflow
7 ),
8 )
9 );
10}
You can choose what works best for you here. I prefer the first approach personally as I like to step through and see the logic, but there is nothing wrong with either approach – the choice is yours. Back to the command now, we now need to think about how we want to be displaying this information:
1public function handle(): int
2{
3 $owner = (string) $this->argument('owner');
4 $repo = (string) $this->argument('repo');
5
6 $request = new ListRepositoryWorkflowsRequest(
7 owner: $owner,
8 repo: $repo,
9 );
10
11 $request->withTokenAuth(
12 token: (string) config('services.github.token'),
13 );
14
15 $this->info(
16 string: "Fetching workflows for {$owner}/{$repo}",
17 );
18
19 $response = $request->send();
20
21 if ($response->failed()) {
22 throw $response->toException();
23 }
24
25 $this->table(
26 headers: ['ID', 'Name', 'State'],
27 rows: $response
28 ->dto()
29 ->map(fn (Workflow $workflow) =>
30 $workflow->toArray()
31 )->toArray(),
32 );
33
34 return self::SUCCESS;
35}
So we create a table, with the headers, then for the rows we want the response DTO and we will map over the collection returned, casting each DTO back to an array to be displayed. This may seem counter intuative to cast from a response array to a DTO and back to an array, but what this will do is enforce types so that the ID, name and status are always there when expected and it won’t give any funny results. It allows consistency where a normal response array may not have it, and if we wanted to we could turn this into a Value Object where we have behaviour attached instead. If we now run our command we should now see a nice table output which is easier to read than a few lines of strings:
1php artisan github:workflows laravel laravel
1Fetching workflows for laravel/laravel
2+----------+------------------+--------+
3| ID | Name | State |
4+----------+------------------+--------+
5| 12345678 | pull requests | active |
6| 87654321 | Tests | active |
7| 18273645 | update changelog | active |
8+----------+------------------+--------+
Lastly, just listing out these workflow is great – but let’s take it one step further in the name of science. Let’s say you were running this command against one of your repos, and you wanted to run the update changelog manaually? Or maybe you wanted this to be triggered on a cron using your live production server or any event you might think of? We could set the changelog to run once a day at midnight so we get daily recaps in the changelog or anything we might want. Let us create another console command to create a new workflow dispatch event:
1php artisan saloon:request GitHub CreateWorkflowDispatchEventRequest
Inside of this new file app/Http/Integrations/GitHub/Requests/CreateWorkflowDispatchEventRequest.php add the following code so we can walk through it:
1class CreateWorkflowDispatchEventRequest extends SaloonRequest
2{
3 use HasJsonBody;
4
5 protected ?string $connector = GitHubConnector::class;
6
7 public function defaultData(): array
8 {
9 return [
10 'ref' => 'main',
11 ];
12 }
13
14 protected ?string $method = Saloon::POST;
15
16 public function __construct(
17 public string $owner,
18 public string $repo,
19 public string $workflow,
20 ) {}
21
22 public function defineEndpoint(): string
23 {
24 return "/repos/{$this->owner}/{$this->repo}/actions/workflows/{$this->workflow}/dispatches";
25 }
26}
We are setting the connector, and inheriting the HasJsonBody trait to allow us to send data. The method has been set to be a POST request as we want to send data. Then we have a constructor which accepts the parts of the URL that builds up the endpoint. Finally we have dome default data inside defaultData which we can use to set defaults for this post request. As it is for a repo, we can pass either a commit hash or a branch name here – so I have set my default to main as that is what I usually call my production branch. We can now trigger this endpoint to dispatch a new workflow event, so let us create a console command to control this so we can run it from our CLI:
1php artisan make:command GitHub/CreateWorkflowDispatchEvent
Now let’s fill in the details and then we can walk through what is happening:
1class CreateWorkflowDispatchEvent extends Command
2{
3 protected $signature = 'github:dispatch
4 {owner : The owner or organisation.}
5 {repo : The repository we are looking at.}
6 {workflow : The ID of the workflow we want to dispatch.}
7 {branch? : Optional: The branch name to run the workflow against.}
8 ';
9
10 protected $description = 'Create a new workflow dispatch event for a repository.';
11
12 public function handle(): int
13 {
14 $owner = (string) $this->argument('owner');
15 $repo = (string) $this->argument('repo');
16 $workflow = (string) $this->argument('workflow');
17
18 $request = new CreateWorkflowDispatchEventRequest(
19 owner: $owner,
20 repo: $repo,
21 workflow: $workflow,
22 );
23
24 $request->withTokenAuth(
25 token: (string) config('services.github.token'),
26 );
27
28 if ($this->hasArgument('branch')) {
29 $request->setData(
30 data: ['ref' => $this->argument('branch')],
31 );
32 }
33
34 $this->info(
35 string: "Requesting a new workflow dispatch for {$owner}/{$repo} using workflow: {$workflow}",
36 );
37
38 $response = $request->send();
39
40 if ($response->failed()) {
41 throw $response->toException();
42 }
43
44 $this->info(
45 string: 'Request was accepted by GitHub',
46 );
47
48 return self::SUCCESS;
49 }
50}
So like before we have a signature and a description, our signature this time has an optional branch incase we want to override the defaults in the request. So in our handle method, we can simple check if the input has the argument ‘branch’ and if so, we can parse this and set the data for the request. We then give a little feedback to the CLI, letting the user know what we are doing – and send the request. If all goes well at this point we can simply output a message informing the user that GitHub accepted the request. However if something goes wrong, we want to throw the specific exception, at least during develoment.
The main caveat with this last request is that our workflow is set up to be triggered by a webhook by adding a new on item into the workflow:
1on: workflow_dispatch
That is it! We are using Saloon and Laravel to not only list repository workflows, but if configured correctly we can also trigger them to be ran on demand :muscle:
As I said at the beginning of this tutorial, there are many ways to approach API integrations, but one thing is for certain – using Saloon makes it clean and easy, but also quite delightful to use.
Laravel News