Laravel 5: Gotchas – Global Scope

Global Scope with update and select, when using whereHas and related model

When you do any updated (and possibly inserts) you have to call withoutGlobalScope before find():

make private

If you move withoutGlobalScope after find, when you attempt to make aid private, you will make all aids private.

All of them.

Again, I did not investigated why (no time at the moment), but this is how it works.

makepublic

If you move withoutGlobalScope after find, you will get:

This is because this particular scope filers out all ‘private’ aids.

Bottom line is that, when you release global scope, it must come before using find() method.

Now interesting thing below.

However, when you use Global Scope release (withoutGlobalScope) in select, especially when calling related model and you will use whereHas() method, you need to use it after find() method and after calling related model, or whereHas() method will not work.

See sample code:

So, usually order is not that important in Laravel Query Builder. However, when Global Scopes comes to play, it looks like it becomes important.

Anyway, this is a practical angle.
Tested on L5.6

Laravel Custom Facade

Laravel 5: Making Custom facade

This is copied from here – just to make sure I have it, in case author decides to delete it.
STEP 1 – CREATE CLASS THAT WILL BE ACCESSED VIA FACADE

STEP 2 – CREATE SERVICE PROVIDER CLASS

STEP 3 – ADD REGISTER METHOD TO SERVICE PROVIDER CLASS

STEP 4 – CREATE FACADE CLASS

Create: App\Facades\MyApp.php

STEP 5 – ADD ALIAS AND SERVICE PROVIDER TO config/app.php

STEP 6 – TESTING

 

Artisan command: make scope

Artisan command: make


Add additional command to “php artisan make:…” console command list

 

NOTE:
I’m making custom global scope in this example, but it can be easily adjusted for any other template.
 
step 1: create Stubs directory (unless you have it already)

Location of this directory is up to you.
I located it in app\Console\, since this seemed logical to me.

step 2: inside of Stubs dir create your stub file

This is a file, that will be used as auto-generated Scopes file.

Here is what I use:

Please note:

  • DummyNamespace, and
  • DummyClass

… they will be replaced by names for class and namespace.

Both of Names will be deducted from your path, you put in your php artisan make command.

Besides pasting this stub file inside of Stubs dir, nothing needs to be done.

step 3: create console command class, that will actually make scope

Now we actually need to make command, that will take care of doing all the magic, after you open console window and type: php artisan make: MyScope

First, lest use existing Artisan make command and create command template file:

This will place out command template file in app\Console\Commands dir:

Now, you can either compare your newly created template with file I will paste right below and apply changes, or replace piecemeal all, that you have in scope template.

Actually, we did not have to use console command making scope template, but just create file by hand, name it MakeScope (or any other name, if you do not like it) and paste this code:

Code is pretty much self-explanatory – just read in-code comments.

Except for one thing – app disc creation.
Just put this code:

in Filesystem Disks in file: config/filesystems.php

step 4: now we have to register our command, so Artisan is able to find it and use it, when we type in command into console

We do it in Kernel – see below:

Inside of Kernel, just add line of code in method: protected $commands = [], see below:

How to use this is put on very top, but just to remind you:

I am not sure, if Laravel engine creates parent app\Scopes\ dir.

In case it does not (and you get some errors, or nothing happens), add it by hand here:

Unless I missed something, above step-by-step should get you working make shortcut accessible from Artisan console.

 

Laravel collections merging peculiarity

Laravel collections merging failings

Laravel Eloquent collections merging fails, if initial collection has same ‘id’ as any of being merged.

Lets assume we have these Eloquent collections:

Lets assume, that $cars and $bikes have ‘id’ element with same value ‘1’.

In such case, if we do this:

… we will get elements with same value overwritten, loosing one collection element.

Here is workaround:

You create empty collection and use it as initial collection, to which you merge all others.

In this case, since your initial collection has no elements, it cannot conflict with any following collection and you get no overwrites

Laravel Macros

Laravel 5: Macros

You can add functionality Laravel does not have out of the box by using Macros

Macro is defined in service provider.

I created a separate one for macros.

Note: macro takes argument, like this:

