Legacy to Laravel: How to Modernize an Aging PHP Application

Legacy to Laravel: How to Modernize an Aging PHP Application

https://ift.tt/3gte7Kg


Here at Tighten, we love Laravel and get excited about staying up to date with the latest and greatest features our framework of choice has to offer. Who among us doesn’t get excited by typing laravel new, watching Composer wave in the latest packages like a third base coach, and then wading through fields of green as we are prompted to Build something amazing.

But let’s face it—as our industry ages and the number of legacy apps grows, we often find ourselves wrestling with outdated code while hopes of using the latest features demoed at Laracon fade away like a distant dream.

It can be tempting to want to rebuild legacy apps from scratch, but if you’ve ever tried it on an app of significant complexity you know it can be a trap. Apps that have existed in production for a long time generally meet the customers’ needs well enough to keep businesses afloat and are complex for a reason: they’re often the only source of truth about business requirements when the original stakeholders and developers have long since moved on. Complexity grows over time as apps expand to handle more edge cases, and tearing down years of work introduces unnecessary risks while often taking years of its own to complete.

The good news is, you don’t have to completely rewrite your legacy app to start using new Laravel features today! In this post, I’ll present some strategies we use at Tighten to convert legacy apps to Laravel gradually over time, without needing to perform a full rewrite. Whether you’re upgrading from an old framework or moving to a framework for the first time, following these steps will let you start benefitting from all that Laravel has to offer right away.

Install a New Laravel App

First we’ll start with a clean slate by installing a new Laravel app. If you don’t already have the Laravel installer, you can find instructions on how to install it here. Once you have the installer, run the following command in your terminal to install a new Laravel app:

laravel new upgrade-to-laravel

Move the New Laravel App Into the Legacy App

Next we’re going to move the contents of the new Laravel installation into our legacy app, and drop our legacy app down one directory into a legacy folder. Then we’ll set Laravel up to handle all incoming requests and pass any requests that don’t have defined routes through to the legacy app. This will also maintain the legacy app’s version control history.

  1. Create a new legacy directory inside of the legacy app
  2. Move the legacy app’s folders containing PHP files from the top level to the legacy folder
  3. Move all of the files and folders from the Laravel installation into the root folder of the legacy app
  4. Add the following legacy catch-all route to your Laravel app, at the bottom of routes/web.php:
Route::any('{path}', 'LegacyController@index')->where('path', '.*');
  1. Create a legacy controller with the following method:
public function index()
{
    ob_start();
    require app_path('Http') . '/legacy.php';
    $output = ob_get_clean();

    // be sure to import Illuminate\Http\Response
    return new Response($output);
}

Most legacy apps use echo to display their content, so the calls to ob_start() and ob_get_clean() allow us to capture that output into the $output variable using output buffering, so we can wrap it in a Laravel response.

  1. Create a new file at app/Http/legacy.php with the following:
// This is assuming the entry point to the legacy app is at `legacy/index.php`
require __DIR__.'/../../legacy/index.php';
  1. Depending on the configuration of the legacy app, the old entry point may need to be changed to account for being one level lower in the directory tree. For example, in a CodeIgniter 3.0 install, $system_path = 'system'; in index.php will need to be changed to $system_path = '../legacy/system';.

    Depending how the frontend is set up we may also need to move legacy frontend assets to Laravel’s public directory and ensure the legacy files that require them are referencing them with the correct path.

Once all of the files are in place and paths have been updated we should be able to visit our app in the browser and see our legacy app’s home page, which means it is running inside of the Laravel app!

Spring Cleaning

Now that we have our legacy app running through Laravel, it’s a good time to focus on a few important maintenance principles.

First, it is common for older apps to contain commented-out code or code that is unreachable and can’t possibly run. Before any code is moved to Laravel or refactored, it’s a good idea to first ensure that the code is actually in use so no one is wasting any time converting unused code. Any code that is commented out or confirmed to be unreachable should be deleted. As long as the app is under version control, we can always retrieve that code later if we need to.

Second, we may run across configuration settings inside the legacy app that would be better suited for a config file (located in /config) and then referenced with the config helper. Any security keys, or other sensitive settings that should not be committed to version control should be moved to an environment variable in the gitignored .env file and then added (with blank values) to .env.example. Once a setting has been moved to .env, we can also define it in a config file so references to environment variables are limited to the /config directory and Laravel will be able to cache our configs for better performance in production.

Testing the Home Page

Let’s imagine there are no existing tests for the legacy app. You are reasonably confident that everything works but the process of transforming the app introduces risk that things could break. We can use Laravel’s built-in testing features to ensure the app continues to work.

Let’s create a test for the home page by running the following in the terminal:

php artisan make:test HomePageTest

Now lets add a test that ensures the homepage loads successfully:

public function testExample()
{
    // the entry point to the legacy app
    $response = $this->get('/');

    // replace 'welcome' with a string on the home page
    $response->assertStatus(200)
        ->assertSee('Welcome');
}

At this point if all goes well we will see a passing test—but in our experience, there are a number of things that will cause simple tests like this to fail after a conversion.

PHP Superglobals

