chrismay

chrismay

Member Since 2 Years Ago

Experience Points 27,950
Experience Level 6

2,050 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 276
Lessons
Completed
Best Reply Awards 0
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.

09 Sep
1 week ago

chrismay started a new conversation Aspectmock Class Eloquent Was Not Found By Locator

I have installed aspectmock and codeception, but I get InvalidArgumentException : Class Eloquent was not found by locator when I try to use it in my tests.

My tests/bootstrap.php:

require_once  __DIR__.'/../bootstrap/app.php';
require_once  __DIR__.'/../vendor/autoload.php';

$kernel = \AspectMock\Kernel::getInstance();

$kernel->init([
    'debug' => true,
    'cacheDir' => __DIR__ . '/_tmp/aspectMock/cache',
    'includePaths' => [
        __DIR__ . '/../vendor/laravel',
        __DIR__ . '/../app'
    ],
    'excludePaths' => [
        __DIR__,
    ]
]);

$kernel->loadFile(__DIR__.'/../bootstrap/app.php');
$kernel->loadFile(__DIR__.'/../vendor/autoload.php');

Is the bootstrap code wrong?

codeception.yml

paths:
    tests: tests
    output: tests/_output
    data: tests/_data
    support: tests/_support
    envs: tests/_envs
bootstrap: bootstrap.php
actor_suffix: Tester
extensions:
    enabled:
        - Codeception\Extension\RunFailed

coverage:
    enabled: true
    include:
        - app/*
03 Sep
2 weeks ago

chrismay left a reply on Auto Retry DB Queries

ok I found the solution for anyone interested: This in composer.json replaces the file. Don't forge to run dump-autoload.

"classmap": [
  "vendorOverrides/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php"
],
"exclude-from-classmap": [
  "vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php"
],

chrismay left a reply on Auto Retry DB Queries

Ok, I found a solution by changing a vendor file: vendor\doctrine\dbal\lib\Doctrine\DBAL\Driver\PDOStatement.php

before:

    public function execute($params = null)
    {
        try {
            return parent::execute($params);
        } catch (\PDOException $exception) {
            throw new PDOException($exception);
        }
    }

after:

 public function execute($params = null)
    {
        $tries = 1;
        $maxTries = 3;
        while(true) {
            try {
                return parent::execute($params);
            } catch (\PDOException $exception) {
                if($tries >= $maxTries)
                    throw new PDOException($exception);
                $tries++;
            }
        }
    }

However I am not sure how to implement this change in my own project without forking the package and the requiring the changed version (I would like to stick to the vendor package and somehow override just the single method)

chrismay started a new conversation Auto Retry DB Queries

I am currently victim to gap locks in MySQL: http://thushw.blogspot.com/2010/11/mysql-deadlocks-with-concurrent-inserts.html

Simply retrying could be a solution to my problem. I see that there is a separate parameter on transactions:

DB::transaction(function () { ... }, 5);

However I do not use transactions and the problem occurs with normal INSERT statement.

Is there some easy way to handle this globally? E.g. configure the driver to use retries on all queries?

Otherwise I'd have to wrap all queries like this:

for ($retries = 0; $retries <= MAX_NUM_RETIRES; $retries++) {
    try {
        // run query
    } catch (\Exception $e) {
        continue;
    }
    break;
}
25 Aug
3 weeks ago

chrismay started a new conversation Posts View Shows Server Time Instead Of User Time

posted x ago is not adjusted to users local time in posts view

The relative time is correct in laracasts.com/dicuss (it shows 3 minutes ago for my last post), but it displays 6 hours ago when I open the post.

chrismay started a new conversation Separate Queue For Each Job

I was wondering if there are any drawbacks if I dispatch each jobclass to its own queue.

e.g. App\Jobs\SendWelcomeEmail is dispatched to a App\Jobs\SendWelcomeEmail queue.

I plan to do so since it allows me to manage the queue more easily:

e.g. I could see how many pending entries are there for the App\Jobs\SendWelcomeEmail job by calling: Queue::size('App\Jobs\SendWelcomeEmail');

Another usecase is that I have a scheduled job that runs every minute, but I only everwant a single one of those jobs in the queue. This could easily be achieved by having a separate queue for the job.

I use horizon to manage the queue and the setup looks like this:

class Queues { const DEFAULT = 'default'; const SCHEDULER = 'scheduler'; const PROCESS_RESULTS = ProcessResults::class; const MOVE_PROCESSED_ROWS = MoveProcessedRows::class; const SEND_WELCOME_EMAIL = SendWelcomeEmail::class ...

static function all() { $oClass = new ReflectionClass(get_called_class()); return $oClass->getConstants(); } }

horizon.php

... 'queue' => \App\Enums\Queues::all(), ...

I appreciate any feedback or criticism to this setup.

03 Nov
1 year ago

chrismay left a reply on Api Test Structure (Model Vs Controller Vs Route Cest)


abstract class ApiCest
{
    protected $route;
    protected $method;
    protected $authentication = true;
    protected $private = true;

    /** @var $user User */
    protected $user = null;

    public function __construct()
    {
        $this->route = $this->route ?? $this->getRouteFromClassName();
        $this->method = $this->method ?? $this->getMethodFromRouteName();
    }

    public function _before(ApiTester $I)
    {
    }

    public function _after(ApiTester $I)
    {
    }

    protected function send(ApiTester $I, $params) {
        $I->{'send'.$this->method}($this->url(), $params);
    }

    protected function url(string $route = null, User $user = null) : string {
        $route = $route ?? $this->route;
        $user = $user ?? $this->user;
        if($user)
            return route($route, ['user' => $user->id]);
        else
            return route($route);
    }

    private function getRouteFromClassName() : string {
        $className = str_replace('Cest', '', static::class);
        $className = lcfirst($className);
        $parts = preg_split('/(?=[A-Z])/', $className);
        $route = strtolower(implode('.', $parts));
        return $this->route = $route;
    }

    private function getMethodFromRouteName() : string {
        $parts = explode('.', $this->route);
        $keyword = strtolower(array_slice($parts, -1)[0]);
        $methodMap = [
            'GET' => [ 'get', 'index', 'read', 'find', 'all' ],
            'POST' => [ 'post', 'store', 'save', 'create' ],
            'PUT' => [ 'put', 'overwrite' ],
            'PATCH' => [ 'patch', 'update' ],
            'DELETE' => [ 'delete', 'destroy' ]
        ];
        $methodMapFlipped = [];
        foreach($methodMap as $method => $keywords) {
            foreach($keywords as $keyword) {
                $methodMapFlipped[$keyword] = $method;
            }
        }
        $this->method = $methodMapFlipped[$keyword];
        return $this->method;
    }

    public function it_implements_authentication_rules (ApiTester $I) {
        if($this->private) {
            $I->seePrivateRoute($this->route, $this->method);
        }
        else if ($this->authentication) {
            $I->seeAuthRoute($this->route, $this->method);
        }
    }
}