Now, we can use it in overriden in \app middleware CheckForMaintenanceMode and allow people connecting from some IPs (like some developer), to have access to a system in maintenance, thus being able to fix things:

Here is what’s macroable:

Facades

  • Cache
  • File
  • Lang
  • Request
  • Response
  • Route
  • URL

Illuminate Classes

  • Illuminate\Cache\Repository
  • Illuminate\Console\Scheduling\Event
  • Illuminate\Database\Eloquent\Builder
  • Illuminate\Database\Eloquent\Relation
  • Illuminate\Database\Query\Builder
  • Illuminate\Filesystem\Filesystem
  • Illuminate\Foundation\Testing\TestResponse
  • Illuminate\Http\RedirectResponse
  • Illuminate\Http\Request
  • Illuminate\Http\UploadedFile
  • Illuminate\Routing\ResponseFactory
  • Illuminate\Routing\Router
  • Illuminate\Routing\UrlGenerator
  • Illuminate\Support\Arr
  • Illuminate\Support\Collection
  • Illuminate\Support\Str
  • Illuminate\Translation\Translator
  • Illuminate\Validation\Rule

 

 

Laravel 5: Creating Package

Laravel 5: Creating Package

I would not be surprised, if when I get back to it some time later it is not going to work. It took me awhile, lots of teeth gritting and almost a dozen tutorials to make it work and I am not entirely sure, why the heck attempts before successful one did not work.

Try reading also this.
Also this for some testing ideas.
Here is also not a bad read.

Want some laugh? Read this, how Laravel folks screwed up.


Step one

Create this folder structure inside of folder ‘packages’, which should be sitting in root path of your Laravel installation.
You can change names later.
But for now, stick “religiously” to naming and even case – to the letter and last dot.

Step two

Open your console and get into folder \imagecache :

Once inside of mentioned dir, run this command:

… and answer some questions. They are simple enough.

You should get something like this:

This is your package JSON file.
It should reside in topmost folder of your package – in this case: \imagecache.

Step three

Create files as shown on image:

  1. this is your service provider
  2. this is your work class, where you actually do something
  3. and this is your Facade, that allows to easy access toy your package output anywhere

And here is code.

service provider

class

facade

Step four

Now we have to register stuff with \config\app.

Open this file: config\app.php and add to :

and to:

Step five

Update your main composer file (composer.json), one that sits in root folder of your Laravel install.

Just find ‘autoload section and ADD THIS LINE marked content.

You have to run composer command – since you adjusted composer.json:

Step six

This is how you use it:

 

If you did all as outlined and LARAVEL DEITY is in good mood, you should see this:

BTW:

I tried to use this new Laravel auto-discovery of ServiceProviders, where you could spice up a bit composer.json:

… and do without adding:

… to app.providers, but I could not make it work.

 

Laravel 5: Testing – Laravel Dusk testing – login shortcut

Cheatsheet: Laravel Dusk testing – login shortcut

Create default user and quickly use it to login. However, there is a problem with this approach.

If you look into /test/Browser folder, you will see another called: /Pages.
Here’s what Laravel docs (5.6) have to say about this.

Scroll slightly below and you will see this Artisan command:

When you run it, it will create class Login inside of /Pages.
This will be our default user login shortcut class.

But it is not ready yet.
We have to prep it a bit to serve its purpose.
We will add loginUser() method to it.
This will be a method, that will be used behind scenes to log in defined there default user.

Before I go to this, a word of caution: do not name your login method login(), but anything else – I used loginUser(), as login() name goes head on with another, Laravel native login() method and is being overridden, giving you error like this, when you attempt to run your test:

Login methods clash was not spotted by me. All credit due is here

Our Login class with changes is below.
A few tidbits in method comments to make things easier to understand – when you learn (or forgot something), nothing seems to be obvious.

And here is Login class with changes:

Now, how to use it.


There is a PROBLEM with this approach.

It is good, if you use Laravel out of the box single level authorization, which is good for blog, when supported by user roles.

Simply you have single single admin and allow access rights based on roles.

In most cases I worked on, I needed 3 separate site areas, with two, that needed authentication.