If the legacy code is referencing superglobals like $_REQUEST or $_SERVER, they should be changed to use Laravel’s request helper instead. References to $_REQUEST['some_param'], $_GET['some_param'], and $_POST['some_param'] can be changed to request('some_param') and references to $_SERVER['some_prop'] can be changed to request()->server('some_prop').

Global Variables

Any tests that run code referencing a global variable will fail if the test doesn’t first run the code where the variable is initialized. This can often be solved by moving the declaration of the global variable to app/Http/legacy.php, but usually the best option is to get rid of the global variable entirely and move it either to a config file (if it’s a simple value) or to Laravel’s Service Container (if it’s an object).

CSRF Tokens

By default, Laravel protects all form submissions with CSRF token verification via the VerifyCsrfToken middleware in the web route group defined in (app/Http/Kernel.php). In order to take advantage of the extra security CSRF tokens offer, we will need to include a CSRF token in each of our form submissions/POST requests. The csrf_field() helper method will generate a hidden input that does this.

However, if the legacy app contains more than a few forms we may want to temporarily disable the VerifyCsrfToken middleware on the legacy routes while we update our forms to include the token. Rather than simply commenting out the VerifyCsrfToken middleware—which would also disable it for any new routes—we can create a new legacy route group that uses the same middleware as the web group, but without VerifyCsrfToken.

To make a new legacy route group that excludes the CSRF middleware, we first need to define the route group in app/Http/Kernel.php as follows:

