davidrushton

davidrushton

Member Since 5 Years Ago

Glasgow, Scotland

Web Developer at papertank.co.uk

Experience Points 19,485
Experience Level 4

515 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed 272
Lessons
Completed
Best Reply Awards 3
Best Reply
Awards
  • start-engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber-token Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer-token Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • lara-evanghelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

06 Aug
1 year ago

davidrushton left a reply on Packets Out Of Order Error

Just adding a comment to this old thread in case anyone else comes across this solution/ issue.

Adding PDO::ATTR_EMULATE_PREPARES to the database config had a serious side effect on our app - floats and decimals were stored as ints (losing their decimal place). Seems related to https://github.com/laravel/framework/issues/23925.

11 May
1 year ago

davidrushton left a reply on GDPR Consent Tracking

@Cronix Sure - that's certainly an option. Thanks for the feedback.

One of the reasons of having just a 'meta' array column was to allow it to be flexible and store whatever links or references make sense.

The model / record's created_at timestamp will already tell us when the consent was given / revoked, and we store our privacy policy as markdown in Git, so we can easily call up exactly what was consented to at the time, and the user sees when we make changes at the top of the privacy page and any communication.

If we make substantial changes to our privacy further down the line, we can run through and revoke everyone's consent and then use a Middleware to prompt them on their next login to re-consent.

davidrushton started a new conversation GDPR Consent Tracking

Just posting this here in case anyone is searching for a tool to help them with their GDPR compliance updates - https://github.com/papertank/origami-consent

I was looking to build consent checkboxes into a number of our apps, and the ICO says that you need to keep records of consent - "who, when, how, and what you told people." (https://ico.org.uk/for-organisations/guide-to-the-general-data-protection-regulation-gdpr/lawful-basis-for-processing/consent/).

Our open source Laravel package includes a GivesConsent trait which can be used easily like this:

$user->giveConsentTo('privacy_policy', [
    'text' => 'I consent to the processing of my data according to the privacy policy',
    'meta' => [
        'ip' => request()->ip(),
        'url' => request()->headers->get('referer'),
    ],
]);

You can then check

$user->hasConsentedTo('privacy_policy');

Finally, to match up with the GDPR / ICO requirements for tracking and evidence, changing the consent (e.g. revoking and then later consenting again) creates new database records.

Any feedback, suggestions, improvements or issue reports welcome :)

18 Dec
1 year ago

davidrushton left a reply on License An Application

@nikhil_webfosters We are still using a private Satis repository with a htpasswd auth (in nginx / apache) on the /web directory. When a client uses one of our proprietary packages, composer asks them for a username and password which we set up manually for them.

Hope that helps.

01 Oct
1 year ago

davidrushton started a new conversation How Do You Optimise Lots Of Individual Queries, Even With Caching?

Hi there,

I'm currently making some optimisation tweaks to one of our projects (CMS), and i've stumbled across a potential block and wondered if anyone had solved something similar?

Since the project is a CMS with flexible, arbitrary content, I currently load up the page / product / etc and then render through the content through Blade partials / modules / shortcodes.

Things like Icons and Media (images) (both models and databases tables) can be referenced in the admin content editor (like Wordpress shortcodes), and I load these on-the-fly when rendering the page. As a first optimisation, I cache each Icon and Media query result and fetch from redis the next time, however looking at the New Relic traces, the page load is now slowed down by the number of redis queries, as opposed to database queries.

The TL;DR is basically - "Rather than caching a (unknown) number of queries to fetch page images and icons, how would you group these in Laravel to cut down the amount of cache hits / queries?"

Thanks in advance! :)

David.

17 Mar
2 years ago

davidrushton left a reply on SaaS / Multi-tenant Advice (Server Architecture)

@daniel.negoita

It ended up getting quite complex, but we have a working custom solution with a central database and then a multi-tenant Laravel app that dynamically loads the right database through a Middleware, after fetching the client from the central db.

Most complex thing was migrations and using a single queue - had to create a new serializing trait to handle loading the queue job's client and override the migration commands to run for each client database in turn.

29 Jan
2 years ago