chrismay left a reply on Api Test Structure (Model Vs Controller Vs Route Cest)

Ok, so the way I handle it now is to extend from an ApiCest class that is tightly coupled to a route.

UserStatusCest would now map to the route 'user.status'

It also tries to guess the REST method based on the name.

I would appreciate feedback on the design.

chrismay started a new conversation Api Test Structure (Model Vs Controller Vs Route Cest)

I want to test all my api endpoints with codeception.

I started off with a more model based approach:

class UserCest
{
    public function it_can_request_its_own_status (ApiTester $I) {
        $user = $I->amLoggedIn();
        $I->sendGET('/users/'.$user->id.'/status');
        $I->seeResponseCodeIs(200);
        $I->seeResponseContainsJson(['status' => 'active']);
    }
}

Now I realized that I might want to map the test directly to the routes to make it more obvious what route is tested. I thought that this would therefore rather refer to the controller that is used by the routes rather than models:

class UserControllerCest
{
    public users__user__status (ApiTester $I) {
        $route = __FUNCTION__;
        $user = $I->amLoggedIn();
        $url = $this->fillRouteWithUserId($route, $user);
        $I->sendGET($url);
        $I->seeResponseCodeIs(200);
        $I->seeResponseContainsJson(['status' => 'active']);
    }
}

Or I could even map the Cests directly to each route:

class users__user__statusCest
{
protected $route = '/users/{user}/status';

    public it_reports_the_status_for_authenticated_users (ApiTester $I) {
        $user = $I->amLoggedIn();
        $url = $this->fillRouteWithUserId($this->route, $user);
        $I->sendGET($url);
        $I->seeResponseCodeIs(200);
        $I->seeResponseContainsJson(['status' => 'active']);
    }

    public it_requires_authentication (ApiTester $I) {
        $user = $I->create(User::class)
        $url = $this->fillRouteWithUserId($this->route, $user);
        $I->sendGET($url);
        $I->seeResponseCodeIs(401);
    }
}

What (other) approach is suitable for testing my API?

07 Aug
2 years ago

chrismay left a reply on JWT With Laravel 5.1

Trying to keep it short: cookies(http-only & secure flag) are vulnerable to CSRF but not XSS. JWT in localstorage is vulnerable to XSS but not CSRF

The best you can do is to minimize the risk: store the JWT in a cookie store a csrf_token in localstorage

To make it stateless: Include the csrf_token in the JWT payload and check serverside if the JWT csrf_token and the csrf_token read from localstorage and provided in the header match.

This requires an attacker to get the csrf_token through XSS (e.g. you use a compromised 3rd party js library in your site or do not apply sanitation) And then he needs to trigger a csrf request with the csrf_token (e.g. embedded img src tag or form in a webpage /email)

This combination makes it a lot harder for an attacker (but not impossible).

It provides the same security level as laravels session based system with csrf_tokens, but does not require state.

chrismay started a new conversation Vue SPA Vs MPA/SSR

The Learn Vue 2.0 series uses ajax calls to get the data. It seems that the SPA is completely isolated from Laravel. I.e. Laravel is just a data API and the vue app could also simply be hosted on a third party external server (e.g. AWS S3). Is this the recommended way, or should I rather use Laravel for Routing and have separate views that implement individual vue components and already included data instead of using a SPA?