// within $middlewareGroups below 'web'
'legacy' => [
    \App\Http\Middleware\EncryptCookies::class,
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \Illuminate\Session\Middleware\StartSession::class,
    // \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

Next, we will move our legacy route to app/routes/legacy.php:

// app/routes/legacy.php
Route::any('{path}', 'LegacyController@index')->where('path', '.*');

Finally, we need to register the legacy route file by editing app/Providers/RouteServiceProvider.php as follows:

public function map()
{
    $this->mapApiRoutes();
    $this->mapWebRoutes();
    // Add this line to the map() method
    $this->mapLegacyRoutes();
}

// Add this method to the end of the class
protected function mapLegacyRoutes()
{
    Route::middleware('legacy')
         ->namespace($this->namespace)
         ->group(base_path('routes/legacy.php'));
}

Now our legacy forms will continue to work as they did before, without Laravel’s CSRF protection, while any new form submission routes can be defined in routes/web.php like normal and take full advantage of the security CSRF tokens provide.

Migrating to Eloquent

If your legacy app has a very complex data access layer, the idea of migrating all of that DB logic to Laravel’s Eloquent ORM may sound daunting. In order to ease this pain and minimize risk, we’ll break this process up into two steps:

Gathering Database Code

Generally, the data access layer will contain code with two responsibilities:

  1. Fetching or modifying data from the database
  2. Acting on data fetched from the database

These responsibilities might be encapsulated in model classes, or they might be scattered throughout the code base—or anywhere in between. We want to resist the urge to refactor this code in-place and instead focus on centralizing it, deferring the refactoring step until later. Separating these two steps helps build a stronger mental model of what the code is responsible for, and reduces duplication upfront. We also don’t want to clutter our brand new Eloquent models with code we know will need to be refactored. Instead, we will gather this database code in classes that sit between the Eloquent models and the rest of the codebase. We will call these classes Eloquent Shims.

Let’s say there is an items table, and code throughout the codebase is responsible for fetching one or more rows and performing operations on each item. Let’s start gathering this database code into an Eloquent Shim.

  1. First we’ll need to create the Eloquent model for the items table.
php artisan make:model Item
  1. Next we’ll create our Eloquent Shim file at app/EloquentShims/ItemShim.php:
<?php

namespace App\EloquentShims;

class ItemShim
{
    protected $item;

    public function __construct($item)
    {
        $this->item = $item;
    }
}

Now we’re ready to gather the database code inside the new shim class. Imagine we have the following code:

// Inside a controller method
$items = OldItemModel::getFutureItems();

// OldItemModel.php
public static function getFutureItems()
{
    // database query
}

First we’ll replace the controller code with the following:

$items = ItemShim::getFutureItems();

Then we’ll move the getFutureItems method from the OldItemModel class to our new ItemShim.

// ItemShim
public static function getFutureItems()
{
    // database query
}

We can continue gathering more database code into the shim classes in a similar manner. For example, when we encounter code that fetches a single record by ID, we can find that item using Eloquent inline and instantiate the shim with it like so:

$item = new ItemShim(Item::find(123));

Any methods called on the $item object can now be moved from OldItemModel to ItemShim.

Refactoring the Shim Code

Once we are ready to move on to the refactoring phase we can focus our efforts on adding enough code to our Eloquent model to eliminate the need for the shim. Back to the earlier example, we have this method now in our shim class:

// ItemShim
public static function getFutureItems()
{
    // database query
}

It might contain any amount of logic, but let’s imagine it contains a raw SQL query that simply fetches the future items from the database. Following Laravel conventions, we will want to implement a future query scope in our Item Eloquent model so we can refactor the body of the getFutureItems method to the following:

// ItemShim
public static function getFutureItems()
{
    return Item::future()->get();
}

At this point our Eloquent model contains enough logic that the shim’s getFutureItems method is no longer needed. We can replace the call to the shim in the controller method with Eloquent directly.

$items = Item::future()->get();

Once all calls to getFutureItems have been replaced with the Eloquent query we can delete the getFutureItems shim method. We can then repeat this process until the shim contains no methods, and then we can delete the shim class entirely.

Stopping Execution Early

Legacy PHP applications often have calls to die or exit that immediately stop execution in place. This will interfere with Laravel’s request/response cycle, break extensions like Laravel Telescope, and prevent LegacyController from returning a response. The app might continue working as intended, but any attempts to write PHPUnit tests covering this code will fail because the PHP process will stop early—none of our assertions will run, and the test suite will come to a halt.

One solution that will preserve existing functionality while allowing PHP to continue execution is to remove these die and exit calls and throw/catch an exception instead. In order to generate an exception that we can consistently catch, we’ll create a new file at app/Exceptions/LegacyExitScript.php with the following:

namespace App\Exceptions;

use Exception;

class LegacyExitScript extends Exception
{

}

Then we’ll update our LegacyController@index method to catch these exceptions and finish the request (don’t forget to import the LegacyExitScript exception!):

public function index()
{
    try {
        ob_start();
        require public_path() . '/legacy.php';
        $output = ob_get_clean();
    } catch (LegacyExitScript $e) {
        $output = ob_get_clean();
    }

    return new Response($output);
}

Now we can replace calls to die and exit with the following:

throw new LegacyExitScript;

If there are too many of these calls to reasonably test while replacing them with the LegacyExitScript exception, it may be a better idea to make these changes over time, while covering them with PHPUnit tests, rather than all at once.

Laravel Views

We want to make sure our application continues to meet our customers’ needs during its transition to a Laravel app, but we are also eager to take advantage of Laravel’s features. Business rules might dictate that we need to render a new page from an existing code path, or perhaps we need to modify an existing page and using a Laravel view would make the task much easier. Migrating an entire route or code path to a Laravel controller might be prohibitively time consuming, but there’s another solution! We can take advantage of the structure we put in place for our LegacyExitScript exception by throwing a view. Let’s create a new file app/Exceptions/LegacyView.php:

namespace App\Exceptions;

use Exception;
use Illuminate\View\View;

class LegacyView extends Exception
{
    protected $view;

    public function __construct(View $view)
    {
        $this->view = $view;
    }

    public function getView()
    {
        return $this->view;
    }
}

We will need to catch this exception in LegacyController@index in order to return the view as a response:

public function index()
{
    try {
        ob_start();
        require public_path() . '/legacy.php';
        $output = ob_get_clean();
    } catch (LegacyExitScript $e) {
        $output = ob_get_clean();
    } catch (LegacyView $e) {
        return $e->getView();
    }

    return new Response($output);
}

We could throw the LegacyView exception inline anywhere we want to call the view, but to make the calls a bit less verbose we can add a global helper method:

function legacy_view($view = null, $data = [], $mergeData = [])
{
    throw new App\Http\LegacyView(
        view($view, $data, $mergeData)
    );
}

Our global function uses the same method signature as Laravel’s view helper, and takes care of throwing the LegacyView exception for us. Now anywhere in the legacy code that we want to stop execution and render a Laravel view we can just call our new helper method:

legacy_view('items.index', ['items' => $items]);
// anything below won't be executed

Throwing a view wrapped in an exception like this may be unconventional but remember, we’re not aiming for perfection on the first pass. Much like our Eloquent shims above, the LegacyView exception is a stepping stone towards a maintainable app. One reason we prepend these functions/classes with legacy is that they are designed to be a temporary solution. Once the app no longer needs them, they should be removed.

Generating Database Migrations

Whether or not the legacy app’s database was generated by migrations, we’re going to want to be able to use Laravel migrations going forward. In order to support running php artisan migrate in a new development environment or on an empty database, we’ll need to generate migration files from the existing database schema. At the time of writing, the oscarafdev/migrations-generator package is one of the easier ways to accomplish this.

Helper Methods

Often when moving pieces of legacy code to Laravel classes, we come across legacy code referencing a helper method that was previously included, but is now undefined when called from the new location. We want to make sure all of our helper methods are available to new code written (or moved to) Laravel, as well as the original legacy app. To do this we can set up a legacy helper file to be autoloaded globally so its methods are made available to the entire app.

Let’s create a new helper file at app/helpers/legacy.php, then autoload it in the "files" key of composer.json:

// Add this to the "autoload" property below "classmap"
"files": [
    "app/helpers/legacy.php"
]

Once we run composer dump-autoload in the terminal, any method we define in app/helpers/legacy.php will be made available globally. Now that we have an easy place to put these methods, each time we run across a helper being called from code we have moved into Laravel we can simply move the referenced method from its legacy location into app/helpers/legacy.php.

Legacy Path Helper

Now that we have a good place to put legacy related helper methods, we can start adding new helper methods for common pieces of code in the legacy app. For example, legacy apps usually contain quite a few include and require statements to import other files. Ideally the paths given will be relative paths so they will continue to work as is, but sometimes full paths are used. In situations like these we might find ourselves needing to reference the new path to the legacy app subfolder. We can make this a bit easier on ourselves by adding a legacy_path helper method to the new app/helpers/legacy.php file:

function legacy_path($path = null)
{
    return base_path('legacy/' . $path);
}

Converting Native PHP Sessions

Most legacy apps make use of native PHP sessions, but the degree to which sessions are relied on may vary widely. Sessions can be used for anything from simply managing user authentication to storing data from every request. Ultimately most people will want to convert their native session data to Laravel sessions—there are a few different strategies that can be used.

Search and Replace

If the app can reliably be tested (either by manual or automated tests), the easiest way to convert the sessions is to perform multiple search and replace calls across the app. Below is an example of using regex to convert setting session values from a native PHP session to a Laravel session.

// find: \$_SESSION\[(.+)] = (.+);
// replace: session([$1 => $2]);

// before
$_SESSION['foo'] = 'bar';

// after
session(['foo' => 'bar']);

Convert by Route

Another strategy is to convert native PHP session usage to Laravel only while moving functionality from the legacy app to newly defined Laravel routes. This strategy would mean fewer session variables need to be converted at once (the native and Laravel sessions will exist simultaneously) but when a session variable is converted, a search should still be performed to convert any other references to that same session variable elsewhere in the legacy app.

In Closing

Legacy apps come in all shapes and sizes, so your specific app might require custom changes or configuration we didn’t cover here. However, we hope these steps can serve as a baseline strategy for transforming a legacy PHP app into a Laravel app without having to undergo a full rewrite—and allow you to start using Laravel features immediately. Laravel is designed to make us happier and more productive developers, so there’s no reason we can’t continue supporting our legacy apps while taking advantage of all that our favorite framework has to offer!

programming

via Laravel News Links https://ift.tt/2dvygAJ

August 6, 2020 at 08:24PM

Spatie Laravel Multi-Tenancy without Sub Domain (customize TenantFinder)

Spatie Laravel Multi-Tenancy without Sub Domain (customize TenantFinder)

https://ift.tt/2PpJt8I


Spatie Laravel Multi-Tenancy without Sub Domain (customize TenantFinder)

Recently Spatie released a brand new package for multi-tenancy called laravel-multitenancy.

It comes with great support to work out of the box with sub-domains like,

https://zluck.infychat.com

https://infyom.infychat.com

https://vasundhara.infychat.com

It identified the tenant based on the sub-domain and sets a database runtime for your tenant-specific models.

Recently, we used it in one of our client for Snow Removal CRM. Here we have two models,

  1. Freemium Model – with no sub-domain (application will work on main domain only)
  2. Premium Model – where the tenant will get its subdomain

And user can convert his account from Freemium to Premium at any point of time by just subscribing to the plan.

So what we want is, on the backend, we want to have a separate database for each tenant, but the application should run on main as well as a sub-domain.

So what we want to have is the ability to extend/customize the tenant detection mechanism. And Spatie does a very good job at there where you can customize the logic.

You can create your own TenantFinder class and configure it in the config file of the package. And there is very good documentation for that here: https://docs.spatie.be/laravel-multitenancy/v1/installation/determining-current-tenant/

To do that, what we did is, we have a field called tenant_id in our users table. All of our users are stored into the main database since we may have user access across the tenant.

And when any user does a login, we listen for the event Illuminate\Auth\Events\Login which is documented in Laravel Docs over here.

When a user does a login, our listener will be called and will create a cookie called tenant on the browser with the tenant id of the user. So our listener will look like,

<?php

namespace App\Listeners;

use App\Models\User;
use Cookie;
use Illuminate\Auth\Events\Login;

class LoginListener
{
    public function handle(Login $event)
    {
        /** @var User $authUser */
        $authUser = $event->user;

        Cookie::forget('tenant');
        Cookie::queue(Cookie::forever('tenant', encrypt($authUser->tenant_id)));
    }
}

Also, we encrypt the cookie on our end, so we do not want Laravel to encrypt it again, so we added tenant cookie into except array of EncryptCookies middleware as per documentation here. so our middleware looks like,

<?php

namespace App\Http\Middleware;

use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;

class EncryptCookies extends Middleware
{
    /**
     * The names of the cookies that should not be encrypted.
     *
     * @var array
     */
    protected $except = [
        'tenant'
    ];
}

Now at the last point, we extended our logic to find a tenant and get it to work on the main domain as well as sub-domain.

We have created our own custom class called InfyChatTenantFinder, which looks like,

<?php

namespace App\TenantFinder;

use App\Models\Account;
use App\Models\SubDomain;
use Illuminate\Http\Request;
use Spatie\Multitenancy\Models\Concerns\UsesTenantModel;
use Spatie\Multitenancy\Models\Tenant;
use Spatie\Multitenancy\TenantFinder\TenantFinder;

class InfyChatTenantFinder extends TenantFinder
{
    use UsesTenantModel;

    public function findForRequest(Request $request): ?Tenant
    {
        $host = $request->getHost();

        list($subDomain) = explode('.', $host, 2);

        // Get Tenant by subdomain if it's on subdomain
        if (!in_array($subDomain, ["www", "admin", "infychat"])) {
            return $this->getTenantModel()::whereDomain($host)->first();
        }

        // Get Tenant from user's account id if it's main domain
        if (in_array($subDomain, ["www", "infychat"])) {

            if ($request->hasCookie('tenant')) {
                $accountId = $request->cookie('tenant');

                $accountId = decrypt($accountId);

                $account = $this->getTenantModel()::find($accountId);

                if (!empty($account)) {
                    return $account;
                }

                \Cookie::forget('tenant');
            }
        }

        return null;
    }
}

So basically, first we check if the sub-domain is there, then find tenant from the sub-domain.

If the domain is the main domain then get the tenant id from the cookie and return the account (tenant) model.

So this is how you can customize the logic the way you want to have a custom tenant identification system.

programming

via Laravel News Links https://ift.tt/2dvygAJ

August 5, 2020 at 08:48PM

MySQL from a Developers Perspective

MySQL from a Developers Perspective

https://ift.tt/33qZjIk

So this has turned into a small series, explaining how to work with MYSQL
from a developers perspective. This post is intended as a directory for the
individual articles. It will be amended and re-dated as necessary.

The code for the series is also available in
isotopp/mysql-dev-examples
on GitHub.

The Tag #mysqldev will
reference all articles from this series.

  • MySQL Transactions – the physical side.
    Looking at how MySQL InnoDB handles transactions on the physical media, enabling rollback and commit. Introduces a number of important concepts: The Undo Log, the Redo Log, the Doublewrite Buffer, and the corrosponding in memory structures, the Log Buffer and the InnoDB Buffer Pool, as well as the concept of a page.

  • MySQL Commit Size and Speed.
    This article has code in Github, in mysql-commit-size/. We benchmark MySQL write speed as a function of number of rows written per commit.

  • MySQL Connection Scoped State.
    Looking at things that are stateful and attached to a MySQL connection, and are lost on disconnect.

  • MySQL Transactions – the logical view.
    This article introduces the concept of TRANSACTION ISOLATION LEVEL and how pushing things into the Undo Log, while a necessity to implement ROLLBACK for a Writer, enables features for a Reader.

  • MySQL Transactions – writing data.
    This article has code in Github, in mysql-transactions-counter. We increment a counter in the database, with multiple concurrent writers, and see what happens.

  • MySQL: Locks and Deadlocks.
    When changing multiple rows, it is possible to take out locks in transactions one by one. Depending on how that is done, it may come to deadlocks, and server-initiated rollbacks. When that happens, the transaction must be retried.

  • MySQL Deadlocks with INSERT
    When using the obscure transaction isolation level SERIALIZABLE, it may happen that a single INSERT can deadlock. Here is how, and why.

  • MySQL Foreign Keys and Foreign Key Constraints
    When establishing relationships between tables, you are doing this by putting one tables primary keys into another tables columns. Enforcing valid pointers between tables seems like a sexy idea, but is painful, and maybe hurts more than it helps.

  • MySQL Foreign Key Constraints and Locking
    Looking at tables with foreign key constraints, we check what happens to table and row locks, and how this is different from before.

technology

via Planet MySQL https://ift.tt/2iO8Ob8

August 4, 2020 at 11:17AM

How To Import/Export CSV Data Using MySQLi and PHP 7

How To Import/Export CSV Data Using MySQLi and PHP 7

https://ift.tt/3ft9jDk

This tutorial help to import the csv data into MySQL and export data from MySQL to csv file.The CSV file is used to import and export data for moving/exchange data information between web application.You can use rest api or web application to import/export CSV data. The web application data is stored, accessed and exchanged between […]

The post How To Import/Export CSV Data Using MySQLi and PHP 7 appeared first on Phpflow.com.

technology

via Planet MySQL https://ift.tt/2iO8Ob8

August 3, 2020 at 11:47AM

Cool things you can do with Laravel Form Requests

Cool things you can do with Laravel Form Requests

https://ift.tt/3fbjnAF


Form requests are often used for validation purposes only, but they can do a whole lot more. You can manipulate data before and after validation, and you can easily add methods of your own.

In this video I’ll demonstrate all these possiblities.

Want to see more videos like this one? Head over to the Readable Laravel video series on our website.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

programming

via Laravel News Links https://ift.tt/2dvygAJ

August 2, 2020 at 08:15PM

Imperial Medieval March

Imperial Medieval March

https://ift.tt/33cap3L

Imperial Medieval March

Link

No, I am Thy Father. Musician Samuel Kim has been building a library of Star Wars tracks reimagined in a medieval style. Among the collection is this version of John Williams’ Imperial March that feels right at home among the knights and castles.

fun

via The Awesomer https://theawesomer.com

July 31, 2020 at 08:00AM

Laravel PDF export tutorial

Laravel PDF export tutorial

https://ift.tt/33a1jVq


Exporting PDF by the web application is an important feature. We need PDF of the customer list, invoice, balance sheet or any other data report. By Laravel and barryvdh/laravel-dompdf package, we can easily generate dynamic PDF from our application. DomPDF can make HTML to PDF and it supports CSS 2.1 compliant HTML layout. The laravel dompdf package is a wrapper package of PHP Dompdf package. With that, we can easily convert our view to PDF. In this post, I’ll show you a step by step process on how to make PDF in Laravel application using the barryvdh/laravel-dompdf package.

 

Laravel PDF generation

Here, I’ll show you the process of making a PDF for a customer list. According to this strategy, you can make your won custom dynamic PDF by your laravel application.

Note: This post is not a version-specific. Following this tutorial post, you can generate PDF by Laravel 5/6/7. 

 

Step 01: Install the barryvdh/laravel-dompdf package.

composer require barryvdh/laravel-dompdf

Add these in config/app.php file.

add in the providers array

Barryvdh\DomPDF\ServiceProvider::class,

add in the aliases array

'PDF' => Barryvdh\DomPDF\Facade::class,

 

Step 02: Make a customer model.

php artisan make:model Customer -m
<?php

namespace App;
use Illuminate\Database\Eloquent\Model;

class Customer extends Model {

    public $fillable = ['name', 'email', 'phone', 'dob'];

}

 

Step 03: Migration Create and run the migration.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCustomersTable extends Migration
{
    
    public function up()
    {
        Schema::create('customers', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('email');
            $table->string('phone');
            $table->string('dob');
            $table->timestamps();
        });
    }

    
    public function down()
    {
        Schema::dropIfExists('customers');
    }
}