davidrushton left a reply on Envoyer Inspired Envoy Script

Just a heads up f or anyone that used (or might use) the Envoy Deploy script at https://github.com/papertank/envoy-deploy.

I've just updated the repository to v2 based on some of the refactors i'd made on my own copy.

It's also much easier to use within a Laravel project / repository now: you just copy the Envoy.blade.php file and then put your server host and path in the .env. Readme has been updated with the details: https://github.com/papertank/envoy-deploy/blob/master/readme.md

Thanks.

07 Dec
2 years ago

davidrushton started a new conversation Trivia Night Apple TV Quiz App

Disclaimer: This is a little bit of shameless promotion for our Apple TV quiz game trivianightapp.com.

Relevance: We just finished rebuilding with Laravel 5.3 and using socket.io for game event broadcasting between the Apple TV and iOS companion app clients. There's a Christmas pack with 200 of festive questions, and you can play with up to 6 family or friends using 1 Apple TV.

Question: Hoping to make a web version next year in Vue - has anyone got any experience or suggestions for building a multiplayer quiz on the web?

Thanks for reading and Merry Christmas when it comes :)

09 Aug
3 years ago

davidrushton started a new conversation SaaS / Multi-tenant Advice (Server Architecture)

Hi there,

We're about to launch a new app we've been working on for a few months, and I wondered if anyone had some advice for us in terms of handling our multi-tenant setup, particularly when we're running across multiple servers.

The app

  • Is currently one Laravel (5.2) codebase, with separate routes, controllers and middleware for the frontend/marketing, as well as each individual tenant (subdomain).
  • Has two database connections - a central database with a tenant table and settings, and a database for each client (name set dynamically and loaded through middleware)
  • Uses Forge and one server currently for codebase and databases, with a wildcard DNS and SSL certificate in place.

Requirements

  • We need to keep the same separation of databases per tenant, to comply with security / privacy, and to allow easy scaling and management
  • There needs to be a central database for general things like tenant records, invoices, settings, etc
  • We need to propagate migrations to all tenant databases (have this working on a single-server setup at the moment)
  • We'd like to be able to spin up new servers and use subdomain A records to route larger tenants as required

Question

We have the app set up to to everything apart from the last point above, and I was wondering if anyone had advice from previous SaaS experience or suggestions? I know Laravel can handle multiple database connections (i.e. not using localhost), and the other possibility would be to develop and hook into an API from each server / tenant, to grab the central database config (i.e. checking if a tenant/subdomain exists).

Thanks in advance :)

David.

29 Jun
3 years ago

davidrushton left a reply on Where Does Artisan Make:auth Set The Routes?

@BartHuis I believe the Route::auth() method is really just a helper to save you from writing all of those individual routes yourself. Also, since AuthController and PasswordController end up using core Laravel traits anyway, the benefit would be that possible changes to method names, etc, would be handled for you.

I end up writing my own Auth controller for projects, so I defined the routes myself anyway.

Hope that helps.

28 Jun
3 years ago

davidrushton left a reply on Where Does Artisan Make:auth Set The Routes?

@BartHuis If I understand your question, you're asking how Route::auth() works in the routes.php file, without being imported?

Route is a Facade which is registered in your config/app.php to be available globally.

'aliases' => [
        ...
        'Route'     => Illuminate\Support\Facades\Route::class,
        ...
]

The facade class is linked to the router instance which is the Illuminate/Routing/Router.html class.

davidrushton left a reply on Where Does Artisan Make:auth Set The Routes?

That command puts the following in your routes.php file

Route::auth();

Which expands to the following if you look in vendor/laravel/framework/src/Illuminate/Routing/Router.php

/**
 * Register the typical authentication routes for an application.
 *
 * @return void
 */
public function auth()
{
    // Authentication Routes...
    $this->get('login', 'Auth\[email protected]');
    $this->post('login', 'Auth\[email protected]');
    $this->get('logout', 'Auth\[email protected]');

    // Registration Routes...
    $this->get('register', 'Auth\[email protected]');
    $this->post('register', 'Auth\[email protected]');

    // Password Reset Routes...
    $this->get('password/reset/{token?}', 'Auth\[email protected]');
    $this->post('password/email', 'Auth\[email protected]');
    $this->post('password/reset', 'Auth\[email protected]');
}