Take ecommerce: backend admin / customer admin.
Take any company website, that allows users to have accounts: backend admin / customer admin.

You could try roles, but good luck with that.

You need multi-level authentication capacity
Note: what you find at the end of the link listed above, was written for Laravel 5.2 and may need some touchups.

Laravel does not have multi-level auth out of the box (as of 5.6)

So, if you are using Laravel provided single level authentication, you are in luck.

You can use this method described above.

You can also use methods stored in here:

Note:

If you are trying to use these methods and getting error to the tune of this:

… you have to override protected user() method from vendor\laravel\dusk\src\TestCase.php in:

  • your TestClass that extends tests\DuskTestCase, or
  • in tests\DuskTestCase.php itself

Whichever serves you best.

Class tests\DuskTestCase seems best, as all your TestClasses will extend it, so you do it once and use it from now on.

Now, as I mentioned these methods are rigged to serve Laravel built in authentication.

Just look into: \vendor\laravel\dusk\src\DuskServiceProvider.php and you’ll see rigged routes, like:

Then these routes work with hardcoded methods in vendor\laravel\dusk\src\Concerns\InteractsWithAuthentication.php:

You could set this for your needs in DuskServiceProvider, but that would also require rewriting methods in vendor\laravel\dusk\src\Concerns\InteractsWithAuthentication.php, which is nothing short of messing with core files, that can be replaced in next framework update.

Not really recommended.

You could overload these methods, but then, why not writing your own 😉

Better use other means of checking login.

They are all described in Tests section.

 

Laravel 5: Testing – Cheatsheet: Laravel Dusk testing – cookies

Cheatsheet: Laravel Dusk testing – cookies

Get, or set testing cookies.

[one_third]
set encrypted cookie()
get encrypted cookie()
[/one_third][one_third]
set plainCookie()
get plainCookie()
[/one_third][one_third_last]
addCookie
deleteCookie
[/one_third_last]


A small cookie reminder.

Parameter Description
name Required. Specifies the name of the cookie
value Optional. Specifies the value of the cookie
expire Optional. Specifies when the cookie expires. The value: time()+86400*30, will set the cookie to expire in 30 days. If this parameter is omitted or set to 0, the cookie will expire at the end of the session (when the browser closes). Default is 0
path Optional. Specifies the server path of the cookie. If set to “/”, the cookie will be available within the entire domain. If set to “/php/”, the cookie will only be available within the php directory and all sub-directories of php. The default value is the current directory that the cookie is being set in
domain Optional. Specifies the domain name of the cookie. To make the cookie available on all subdomains of example.com, set domain to “example.com”. Setting it to www.example.com will make the cookie only available in the www subdomain
secure Optional. Specifies whether or not the cookie should only be transmitted over a secure HTTPS connection. TRUE indicates that the cookie will only be set if a secure connection exists. Default is FALSE
httpOnly Optional. If set to TRUE the cookie will be accessible only through the HTTP protocol (the cookie will not be accessible by scripting languages). This setting can help to reduce identity theft through XSS attacks. Default is FALSE
above table taken from: w3schools.com



This is same as setting encrypted cookies, you just change method name cookie(), to plainCookie().
Click here to see how it is done


This is same as getting encrypted cookies, you just change method name cookie(), to plainCookie().
Click here to see how it is done


addCookie()

This method is used internally by cookie() and plainCookie() methods.
It is used pretty much same way.
It has last parameter $encrypt, which is set to true in cookie(), and to false in plainCookie().

For examples, look above.


deleteCookie()

 

 

Laravel 5: Testing – Cheatsheet: Laravel Dusk testing – delayed action

Cheatsheet: Laravel Dusk testing – delayed action

Wait for something to happen, or/and delay by some time.

[one_third]
whenAvailable
waitFor
waitUntilMissing
waitForText
[/one_third][one_third]
waitForLink
waitForLocation
waitUntil
waitForDialog
[/one_third][one_third_last]
waitForReload
waitUsing
[/one_third_last]


whenAvailable

waitFor

waitUntilMissing

waitForText

waitForLocation

waitUntil

waitForDialog

waitForReload

waitUsing