Now run the migration by php artisan migrate command.

 

Step 04: Define a route.

Route::get('admin/customers','CustomerController@index');

 

Step 05: Make a customer controller.

php artisan make:controller CustomerController

Now do the code for showing report and generating the PDF of that report.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Customer;
use PDF;

class CustomerController extends Controller
{
    public function index(Request $request)
    {
        $data = Customer::all();

        if ($request->has('export')) {
            if ($request->get('export') == 'pdf') {
                $pdf = PDF::loadView('customers.index-pdf', compact('data'));
                return $pdf->download('customer-list.pdf');
            }
        }

        return view('customers.index', compact('data'));
    }
}

Here, we’ll show the custom report with customers/index.blade.php view and export pdf with the customers/index-pdf.blade.php view when the user clicks on export pdf button from report view.

 

Step 6: Make the report and PDF view.

Report view – customers/index.blade.php

@extends('admin.template')
@section('content')

	<div class="container mt-5">
		<div class="d-flex justify-content-between mb-2">
	        <p><strong>Customer List</strong></p>
	        <a class="btn btn-primary" href="">Export to PDF</a>
	    </div>

	    <table class="table table-bordered mb-5">
	        <thead>
	            <tr>
	                <th scope="col">Name</th>
	                <th scope="col">E-mail</th>
	                <th scope="col">Phone</th>
	                <th scope="col">DOB</th>
	            </tr>
	        </thead>
	        <tbody>
	            @foreach($data as $row)
	            <tr>
	                <td></td>
	                <td></td>
	                <td></td>
	                <td></td>
	            </tr>
	            @endforeach
	        </tbody>
	    </table>
	</div>