Hope that helps!

31 May
3 years ago

davidrushton left a reply on Multi Tenant Database Selection

We required a separate database for each cilent (site) on a multi-tenant app, but also a 'base' database table/connection for our general data/logic.

In the end, we set up two connections - base and site - and added protected $connection = 'base' to each Eloquent model that wasn't site-specific.

I copied + pasted some of the main logic to https://gist.github.com/davidrushton/b7c6748d90ad3bce044579ade30e3a98 in case that helps.

There's some other things we had to tackle including installing a new database automatically and running 'site' migrations across all of the site databases when deploying new code, but it seems to be working really well.

30 May
3 years ago

davidrushton left a reply on Help With Sessions Duplicate Id?

Incase anyone else stumbles upon this, I've not experienced this in a few days.

One of the main changes I made was caching config using php artisan config:cache, after each deployment. I think I saw somewhere else that this might be related to the boot-time and therefore have an impact on the session.

Hope that helps.

23 May
3 years ago

davidrushton started a new conversation Help With Sessions Duplicate Id?

I recently updated a project to use Laravel 5.2 and am having some sporadic exceptions like the following picked up by Sentry:

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '403f212667d4940b3524a352f983cbe05057b035' for key 'sessions_id_unique' in /path/to/app/vendor/laravel/framework/src/Illuminate/Database/Connection.php:408
  • I use the database session driver
  • I've not modified the default session middleware or driver code
  • My database table is the default with a 255 varchar unique key for the sessions.id

My session.php looks like following

<?php

return [

    'driver' => env('SESSION_DRIVER', 'file'),

    'lifetime' => 120,

    'expire_on_close' => false,

    'encrypt' => false,

    'files' => storage_path('framework/sessions'),

    'connection' => null,

    'table' => 'sessions',

    'lottery' => [2, 100],

    'cookie' => 'worldwalking',

    'path' => '/',

    'domain' => null,

    'secure' => false,

    'http_only' => true,

];

If anyone has experienced this problem and fixed, or has any thoughts, I'd be very grateful for a heads up or any advice.

Thank in advance :)

27 Mar
3 years ago

davidrushton left a reply on Set Up Laravel 5 On Shared Hosting (c-panel)?

Hi @Applelay .

We blogged about setting up Laravel on shared hosting - http://papertank.co.uk/blog/793/setup-laravel-on-shared-hosting

The article was written for L4 I think, but it should still be valid for L5+.

Hope that helps.

27 Feb
3 years ago

davidrushton left a reply on AWS Tutorials?

@jlrdw Hey. Sorry, it was less the technical and API docs, and more a guide on how to setup and use services with Laravel - for instance generating the right access policies and choosing the right regions, etc.

davidrushton started a new conversation AWS Tutorials?

Quick question for anyone learning or familiar with Amazon Web Service, and the AWS Management Console:

Where did you learn how to set everything up, for instance permissions and getting set up with SES, SQS, S3, etc?

Thanks in advance!

18 Feb
3 years ago

davidrushton left a reply on Database Queue On Shared Hosting

@daem0n Just a quick update - I tried the queue:work --daemon setup but it looked like this was keeping the schedule:run command going and was creating several new queue:work commands.

I might not have set it up right, but I've gone back to the other setup for now.

17 Feb
3 years ago

davidrushton left a reply on Database Queue On Shared Hosting

@daem0n Thanks for the tip - I'll try that out on our setup and update our blog post.

davidrushton left a reply on Database Queue On Shared Hosting

@daem0n Just looking at that withoutOverlapping method - interesting.

It looks like Laravel might use the description of the task rather than the process id, so this might not handle if the process is killed for some reason outside of Laravel, i'm not sure.

Have you had any issues with using queue:work --daemon on your shared hosting?

davidrushton left a reply on Issue With Custom E-commerce & Select Dropdowns