@endsection

customer-list.png

 

PDF view – customers/index-pdf.blade.php

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Laravel PDF</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
  </head>
  <body>
    <h2 class="mb-3">Customer List</h2>
    <table class="table table-bordered">
    <thead>
      <tr>
        <th>Name</th>
        <th>E-mail</th>
        <th>Phone</th>
        <th>DOB</th>
      </tr>
      </thead>
      <tbody>
        @foreach ($data as $row)
        <tr>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        @endforeach
      </tbody>
    </table>
  </body>
</html>

 

Hopefully, this step by step tutorial post will help you to learn how to generate dynamic PDF in the Laravel framework. If you find this post helpful then please share it with others.

programming

via Laravel News Links https://ift.tt/2dvygAJ

July 30, 2020 at 09:27AM

MySQL audit logging using triggers

MySQL audit logging using triggers

https://ift.tt/332iUP3

Introduction In this article, we are going to see how we can implement an audit logging mechanism using MySQL database triggers to store the old and new row states in JSON column types. Database tables Let’s assume we have a library application that has the following two tables: The book table stores all the books that are found in our library, and the book_audit_log table stores the CDC (Change Data Capture) events that happened to a given book record via an INSERT, UPDATE, or DELETE DML statement. The book_audit_log table is created… Read More

The post MySQL audit logging using triggers appeared first on Vlad Mihalcea.

technology

via Planet MySQL https://ift.tt/2iO8Ob8

July 29, 2020 at 10:43AM

[Guide] How To Shoot a Pistol One Handed: Tips, Tricks, & Drills

[Guide] How To Shoot a Pistol One Handed: Tips, Tricks, & Drills

https://ift.tt/2P78JjZ

We all start our shooting lives using both hands to hold the gun.

Once we’ve mastered the fundamentals and are well on our way to sharpening those skills into something above-average, though, it’s time to move on.

pew pew Glock 20
Hadouken

Enter one-handed shooting. Learning to run your gun with one hand isn’t a cool trick or something you do out of boredom it’s a useful ability that might one day save your life.

Here’s how to do it and a little more why.

Table of Contents

Loading…

Self-Defense

The realities of self-defense include the fact you cannot control how a fight for your life will go down.

Maybe you’ll have time to draw your holstered gun and get on target with two hands.

Collateral, Mozambique Drill
Collateral, Mozambique Drill

Maybe not.

Perhaps you’ll be standing solidly on two feet (probably not). It’s highly unlikely you’ll have time for Isosceles or Weaver or Chapman.

The threat will present itself and you’ll have seconds to react. It’ll probably be over as quickly as it started and you will have only your training to get you through it. 