Here is the javascript we used for a custom e-commerce app if that helps

   (function(){

        var price_field = $('#product-price');
        var options = $('.product-options select');
        var original = [];
        var selected = [];
        var values = [];

        //$(function(){

        $(options).each(function(index)
        {
            var option = $(this);
            var id = option.data('optionId');

            original[id] = $.map($('option:not([value=""])', option),function(value) {
                return value.value;
            });

            if ( index > 0 ) {
                option.addClass('disabled').attr('disabled','disabled').html('<option value="">--Select options above to filter--</option>');
            }
        });

        $(options).change(function()
        {
            var current = $(this);
            var position = options.index(current);
            selected = [];

            $(options).each(function(index){

                var option = $(this);
                var id = option.data('optionId');

                if ( index > position ) {
                    option.parent().addClass('loading');
                    option.addClass('disabled').attr('disabled','disabled').html('<option value="">--Select options above to filter--</option>');
                } else {
                    if ( option.val() != "" ) {
                        selected[id] = option.val();
                    }
                }
            });

            if ( selected.length == 0 ) {
                $('.product-options.loading').removeClass('loading');
                return false;
            }

            $.ajax({
                type: 'GET',
                url: '{{ url('api/v1/products/'.$product->ref.'/options') }}',
                data: { options: selected },
                success: function(response) {
                    updateOptions(current, response.data);
                    updatePrice(response.data);
                }
            });

        });

        function updatePrice(data)
        {
            if ( typeof data.price == 'undefined' ) {
                price_field.html();

                if ( $(options).filter('.disabled').length == 0 ) {
                    $(options).last().change();
                }

                return;
            }

            var price = parseInt(data.price_inc_tax);

            total = price / 100;

            price_field.html('£' + total.toFixed(2));

        }


        function updateOptions(changed, data)
        {
            var position = options.index(changed);
            var values = data.options;

            $(options).each(function(index){
                if ( index <= position ) {
                    return;
                }

                var option = $(this);
                var id = option.data('optionId');

                option.parent().removeClass('loading');

                if ( ! values[id] ) {
                    option.html('No options available');
                    return;
                }

                option.html('');
                $(values[id]).each(function(index, value)
                {
                    option.append($("<option>", { value: value, html: value }));
                });
                option.removeClass('disabled').removeAttr('disabled');

            });
        }


    })();

davidrushton left a reply on Queue Solution For Shared Hosting

Just saw this pop up the top of the discussions after posting another thread - https://laracasts.com/discuss/channels/servers/database-queue-on-shared-hosting.

Hope that helps someone else.

davidrushton started a new conversation Database Queue On Shared Hosting

Sometimes it's necessary to host a Laravel app on shared / cPanel hosting, but we recently ran in to an issue where using the queue was necessary.

Given that Beanstalkd, SQS and Redis weren't possible, we looked into using the database driver and a the scheduler cron job.

Thought I'd post the solution we used here in case it's helpful for anyone else. The code is on Gist at https://gist.github.com/davidrushton/b7229df4c73372402fc1 and I wrote a quick blog post at http://papertank.co.uk/blog/903/setup-laravel-queue-on-shared-hosting/.

Thanks to inspiration from https://gist.github.com/mauris/11375869, the scheduler job which runs every 5 minutes spawns a new queue:listen process and checks a local file with the process ID to see if it needs re-created or not.

19 Nov
3 years ago

davidrushton left a reply on How Would You Structure This Logic (banking/spending) In MySQL?

@devtraining

Thanks for your advice. I'm not too concerned with 70-80k records just now, but with our new model this immediately increases to 140-160k since all banked distance will be automatically 'spent'.

Thanks again.

davidrushton started a new conversation How Would You Structure This Logic (banking/spending) In MySQL?

Thanks in advance for any advice or suggestions!

Our Laravel app currently has a database table which keeps track of transactions (in this case distance, but could probably extend to credits, etc). The structure is:

id int primary
user_id int foreign
linked_to int foreign
type varchar
value decimal(12,3)
created_at timestamp
updated_at timestamp

Essentially, each user has multiple records with positive value fields, making up their total distance logged on the site.

The problem is that as well as handling positive values, we are now handling negative values (i.e. when the user spends or uses their distance within the app). At over 70k records at the moment, this distance table will become quite large quite quickly.