You’re likely to need to aim and fire your gun one-handed in a self-defense scenario. You might be able to get a firm two-handed grip, but don’t count on it.

When was the last time you trained drawing and firing from your knees?

You also cannot depend on hip shooting or pure dumb luck to get you through it. Practice is, as always, the answer to shooting dilemmas.

Stance

It might seem counter-intuitive to work on stance with your one-handed SHTF shooting but it isn’t. It’s logical.

The more you train doing something the greater the possibility you’ll automatically do it under pressure. When shooting one-handed put your gun hand foot forward.

That means if you’re shooting with your right hand, put your right foot forward, and vice versa. Shift your weight forward onto that foot, leaving some bend in your knee, but keep your rear foot firmly grounded.

A solid base is important for accurate, safe shooting. 

Thumbs

Make a fist. Is your thumb folded down over your fingers or sticking up in the universal thumbs-up gesture?

Try raising your thumb skyward and squeeze your fist closed. Now lower your thumb partway so it’s pointed straight out alongside your pointer finger.

8. Handgun High Grip
One-handed handgun grip

Squeeze. Finally, drop your thumb down where it probably was originally, folded down over your fingers. Squeeze again. Which thumb position gave you the strongest grip?

Thumb down. When you’re shooting one-handed you’ll be gripping the gun with your thumb down regardless of which hand you’re using. It gives you the firmest grip and enhances accuracy.

That Other Arm

There are a few schools of thought about what to do with your other hand when you’re firing with only one hand.

Some say you should press the flat of your hand – or your fist – to your abdomen; some say to just let your arm hang at your side. My personal preference is the Shotokan Punch method used by Massad Ayoob.

pew pew Glock 20
Shooting my Glock 20 10mm one-handed. I’ve found this stance, which is taught by Mas Ayoob, works best for me.

It involves making a fist with your unused hand and raising the arm to hip level with your palm facing upward. Bend your elbow and draw the arm in tightly to your body.

When I’m working with one hand I either do this or pull my fist to my chest. Find what works best for you but take care to hold your free hand and arm tightly out of the way.

If you let it hang it’s unlikely to end well and can throw you off balance, making it harder to fire accurately.

Arm Extended/Straight-Arm

The most commonly used method for firing with one hand involves extending your gun hand straight ahead of you.

Face your target, step forward with your gun-hand-side foot, and raise the gun directly in front of you. This is where I remind you to raise the gun to your eye level, not lower your head to the gun.

one handed straight arm position
Straight Arm Shooting Stance, Lucky Gunner

Extend your shooting arm straight in front of your body and put enough tension in your arm to control recoil and maintain good follow-through as you shoot.

McMillan Tilt

The McMillan Tilt, or canted, method is a trick you can use with either hand to improve control and accuracy.

To do it, extend the gun like you would using the straight-arm method, then cant the gun inward. You’re looking for an approximately 45-degree angle.

This is not a sideways gangster hold it’s a slight cant for greater control. You may find canting your gun slightly significantly improves your shooting on one or even both sides.

For me, the McMillan Tilt helps quite a bit on the right-hand side but makes it worse on the left. This might have something to do with being cross-dominant or it may simply be one of those random things.

Don’t be afraid to experiment and find out what it takes to give you an edge.

Quick Change

All right, so taking a quick-change approach to moving the gun from one hand to another isn’t the best idea ever.

Always take your time when swapping hands with your gun for one-handed shooting. Do this by carefully and thoughtfully shifting your gun hand in front of your body with the muzzle remaining safely down-range.

Use your free hand’s thumb to slide along the gun’s grip under the palm of the hand gripping the gun.

This allows you to maintain contact with the gun and keeps you in control as you pass the gun to your other hand.

If your gun has an external thumb safety and you’ve just transferred the gun to what is normally your support hand you can reach behind the gun with your dominant hand to flip the safety off when you’re ready to shoot.

Yes, you can also learn to manipulate the safety with your non-dominant hand but it’s wise to wait until you’re more proficient with one hand before adding steps.

Tricks

Keeping 60 percent of your weight on your forward foot while maintaining a strong base is a vital step in the one-handed shooting process.

If your foundation is wobbly your accuracy will suffer (and so will your safety). Take a moment to find your balance and ground yourself.

Kat on the range with 50 Beowulf
The same applies to a rifle too, especially with big bores! Running the .50 Beowulf at the range, because big boom.

Whether your shooting-side elbow is bent or fully extended comes down to personal preference. I prefer to keep mine fully extended with a great deal of tension in my arm and shoulder.

It helps me shoot better. If you have any kind of arm injury you’re going to want to try to leave some bend in that elbow and there is nothing wrong with that.

Try both ways so you know which position gives you the best control of the gun.

Grip your gun firmly but quit trying to choke the life out of it. An uneven grip or tightening your hand as you shoot will ruin your shots. Do you need to hold on tightly?

Rick Grimes
The perfect grip for shooting walkers… in the feet. Do NOT make the same mistake.

Absolutely, but don’t get carried away.

Your accuracy when shooting with one hand comes from control. Without a good grip and stance your target reacquisition will be lousy and your shots will be all over the place.

Drive the gun forward with a combination of solidly grounded legs, proper balance, and firm tension in your gun arm. Practice good trigger control just as you do with two hands.

Focus on your front sight. All the fundamentals apply you’re just dropping a hand.

Single Target Drills

When you first start shooting with one hand, keep things simple. Shoot your target from five yards and don’t try moving between different zones, not at first.

Go for center mass. Once you think you’ve got a single shot down move on to strings of three shots at a time, then five. Just as with two-handed target shooting your goal is a nice, tight group.

It’s going to take time, especially with your non-dominant hand, so be patient.

Producing nice groups at center mass? Try moving from center mass to the head box on your target. You can do this by doing a traditional Mozambique Drill – two shots to center mass, one to the head – or you can fire any combination of shots.

Don’t be random about it, have a plan. Also do not focus only on your dominant hand. Both hands need equal attention (realistically, your non-dominant hand is the one you’re going to need to work on a bit more).

Multiple Target Drills

Using two or more targets is a good way to work on movement while firing your gun one-handed. As with all drills, have a plan. This isn’t about firing randomly at whatever target your gun swings past.

starting el presidente
The extremely popular El Presidente drill can be shot one-handed also

Start firing left-to-right or right-to-left. When that gets too easy, mix it up. For example, if you have three targets shoot the center target, then the right-side target, and then the far left-side target.

Try this firing one shot per target before moving on to multiple shots per target. Also, aim at a specific spot on the targets whether center mass or elsewhere.

Do not blindly fire just planning to hit the target “somewhere” as along as it’s on paper or steel. 

Distance

5 yards is a good distance to shoot from at first. Just remember, if you’re shooting steel plates you should be using frangibles, not FMJs.

Frangible ammo at REALLY close range.

As your skills improve you can increase the distance to 7 yards and 10 yards.

Keep in mind most – although not all – firefights take place at close range. That doesn’t mean you should ignore longer distances simply that you would be right to take the time to hone your closer-range skills first.

Don’t get cocky and start out at 10 yards or move further out prematurely. Go slow. Practice. 

Parting Shots

It’s easy to slack off on your one-handed shooting time. After all, it’s harder and might be less rewarding than shooting two-handed, at least initially.

If you just integrate a few one-handed drills into each shooting session you’ll see improvement quickly. Sure, shooting is fun, but self-defense is serious.

As a responsible shooter, it’s your job to make sure you put the work in along with the fun.

How do you train new skills? Share your one-handed target pictures and tips in the comments below! If you’re looking for more training, give Dry Fire a try. If you really want to go to the next level, find yourself a Firearms Training Class!

The post [Guide] How To Shoot a Pistol One Handed: Tips, Tricks, & Drills appeared first on Pew Pew Tactical.

guns

via Pew Pew Tactical https://ift.tt/2m7cc0U

July 29, 2020 at 06:25PM

Mac OS 8 emulator brings the late ’90s to your modern PC

Mac OS 8 emulator brings the late ’90s to your modern PC

https://ift.tt/2BGBmS3

If you’ve ever been interested in reliving (or discovering) what using a Mac was like in the late ‘90s, here’s your chance. Felix Rieseberg, a Slack developer, has created an app that emulates Mac OS 8, which you can download and run on macOS, Windows or Linux. He did something similar a couple of years ago with Windows 95.

Rieseberg wrote on the GitHub page for the project (via iMore) that while it works pretty well, he built the Electron app using JavaScript, “so please adjust your expectations.” It emulates Mac OS 8.1 on a 1991 Macintosh Quadra 900 with a Motorola CPU — this was before Apple’s move to PowerPC architecture.

It’s actually kinda functional in terms of software. It features games and demos from a 1997 Macworld demo disc, including Oregon Trail, Duke Nukem 3D, Civilization II, Alley 19 Bowling, Damage Incorporated and Dungeons & Dragons. There are some other apps and demos too, such as Photoshop 3, Premiere 4 and Illustrator 5.5.

You won’t be able to get online through the emulator, even though it includes Internet Explorer and Netscape. However, there’s a way for you to transfer files into your new, but very old operating system. You might like to grab some games and apps from Macintosh Repository. Rieseberg said he was able to install Encarta on the emulator.

It doesn’t run perfectly, given issues that other GitHub users have raised — the Civ II demo crashed immediately for one brave soul who tried it. So you probably shouldn’t use it for any serious purposes, but it seems like a fun trip down memory lane (or into the before times for some younger folks).

geeky,Tech,Database

via Engadget http://www.engadget.com

July 29, 2020 at 12:54PM