Aside from caching and app-based logic, do you have recommendations for database changes that might handle this a bit better?

Thanks!

18 Nov
3 years ago

davidrushton left a reply on License An Application

@andy @Hulu

Just catching up on your replies. The method we use is a simple htaccess protecting our self-hosted Satis repository which has archive downloads enabled.

The customer (who we intend to be a developer with composer knowledge) clones our Github repo and when then run composer install and it gets to our framework package, they are asked for a Username + Password. You can see our composer.json file at https://github.com/doorstepapp/doorstep/blob/master/composer.json

We're not in favour of encoding software, and as everyone else has said, this method clones our source code, migrations, etc to the vendor folder and we are then trusting the client not to re-sell or pirate.

Good luck with your project.

17 Nov
3 years ago

davidrushton left a reply on License An Application

We are also just releasing a commercial web app where users pay a one-off license fee for access and support, so have been thinking about the same thing.

Initially I was going to use Bitbucket and give access to users based on their username, but this became a bit problematic.

Instead, we now use the Satis private repository manager on our server (https://getcomposer.org/doc/articles/handling-private-packages-with-satis.md), protected by a basic auth htaccess / htpasswd.

When the user tries to composer install or composer update their repository (pulling in our app as a dependency), the Get

  - Installing doorstep/framework (dev-master 5e8766c)
    Authentication required (get.doorstepapp.com):
      Username: 
      Password:

In the background, when they buy a license we fill their license key as the username and password on the htpasswd, so effectively it should be instant access. If we need to revoke a license, they no longer get updates.

Hope that helps. Happy to give more info

30 Oct
3 years ago

davidrushton left a reply on Help: Eloquent Save() Stopped Working

Hey, @sukonovs.

It's a practice I follow in all my repositories, throwing a StorageException if I can't guarantee the model was saved, therefore halting any code that expects there to be something to to work with (saving relationships, redirecting to ID, etc).

I understand that a PDOException would be thrown for MySQL errors, but in this case save was returning false so my code caught this and I was alerted.

29 Oct
3 years ago

davidrushton left a reply on Help: Eloquent Save() Stopped Working

@Erik - I got it fixed, thanks.

davidrushton left a reply on Help: Eloquent Save() Stopped Working

Fixed - I think!

Turns out a PR this week broke the return of the save method - https://github.com/laravel/framework/commit/edd357dafd804b61446537e7c5f22ddac7bef271.

Taylor already fixed - https://github.com/laravel/framework/commit/34b86ebd2990e4908209a27bcf1eff4693d8acda - so a composer update sorted it out.

Whew.

davidrushton left a reply on Help: Eloquent Save() Stopped Working

I've written the following test:

$user = User::find(6);

var_dump($user->save());

$user->firstname = 'David';

var_dump($user->save());

$user->firstname = 'Different';

var_dump($user->save());

which returns

boolean false
boolean false
boolean true

So, it would appear Eloquent returns false when nothing was changed from the original model.

I think this is new behaviour on Eloquent but i'll keep looking into it.

davidrushton started a new conversation Help: Eloquent Save() Stopped Working

Hey. I wonder if anyone can help me - I'd be super grateful

My $user->save() has suddenly stopped working on my live server, but when testing it works locally and on dev/staging. Assuming it's a database issue, I've also tried cloning my live DB onto local, but I can't replicate.

My repository class does

if ( ! $user->save() ) {
    throw new StorageException('Could not create user');
}

And on my live server i’ve started catching those exceptions every time the account / user edit page is submitted and the User model is saved.

Nothing else untoward in the logs, var_dump($user->save()) does indeed return false, and I've restarted nginx and mysql with no joy.

Any ideas?

13 Oct
3 years ago

davidrushton left a reply on L5.1: How To Deploy To Shared Hosting Properly?

Hi @alierfani.

We blogged about this very thing a while ago http://papertank.co.uk/blog/793/setup-laravel-on-shared-hosting/

I think it's mostly still relevant for L5.

Hope that helps.

23 Sep
3 years ago

davidrushton left a reply on API Authentication For Mobile Applications

We've just tackled a new method of api session / authentication in our mobile + web apps. There's a couple of steps:

As well as the users database table, I have a table for app_sessions like so:

Schema::create('app_sessions', function(Blueprint $table)
{
    $table->engine = 'InnoDB';

    $table->increments('id');
    $table->integer('user_id')->unsigned();
    $table->string('key')->unique();
    $table->string('user_agent')->nullable();
    $table->string('app_version')->nullable();
    $table->text('payload')->nullable();
    $table->timestamps();
    $table->timestamp('last_activity')->nullable();

    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
Route::group(['prefix' => 'api/v1', 'namespace' => 'Api\V1', 'middleware' => ['api', 'api.auth']], function($route)
{
    $route->any('/', function(){
        return app('api')->response()->errorUnauthorized();
    });

    $route->post('auth/login', 'Auth@login');
    $route->post('auth/register', 'Auth@register');
    $route->post('auth/session', 'Auth@session');
    $route->post('auth/logout', 'Auth@logout');

    Route::group(['middleware' => 'api.session'], function($route) {

        // Other user specific / authenticated calls.

    });

}

The api and api.auth middleware sets up the api to be stateless and validates the api-key which is passed as an x-api-key http header.

The handle method of our api.session middleware looks like:

public function handle($request, Closure $next)
{
    $key = $request->header('x-api-session');

    if ( ! $key ) {
        return app('api')->response()->error('Invalid session', 34, Response::STATUS_UNAUTHORIZED);
    }

    $session = $this->session->findByKey($key);

    if ( ! $session ) {
        return app('api')->response()->error('Session expired', 34, Response::STATUS_UNAUTHORIZED);
    }

    $request->setUserResolver(function() use($session) {
        return $session->user;
    });

    return $next($request);
}

So, I pass the x-api-session http header to my Api Session repository class and get the user from that, setting it up in the Laravel request for use in controllers.

Because I set the Api session user in each request, I can have api end points like GET /me which don't require anything other than the session key in the header (and api key of course). Then my controllers can do:

public function view(Request $request)
{
    $user = $request->user();

    return $this->response()->resourceItem($user, new UserTransformer);
}

My Api Auth controller makes use of a custom Auth class with the following method:

public function attempt($email, $password, array $extra = [])
{
    $throttles = $this->isUsingThrottlesLoginsTrait();

    $request = app('request');

    if ( $throttles && $this->hasTooManyLoginAttempts($request) ) {
        throw new AuthException('Too many unsuccessful login attempts. Please try again later');
    }

    $credentials = [
        'email' => $email,
        'password' => $password
    ];

    if ( ! $this->auth->once($credentials) ) {
        $this->incrementLoginAttempts($request);
        throw new AuthException('Login unsuccessful');
    }

    $user = $this->auth->user();

    $session = $this->session->create($user, $extra);

    return $session;
}

So, I always create a session for api logins and return that in the response (with the user embedded). The app then passes the key as x-api-session for future requests.

A lot of our Api boilerplate code is open-source at http://github.com/papertank/origami-api but I've not published the authentication parts.

Hope that helps.

01 Sep
3 years ago

davidrushton left a reply on Image Upload Using Storage Function To Public Folder

We've been doing something similar, storing images in the /storage/app folder for our SaaS app for various reasons. It offers better security, we can do on-the-fly resizing or placeholder/default images with routes, and local/s3/rackspace can be changed easily.

We're keeping an eye on the server resources - as you mentioned using a route to respond with the image loads the Laravel framework, a bit much vs linking directly to the file url. We use the same approach as Intervention when responding with the images, i.e. sending cache headers (https://github.com/Intervention/imagecache/blob/master/src/Intervention/Image/ImageCacheController.php#L136). We also append a unix timestamp (related to the model's updated_at) to get the browser to re-fetch the image when it is changed.

Hope that helps!

19 Aug
3 years ago

davidrushton left a reply on Launching The Site

For UK based hosting, either self managed or fully managed VPS, we always recommend South West Broadband (swbroadband.co.uk). Really great service.

Good luck with your launch.

21 Jul
4 years ago

davidrushton left a reply on `artisan Clear-compiled` Fails With "Invalid Filename Provided." On A Fresh Install

Hi @drewjoh & @Kenneth_H ,

I too was having this error on my live /dev server with an upgrade to Laravel 5.

I initially thought https://github.com/laravel/framework/issues/9678 might help, but I will still having issues with the optimize command.

The fix was that my config/compiled.php file was out of date and had the wrong paths and files after I upgraded to Laravel 5.1.

PS. It turns out that php artisan optimize doesn't run when debug is true, unless you pass --force, which is why the error didn't happen locally.

21 Apr
4 years ago

davidrushton started a new conversation How Would You Group Activities / Notifications Together?

TLDR

I'm adding a couple of new activities / events to my Laravel app for worldwalking.org and I want to group them together so that 1 push notification is sent out.

For instance, user A uploads 1 photo to the group and user B uploads 4 photos to the group. Instead of all of the members receiving multiple notifications one after the other, they just receive one notification saying '5 new photos were added to the group'.

I'd considered running a cron-job or using delayed queue jobs, but I'm not clear what the best way to implement this kind of check is.

Any pointers would be really appreciated :)

David.

Backround

Our Laravel based app worldwalking.org shows users recent activity, e.g. 'You added 500 steps to the Walk the World walk' and 'Papertank gained the Country Flags achievement for Brazil'.

This works on a combination of Laravel's event fire / handle functionality, with a listener saving activity information in a database table for querying and output.

Some events also fire push notifications to our mobile apps, like 'Your group reached Arc de Triomphe on your Paris walk'.

I'm trying to add a new type of notification for repetitive things like photos uploaded or chat messages left, where I'd need to group activities together and send out 1 notification for multiple events.

19 Mar
4 years ago

davidrushton left a reply on Best Way To Get Account Balance

@EliasSoares Yeah, that might be a way to do it.

If you were worried about deletions knocking out the database total/current balance field, could fire an event on those occurrences too to handle the re-sum?

Another method may be to use PHP for the calculation - I'm not sure if that would have any speed benefit based on the size of the table. Rather than using a timely Eloquent model query, you could just do something like:

<?php

$movements = DB::table('account_movements')->where('account_id','=',1)->lists('value');
$sum = ( count($movements) > 0 ? array_sum($movements) : 0 ); // Total

davidrushton left a reply on Best Way To Get Account Balance

@EliasSoares I'm actually in the middle of doing something similar for a credit based payment system.

My plan is to have a credits table with value (could be negative or positive depending on debit/credit) (similar to your account_movements).

Whenever a transaction is done, a CreditsPurchased or CreditsRefunded event is fired. Both of these events will be handled by a handler class which does the SUM query and then saves the result as a credit_balance on the user table. This could even be queued once the database or traffic grows considerably.

Hope that helps.

davidrushton left a reply on Integrate A CMS Into Laravel 5

@RemiC Sure, yeah - it completely depends on the project. In this case the client was specifically moving from a Wordpress managed site and wanted to retain that for the CMS while we built a bespoke payment system and backend. In other cases where the development cost is too high to replicate something like WP, it might also make sense, however as you said if you want to tightly integrate the frontend or authentication etc then it becomes a headache.

davidrushton left a reply on Integrate A CMS Into Laravel 5

Not sure if this helps, but we had a specific requirement to use Wordpress for the CMS but Laravel to handle payments and some other custom functionality.

The approach we use is a rather simple one - a set of reserved URLs that Laravel hijacks and then the rest are continued on to Wordpress.

Our public/index.php looks something like this

<?php

if ( file_exists(__DIR__.'/wp/index.php') ) {

    $segments = ( isset($_SERVER['REQUEST_URI']) ? explode('/', trim($_SERVER['REQUEST_URI'],'/')) : array('/') );

    $urls = ['api','shop','admin','donate','_debugbar'];
    
    if ( ! in_array($segments[0], $urls) ) {
        require_once __DIR__.'/wp/vendor/autoload.php';
        require_once __DIR__.'/wp/index.php';
        exit;
    }

}

// Laravel bootstrap stuff here

Then, we put all the Wordpress code in public/wp a la https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory (we also use https://roots.io which is why Wordpress includes a composer vendor autoload file).

We also wanted to share the Wordpress theme header and footer on our Laravel site, so we :

  1. Wrote the following functions into our functions.php:
<?php

function site_primary_navigation()
{
    $cache = new \Illuminate\Cache\FileStore(new \Illuminate\Filesystem\Filesystem(), ABSPATH.'/cache');

    $menu = wp_nav_menu(['theme_location' => 'primary_navigation', 'menu_class' => 'nav navbar-nav navbar-right', 'echo' => false]);

    if ( ! $cache->get('wp_nav') ) {
        $cache->put('wp_primary_nav', str_replace('class="active', 'class="', $menu), 1440);
    }

    return $menu;
}

function site_primary_footer()
{
    $cache = new \Illuminate\Cache\FileStore(new \Illuminate\Filesystem\Filesystem(), ABSPATH.'/cache');

    ob_start();
    get_template_part('templates/footer', 'primary');
    $footer = ob_get_contents();
    ob_end_clean();

    if ( ! $cache->get('wp_footer') ) {
        $cache->put('wp_footer', $footer, 1440);
    }

    return $footer;
}
  1. Used those functions in Wordpress header.php and footer.php

  2. In Laravel blade partials / layouts we did:

<?php
    $cache = new \Illuminate\Cache\FileStore(new \Illuminate\Filesystem\Filesystem(), Config::get('wordpress.cache_path'));
    echo $cache->get('wp_primary_nav');
?>

Where cache_path is set up in a wordpress.php config file with the path to our Wordpress root / cache folder

David.

18 Mar
4 years ago

davidrushton left a reply on Envoyer.io Is Live

@pmall - I'm afraid I don't have much experience with ssh-agent, but this might help: https://developer.github.com/guides/using-ssh-agent-forwarding/

davidrushton left a reply on Envoyer.io Is Live

Thanks @pmall.

I don't think Envoy can prompt for things like key passphrases, but you might find some luck using https://help.github.com/articles/working-with-ssh-key-passphrases/#but-i-dont-want-to-enter-a-long-passphrase-every-time-i-use-the-key ssh-agent if you don't want to remove the passphrase.

davidrushton left a reply on Envoyer Inspired Envoy Script

@noeldiaz - Thanks for the heads up, I just watched @fideloper 's Servers for Hackers videos on Envoy and they are really helpful. Also thanks for the cleanup command - that was on the TODO list.

17 Mar
4 years ago

davidrushton left a reply on Envoyer.io Is Live

For anyone looking for a v. basic alternative using the Envoy tool, we just created one - see https://laracasts.com/discuss/channels/general-discussion/envoyer-inspired-envoy-script

davidrushton started a new conversation Envoyer Inspired Envoy Script

The new https://envoyer.io service from Taylor looks great and something we hope to use on future apps.

In the meantime, we were inspired to create a very basic deployment script using Envoy http://laravel.com/docs/5.0/envoy which follows the same "zero-downtime" approach.

The GitHub repo is https://github.com/papertank/envoy-deploy

After setting two variables (git url and server path) and setting up the Envoy file with your SSH login, the idea is you simply run envoy run init to setup the first deployment and envoy run deploy for each subsequent deployment.

We've only tested this on a Homestead / Vagrant VM but it appears to work ok. Not sure if anyone else will use this, but would really appreciate the feedback and of course any contributions.

David.

15 Mar
4 years ago

davidrushton left a reply on Where To Place Menu-related Stuff

@huconglobal - yeah, now that I try that on one of my apps I get null too - must be triggered too early.

What about creating a middleware like so that you could call globally or just on front / back end routes?

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\Guard;

class MenuMiddleware {


    protected $auth;

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

    public function handle($request, Closure $next)
    {
        $user = $this->auth->user();

        Menu::make('menuName', function($menu) use($user) {
                // Logic here
        });

        return $next($request);
    }

}

davidrushton left a reply on Where To Place Menu-related Stuff

Not sure if this answers your question, but I believe you can use the following code in your service provider to get the currently logged in user:

$this->app['request']->user()