meredevelopment

meredevelopment

Member Since 4 Years Ago

Experience Points
9,550
Total
Experience

450 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
86
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.

Level 2
9,550 XP
Sep
05
1 month ago
Activity icon

Started a new conversation Mailed Notifications Don't Use 'mail.markdown.theme' Setting...

Hi, I'm using a custom theme for my markdown Mailables which works fine.

But Notifications don't get the custom theme and I can't work out why.

Here's an example if you want to test:

Create resources/views/vendor/mail/html/themes/mytheme.css and make an obvious change:

.body {
    background-color: red;
    /* etc... */
}

Set theme in config/mail.php:

'markdown' => [
    'theme' => 'mytheme',

    'paths' => [
        resource_path('views/vendor/mail'),
    ],
],

Create Notifications/ThemeTestNotification.php:

// etc...
public function toMail($notifiable)
{
    return (new MailMessage)
                ->line('This is a theme test.')
                ->action('Test button', url('/'));
}
// etc...

Add a test route to routes/web.php:

Route::get('mailtest', function () {
    Notification::route('mail', '[email protected]')
        ->notify(new App\Notifications\ThemeTestNotification());
});

The resulting emailed notification WON'T have the new theme...

If the theme method is used to set the theme manually - as per docs - inside the notification like so:

public function toMail($notifiable)
{
    return (new MailMessage)
                ->theme(config('mail.markdown.theme')) //this is pulling the one set in mail config, but it could be set directly to 'mytheme'.
                ->line('This is a theme test.')
                ->action('Test button', url('/'));
}

...then the new theme WILL be used.

I guess my question is: Why doesn't Notifications just respect the setting in mail config. Is this worth flagging as a bug/enhancement? Or have I just got it all wrong (again).

Thanks!

Sep
01
1 month ago
Activity icon

Replied to Allowing Session-based Users To Access API - Is There A Nicer / Safer Way?

Thank you @audunru and @pciranda, I had completely overlooked CreateFreshApiToken in the docs. It's working perfectly!

Aug
30
1 month ago
Activity icon

Started a new conversation Allowing Session-based Users To Access API - Is There A Nicer / Safer Way?

I have a Passport protected API as part of a public-facing App, with external parties connecting with Personal Access Tokens. This ideally needs to stay as-is.

'Users' with accounts (plain old username/pass) also login to this App, and need to query some parts of the API with Vue in Views. This is where I'd like help and suggestions please:

At present I have the following sort of setup:

api.php

Route::group(['middleware' => 'auth:api'], function () {
    Route::apiResources(
        [
            'example' => 'API\ExampleController',
            // all the other resources

        ],
        ['except' => ['destroy']]
    );
});

web.php

Route::group(['middleware' => 'auth'], function () {
    Route::resources(
        [
            'example' => 'API\ExampleController',
            // all the other resources
        ],
        ['only' => ['index','show']]
    );
});

And in Views I'm doing stuff like this:

axios.get('/members/'+this.query)
.then(response => {
    // etc
})
.catch(error => {
    // etc
})

This all works fine... but a few questions:

  • Is there a way to not have to list all the Resources/Controllers in both Routes files? Maybe a way to import them from one place? I did attempt to add the EncryptCookies and StartSession middleware to the api group in Kernel.php but no luck, I get not authenticated errors when GETing the data.

  • Is this sort of access to the API via a session safe? I have the appropriate CSRF fields added to the Axios config (as it is out the box these days).

  • Finally, it strikes me that this sort of setup, i.e. having both an API and local users on one App must be quite common? How are others doing it if not this way?

Thanks for reading 👍

Activity icon

Replied to AuthenticateSession Middleware

Just a small note that AuthenticateSession is now partially documented here: https://laravel.com/docs/5.8/authentication#invalidating-sessions-on-other-devices

However @kfirba's article does a fantastic job of actually explaining it!

Aug
22
1 month ago
Activity icon

Replied to Using Passless Driver For Passwordless Login AND Registration.

Fixed it! Just in case someone has a similar problem, I had to make the auth attempt directly, and only then was the Passless driver used.

In my RegisterController I swapped:

$this->guard()->login($user);

with

Auth::attempt($user->only('email'));

(making sure to add use Illuminate\Support\Facades\Auth; to the opening declarations)

Aug
21
1 month ago
Activity icon

Replied to Using Passless Driver For Passwordless Login AND Registration.

I've not found a fix to this yet. I asked the Passless developer for suggestions and his reply looked hopeful, but I think I've misunderstood the instructions.

If anyone here is familiar with Passless please take a look at the issue: https://github.com/DarkGhostHunter/Passless/issues/10

Thank you.

Activity icon

Replied to Passing Additional Data To The Registered Event

Thanks! Ok I've gone with the first option and ended up with two events being fired by the RegisterController which works fine:

event(new Registered($user = $this->create($request->all())));
event(new UserCreated($user, $validated['memnum']));
Aug
19
1 month ago
Activity icon

Started a new conversation Passing Additional Data To The Registered Event

I'm using my own register function in RegisterController.php:

public function register(Request $request)
{
    // Gets validated request data.
    $validated = $this->validator($request->all())->validate();

    // Checks if member is migrated to this system. If not passes to old system.
    $member = new Member;
    if (!$member->migrated($validated['memnum']))
    {
        return redirect()->away('http://example.com?' . http_build_query($validated));
    }

    // Creates new user and passes it to registered event. ALSO WANTS TO PASS Member Number.
    event(new Registered($user = $this->create($request->all()), $validated['memnum']));

    $this->guard()->login($user);

    return $this->registered($request, $user)
        ?: redirect($this->redirectPath());
}

The registration form has a new field for memnum, which I don't want to be part of the User record in the DB, but I do need to collect at registration time.

I have a listener setup to fire on Registered events, and this listener needs access to both $user and $memnum.

I can't work out how to get $memnum to the listener without sending it as an Event arg. Plus for my code above to work, I need to edit Illuminate\Auth\Events\Registered and add $memnum as a public... whatever it's called. Obviously I can't do this (hack the core).

I could fire a second custom event after event(new Registered ... but... it just seems messy.

Any better ideas? Thanks!

Jul
12
3 months ago
Activity icon

Replied to Using Passless Driver For Passwordless Login AND Registration.

Thanks for the suggestion but I spent quite a while trying to use the bundled verification without password and getting it to auto-login after the verification link is clicked and... nope. Days of pain. As the Passless driver works so well for the login I'd love to get that working after registration too.

Activity icon

Started a new conversation Using Passless Driver For Passwordless Login AND Registration.

I'm using https://github.com/DarkGhostHunter/Passless for password-less login. It works as expected, users can login by entering their email address, then clicking on a link in the a validation email that get's sent.

When it comes to registration, by default when users register they are automatically logged-in. Instead I want to generate the same type of validation email that's generated at login so they have to wait for email.

I can't work out why the RegistrationController's register method doesn't already do this?

To explain a bit more: In my RegistrationController I have this function (copied from core):

public function register(Request $request)
    {
        $this->validator($request->all())->validate();
        event(new Registered($user = $this->create($request->all())));

        $this->guard()->login($user);

        return $this->registered($request, $user)
                        ?: redirect($this->redirectPath());
    }

The line $this->guard()->login($user); uses - I believe - the same login method that LoginController does, so I don't understand why the new driver isn't being used.

My grasp of Laravel Auth is thin, I'm trying to understand it more!

Apr
18
5 months ago
Activity icon

Replied to Casting To Array In Model Strips 'keyed' Keys. Manually Using `json_decode` Doesn't.

@FTIERSCH - Hi, thanks for looking at this. How would I cast it to JSON? It looks like the supported cast types are: integer, real, float, double, decimal:<digits>, string, boolean, object, array, collection, date, datetime, and timestamp.

Apr
17
5 months ago
Activity icon

Started a new conversation Casting To Array In Model Strips 'keyed' Keys. Manually Using `json_decode` Doesn't.

I am storing this in a DB column (MariaDB, Text) called "insured_works":

{"3000000":{"certificate":3000000,"pids":[22],"children":null}}

When I cast insured_works to an array in my Model with this:

protected $casts = [
    'insured_works' => 'array',
]

...and retrieve it in a JSONResource with this:

public function toArray($request)
{
    return [
        'insured_works' => $this->insured_works
    ];
}

I get this (note the missing "30000" key):

{
    "data": {
        "insured_works": [
            {
                "certificate": 3000000,
                "pids": [
                    22
                ],
                "children": null
            }
        ]
    }
}

If I don't cast it, but manually decode it in the JSONResource like this:

public function toArray($request)
{
    return [
        'insured_works' => json_decode($this->insured_works)
    ];
}

then this is returned:

{
    "data": {
        "insured_works": {
            "3000000": {
                "certificate": 3000000,
                "pids": [
                    22
                ],
                "children": null
            }
        }
    }
}

...which is what I want.

Any ideas why? I thought casting to an array did the same in the background as json_decode/encode.

Feb
08
8 months ago
Activity icon

Replied to Help Needed Adding Key-value Pair To Sub-array In Collection.

@REALRANDYALLEN - That's ace. I'd much rather transform() and modify the array item on the fly as you've done than fart about with keys and partial merged array nonsense.

Thanks a lot, you've taught me stuff!

Activity icon

Started a new conversation Help Needed Adding Key-value Pair To Sub-array In Collection.

Hi, I've had all sorts of trouble trying to add a key=>value pair to an array nested in a collection. I thought it would be easy with a collection method but... nope, been messing about with this for longer than my dignity allows me to say. All the things I've attempted with merge(), push() etc want to work on a collection not array. So I've ended up going back to basics and it's ugly!

Here's an example. It's completely fictitious but perfect illustrates the problem. In the example I have achieved what I want, but it's a joke! there must be a faster easier more succinct way:

$collection = collect([
    [
        'bid' => 2,
        'type' => 'Onion'
    ],
    [
        'bid' => 12,
        'type' => 'Clove'
    ],
    [
        'bid' => 19,
        'type' => 'Apple'
    ],
    [
        'bid' => 39,
        'type' => 'Clove'
    ]
]);
dump($collection);

// Find the key of the first 'Clove' entry
$foundCollectionKey = $collection->search(function ($item, $key) {
    return $item['type'] === 'Clove';
});

dump($foundCollectionKey);

// Extract the array data of the first 'Clove' entry.
$firstWhereArray = $collection->firstWhere('type', 'Clove');
dump($firstWhereArray);

// Append a key value pair.
$firstWhereArray['category'] = 'spice';

dump($firstWhereArray);

// Put the modified collection item back where it came from by Key.
$collection->put($foundCollectionKey, $firstWhereArray);

dump($collection);

This is the collection I want to end up with:

Collection {#419 ▼
  #items: array:4 [▼
    0 => array:2 [▼
      "bid" => 2
      "type" => "Onion"
    ]
    1 => array:3 [▼
      "bid" => 12
      "type" => "Clove"
      "category" => "spice"
    ]
    2 => array:2 [▼
      "bid" => 19
      "type" => "Apple"
    ]
    3 => array:2 [▼
      "bid" => 39
      "type" => "Clove"
    ]
  ]
}

I should say that this data is eventually going to be stored as JSON (TEXT) in a DB cell in this format:

{
    "foods": [{
            "bid": 2,
            "type": "Onion"
        },
        {
            "bid": 12,
            "type": "Clove",
            "category": "Spice"
        },
        {
            "bid": 19,
            "type": "Apple"
        },
        {
            "bid": 39,
            "type": "Clove"
        }
    ]
}
Jan
15
9 months ago
Activity icon

Started a new conversation Access Token Length - Locating The Method That Generates Access Tokens For Passport

Hi, I'm investigating the possibility of limiting the length of Access Tokens¹. The docs say that Passport is built upon League OAuth2 server, so I've attempted to locate this in Laravel's dependencies but can't see anything in `vendo.

I think I'm looking for getNewToken() to see how a length might be passed, but it's not present in the framework anywhere as far as I can see. Any ideas?

¹ If you need to know why, the old school VBA app that's accessing my Authorization Server has a maximum allowed length that I need to respect.

Jan
09
9 months ago
Activity icon

Started a new conversation Using Email Verification But Also Sometimes Manually Verifying Users.

I'm using Laravel's bundled Email Verification for a project. There are times that I need to bypass the email verification for some users, i.e. when I'm manually adding and verifying admin users.

I've found that to manually verify I user when it's created I need to 'simply' fill the email_verified_at users table column with a now(). i.e:

$strrand = str_random(10);
$user = User::create([
    'name' => 'User '.$strrand,
    'email' => 'user'.$strrand.'@example.com',
    'password' => Hash::make($strrand),
    'email_verified_at' => now()
]);

But... to make that possible, I need to set email_verified_at to fillable in the model, i.e:

protected $fillable = [
    'name', 'email', 'password', 'email_verified_at',
];

I don't really like making it 'fillable' though, and I think there must be a way to set the user as verified using an existing method, but I can't track it down. The VerifiesEmails trait has a markEmailAsVerified() method but I'm not sure how to use it? Any thoughts?

Activity icon

Replied to Attempting An Email + Email Verification Only Login (no Password). L5.7

Thank you @d9705996 and @realrandyallen, between the two of you I've realised that I need to rethink this token/password-less login quite a bit. The article by Matt provides loads of useful food for thought.

Dec
21
9 months ago
Activity icon

Started a new conversation Attempting An Email + Email Verification Only Login (no Password). L5.7

Hi, I'm trying to get a fresh L5.7 project running that allows people to register for an account with email only, but makes use of Email Verification.

I've removed password from:

  • fields on registration and login forms.
  • the RegisterController's create() and validate() functions.
  • the create_users_table migration.

I've also added the following to LoginController:

protected function validateLogin(Request $request)
{
    $request->validate([
        $this->username() => 'required|string',
        // 'password' => 'required|string', //NOT NEEDED
    ]);
}

What works:

When I register I get the "Verify Your Email Address" message and the actual verification email arrives. When I click on the verification link I'm logged in and it looks like it's all worked.

What breaks:

After verification, if I log out and try and login again with email address only, the following error is displayed:

"Undefined index: password".
…/vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php140

The function that's failing is validateCredentials(). If I modify it to return true like this everything works as I want it to:

public function validateCredentials(UserContract $user, array $credentials)
{
    // $plain = $credentials['password'];

    // return $this->hasher->check($plain, $user->getAuthPassword());
    return true;
}

So... how can I achieve this without hacking about in the core?

If this is a stupid approach, do you have suggestions of a better way to handle this? Ultimately I need to end up with a user logged-in to a session, with a proper user account. This user will only 'login' to the app twice in order to complete two application forms, and have some documents generated and sent to them. The user account will then be locked and sanitised.

Dec
18
9 months ago
Activity icon

Replied to Passport 'Frontend Quickstart' Usage / Docs

Thanks, that's very useful.

Seeing that registering components the way the doc currently suggests is now considered the 'old' way, I wonder if we should be suggesting that people do:

import PassportClients from './components/passport/Clients.vue';

Vue.component('passport-clients', PassportClients);

instead.

Activity icon

Replied to Passport 'Frontend Quickstart' Usage / Docs

Great, thanks a lot. I've submitted a PR as I think a breaking change by a minor Laravel release (even if it is in a component) definitely needs documenting!

Dec
17
9 months ago
Activity icon

Started a new conversation Passport 'Frontend Quickstart' Usage / Docs

I'm familiarising myself with Passport. I've just been through the Passport docs and noticed what seems to be a bug/mistake. This is a fresh 5.7 project with authentication installed.

When adding the Quickstart components to resources/js/app.js like so:

Vue.component(
    'passport-clients',
    require('./components/passport/Clients.vue').default
);

// other two as well

...and then also adding the component to the view in resources/views/home.blade.php:

<passport-clients></passport-clients>

I get this in console: [Vue warn]: Unknown custom element: <passport-clients> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

If I remove .default from the end of the line that registers the component in app.js (see above) it works as expected, showing me the OAuth Clients meta box in the view.

Any ideas? Worth reporting to the Laravel project, or something I've doing wrong?

Dec
11
10 months ago
Activity icon

Replied to Confusion Over How To Customise Mail View Components

No sooner do I post this than the answer is found under an old Github issue! It turns out my old project that's been upgraded was missing a config value.

For anyone else with weird old upgraded projects like me:

/*
    |--------------------------------------------------------------------------
    | Markdown Mail Settings
    |--------------------------------------------------------------------------
    |
    | If you are using Markdown based email rendering, you may configure your
    | theme and component paths here, allowing you to customize the design
    | of the emails. Or, you may simply stick with the Laravel defaults!
    |
    */

    'markdown' => [
        'theme' => 'default',

        'paths' => [
            resource_path('views/vendor/mail'),
        ],
    ],

needed to be in config/mail.php

sighhhhhh

Activity icon

Started a new conversation Confusion Over How To Customise Mail View Components

I'm attempting to customise the mail components that Laravel ships with, in particular the markdown components. I've followed the docs (5.7) as best I can, and there seems to be a bit of the puzzle missing. I'll use the docs examples to explain the scenario:

To create my mailable and the markdown template I do:

php artisan make:mail OrderShipped --markdown=emails.orders.shipped

This creates a mailable which has the build() function:

public function build()
    {
        return $this->markdown('emails.orders.shipped');
    }

It also creates a the blade view in views/emails/orders/shipped.blade.php with this in it:

@component('mail::message')
# Introduction

The body of your message.

@component('mail::button', ['url' => ''])
Button Text
@endcomponent

Thanks,<br>
{{ config('app.name') }}
@endcomponent

In that view I change "Button Text" to "Click Me". I then render the email source with this route:

use App\Mail\OrderShipped;
Route::get('/testemail', function () {
  return (new OrderShipped)->render();
});

I see the email with default styling, but the button text is changed. Brilliant.

The problem:

Now I want to customise the scaffolding of that email, the layout and colours etc. So following the docs I run php artisan vendor:publish --tag=laravel-mail and get a load of blade views generated in views/vendor/mail/html and views/vendor/mail/markdown.

As a test I want to remove the link in the header of the email. I find this template in views/vendor/mail/html/header.blade.php:

<tr>
    <td class="header">
        <a href="{{ $url }}">
            {{ $slot }}
        </a>
    </td>
</tr>

I remove the link so it looks like:

<tr>
    <td class="header">
        {{ $slot }}
    </td>
</tr>

...save the file, and re-load my rendered email. Nothing has changed. What am I doing wrong?

I can't see or deduce any more steps needed from the docs. Any help you can give will be appreciated!

Activity icon

Replied to How Can I Attach File Coming From The Public Folder?

Update: 5.7 has a helper called attachFromStorage which paths from the storage/apps dir.

The example from the docs is this:

/**
 * Build the message.
 *
 * @return $this
 */
 public function build()
 {
    return $this->view('email.orders.shipped')
                ->attachFromStorage('/path/to/file', 'name.pdf', [
                    'mime' => 'application/pdf'
                ]);
 }
Oct
11
1 year ago
Activity icon

Replied to Resource Controller Parameter Rename Not Working (L 5.7.8)

Ok will do when I’m on a desktop. Doesn’t seem possible from mobile.

Activity icon

Replied to Resource Controller Parameter Rename Not Working (L 5.7.8)

Ah man the wrong docs! Sorry. Thank you. Sorry!

Activity icon

Started a new conversation Resource Controller Parameter Rename Not Working (L 5.7.8)

I can't seem to get Named resourceful route parameters working correctly (https://laravel.com/docs/5.3/controllers#restful-naming-resource-route-parameters)

I have this in my API routes:

Route::resource('members', 'MemberController', ['parameters' => ['member' => 'member_id']]);

When I list routes in Artisan I see, for example, this for the show route:

GET|HEAD  |  api/v3/members/{member}  |  members.show  | 
 App\Http\Controllers\[email protected]  |  api,auth:admin-api

I would expect to see:

GET|HEAD  |  api/v3/members/{member_id}  |  members.show  | 
 App\Http\Controllers\[email protected]  |  api,auth:admin-api

Any ideas please?

Oct
02
1 year ago
Activity icon

Replied to Using 5.7 Email Verification - Triggering Verification Email On Manual User Creation.

@Cronix I was testing on an old upgraded install. Been upgraded through last 4 or 5 versions so can't be trusted.

So I've just run up a new L5.7 install. The results are the same. So... it turns out that it IS working, but I didn't realise that I had to log-in again to complete the verification.

When testing with the form I'd been keeping the browser/session open, so when I used the link in the email it verified instantly. When using the seeder/manual user registration and using the link, it takes me to /login to re-authenticate the user.

Obvious really. I just need to find a way to put a message on the login screen in that particular circumstance so users (who are as stupid as I was) know that they are about to verify the account once they have logged in again.

Thanks a lot for your help!

Activity icon

Replied to Using 5.7 Email Verification - Triggering Verification Email On Manual User Creation.

@Cronix Hi, thanks. That’s interesting. If I try that an email DOES get sent, but the link in the email doesn’t work. It looks to be formatted correctly but it just sends me to /login. So... I wonder if the signature doesn’t match or wasn’t stored correctly at first.

@ekpono thanks, but unless I read the first bit of the tutorial wrong, that’s a custom verification method and not Laravel’s built-in one? I’d like to stick with the bundled tools at the moment thanks.

Activity icon

Started a new conversation Using 5.7 Email Verification - Triggering Verification Email On Manual User Creation.

I'm using Email Verification (https://laravel.com/docs/5.7/verification). When a user registers via the default registration form the verification email gets sent, and the process works end to end.

In my particular app, I manually register certain types of user. When I do this, the user gets created ok, but no verification is sent. I don't set the email_verified_at column to anything, just nam, email and pass. i.e:

User::create([
    'name' => 'First Example,
    'email' => '[email protected]',
    'password' => Hash::make('password'),
]);

I assumed there would be a listener that triggers the verification email on save, but... guess not!

Any ideas?

Activity icon

Replied to Verify Email Feature?

Just in case this discussion attracts any visitors from search: Laravel 5.7 ships with User email-based verification - https://laravel.com/docs/5.7/verification

Jul
24
1 year ago
Activity icon

Started a new conversation Forcing Single JSON Resource From An Eloquent Resource To Be Wrapped In Array Notation

Hi, hope that title hasn't confused y'all. It confused me. Some of the Laravel nomenclature seems to overlap.

I'm using Eloquent API Resources to format some JSON. When a collection is returned the format is:

{
    "data": [
        {
            "id": 1
        },
        {
            "id": 2
        },
        {
            "id": 3
        }
    ]
}

When it's a single resource it's:

{
    "data": {
        "id": 1
    }
}

The system I'm writing this API for requires everything to be in a JSON array (Maybe it's called a JSON object. I don't know) and but it needs to look like this:

{
    "data": [
        {
            "id": 1
        }
    ]
}

Using some hints from this thread by @johnvoncolln I've come up with this:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class ApplicationResource extends JsonResource
{

    protected $wrapbool;

    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return $this->checkArrayWrap([
            'id' => $this->id,
        ]);
    }

    public function arrayWrap( $wrapbool = true )
    {
        $this->wrapbool = $wrapbool;
        return $this;
    }

    protected function checkArrayWrap(array $array)
    {

        if ($this->wrapbool != false) {
            return collect([$array]);
        }

        return collect($array)->toArray();
    }
} 

...and from my controller (index) I call this for a collection:

return ApplicationResource::collection($applications);

and this for a single item (show):

$applicationResource = new ApplicationResource($application);
return $applicationResource->arrayWrap();

This works. It also looks pretty horrid and I'm sure there's a better 'separation of concerns' way to do it. Any advice on how to do this in one place for every JsonResource? I'm always going to need single resources from loads of different controllers to be wrapped in arrays. It might be that there's even a built-in helper that I've missed in the docs.

Thanks a lot!

Dec
21
1 year ago
Activity icon

Replied to Returning In A Returned Function Confusion

Ok I've found the getOriginalContent() (for Response objects) and getData() (for JsonResponse objects) methods. Using getOriginalContent()with my respondError call gets the string response I wanted without breaking the purpose of respondError.

e.g.

/**
* Check an ID.
*/
public function checkTxID($inid = null)
{
    if ($inid == 2) {
        $return = $this->respondError()->getOriginalContent();
    } else {
        $return = "OK";
    }
    return $return;
}

result:

"ERROR"

Thanks JonnyL for help.

Dec
20
1 year ago
Activity icon

Started a new conversation Returning In A Returned Function Confusion

Hi, I've got very confused with returning values from a function that itself tries to call a function that returns a value. This is in a fairly complex API project, so I've created a simple example of my problem here. I'm aware this is PHP101 stuff, and I have real brainfreeze on it...


// in TestController.php

    /**
     * Return an error response.
     */
    public function respondError() {
        return response('ERROR', 500);
    }

    /**
     * Check an ID.
     */
    public function checkTxID($inid = null)
    {
        if ($inid == 2) {
            $return = $this->respondError();
        } else {
            $return = "OK";
        }
        return $return;
    }

    /**
     * PUT / PATCH method.
     */
    public function update(Request $request, $oid)
    {
        $check = $this->checkTxID($oid);
        dump($check);
    }

When I PATCH /route/to/my/api/test/1 I get:

"OK"

When I PATCH /route/to/my/api/test/2 I get:

Response {#282
  +headers: ResponseHeaderBag {#289
    #computedCacheControl: array:2 [
      "no-cache" => true
      "private" => true
    ]
    //etc etc etc
  }
  #content: "Error"
  #version: "1.0"
  #statusCode: 500
  #statusText: "Internal Server Error"
  #charset: null
  +original: "Error"
  +exception: null
}

But what I want to see is:

"ERROR"

Obviously this is just an example, I'm actually trying to return JSON data in all instances, but this does illustrate my problem.

Essentially, how do I get respondError() to return it's own response, and not a Resposne object.

That sounds wrong... but I don't know how else to explain this. Help.

Nov
10
1 year ago
Activity icon

Replied to Help Re-populating Checkbox Array In Blade Template.

Hi Wilk, Thanks a lot, that was really useful and I'm now passing the array to the view with return view("manage.users.edit")->with('user', $user)->with('roles', $roles)->with('userroles', $userroles);

I did try and use the hasRole() function but when I try to call it with $user->hasRole() in the view I get nothing back, just null.

So I attempted to call it explicitly like so: App\Http\Controllers\UserController::hasRole() which then gives me a "Non-static method App\Http\Controllers\UserController::hasRole() should not be called statically" error. If I make the function static I get "Using $this when not in object context" error. So.. I'm going in circles now.

You've already helped a load, so don't worry if you're too busy, but IF you have time, I'd love to know how to get the scope right on this hasRole() function.

Thanks! Ben

Nov
08
1 year ago
Activity icon

Started a new conversation Help Re-populating Checkbox Array In Blade Template.

Hi, I'm trying to setup an array of roles checkboxes for a user management view. I have this, which works:

@php
    $userroles = $user->roles->pluck('id')->toArray();
@endphp

@foreach ($roles as $role)
    <div>
        <input class="checkbox" type="checkbox" name="roles[]" id="check-box-{{$role->id}}" value="{{ $role->id }}" {{ in_array($role->id, $userroles) ? "checked" : "" }} />
        <label for="check-box-{{$role->id}}">{{$role->display_name}}</label>
    </div>
@endforeach 

Knowing how many helper functions and methods Laravel has, I'm pretty sure I'm retrieving the previously set value a goofy way. Using in_array($role->id, $userroles) seems wrong.

Also, if possible I'd like to avoid the @php block. How SHOULD I be re-populating checkboxes?

Any ideas or corrections gratefully received!

Dec
14
2 years ago
Activity icon

Started a new conversation Fast/Cheap Way To Store / Retrieve / Increment A Single Transaction ID Integer

I'm building an API. The system that will be consuming this API always sends a sequential incrementing TxID with every block of JSON data it POST/PUT/PATCH's.

I want to check this TxID against a locally stored integer. If the number is out of sequence, or I've already been sent it, I will respond with an error and report the expected ID.

I'm looking for a very fast/cheap (low retrieval time and CPU usage) way to manipulate this integer. I was going to use a table with one column and one row, but this seems like overkill. If I use a text file, I'm worried that FileSystem access isn't very efficient. I wondered if Session storage was ok, but I believe that would only work per-user and this needs to be system wide.

Any clever ideas?

Nov
04
2 years ago
Activity icon

Replied to Get Inserted ID When PrimaryKey Isn't Autoincrement

Thanks both, yes I know it seems an odd question. I should have provided the example that prompted my question. In stripped down form I have this:

$memberStore = new Member;
$memberStore->mem_mid = $request->input('id');
$memberStore->mem_name = $request->input('name');

// at this point, $memberStore->mem_mid contains the 'id' I sent.

$memberStore->save();

// at this point, $memberStore->mem_mid = 0

Any idea why it gets stripped / removed / set to 0? I'm trying to return $memberStore via JSON and here's what I get:

"data": {
    "mem_mid": 0,
    "mem_name": "Benjamin's Builders",
}
Nov
03
2 years ago
Activity icon

Started a new conversation Get Inserted ID When PrimaryKey Isn't Autoincrement

I'm inserting items to a model with a non-auto-incrementing primary key. The PK isn't 'id' so I'm using this in my model:

protected $primaryKey = 'mem_mid';

The docs (https://laravel.com/docs/5.3/queries#inserts )say: If the table has an auto-incrementing id, use the insertGetId method to insert a record and then retrieve the ID:

$id = DB::table('users')->insertGetId(
    ['email' => '[email protected]', 'votes' => 0]
);

What if there isn't an auto-incrementing ID?

Sep
29
3 years ago
Activity icon

Replied to 5.3: Api Routes, Auth Middleware Confusion

I worked out what was wrong, thanks to lots of articles around the web and delving into the 5.3 code more than before. I think the links offered above probably do contain the answers but were a little too 'conceptual' for my tiny tired brain. Here's the 'answer' I posted to a similar question on SE:

If you are specifying routes in api.php, you will need to use the auth:api middleware. For example:

    Route::group(['middleware' => ['auth:api']], function () {
        Route::get('/test', function (Request $request) {
             return response()->json(['name' => 'test']);
        });
    });

Notes about Token auth and Laravel 5.3:

  • If you've setup laravel's default auth system, you will also need to add a column for api_token to the user table. If you are using DB seeders, you might want to add something like: $table->char('api_token', 60)->nullable(); to your users table seeder. Alternatively just add the column manually and fill that column with a random 60-char key.
  • When making the request, you can add the api_token as a URL/Querystring parameter like so: domain.com/api/test?api_token=[your 60 char key]. You can also send the key as a header (if using Postman or similar), i.e: Header: Authorization, Value: Bearer [your 60 char key].
  • I order to get a useful error if the token is incorrect, also send the following header with all requests: Header: Accept, Value: application/json. This allows the expectsJson() check in the unauthenticated() function inside App/Exceptions/Handler.php to work correctly.

I found it hard to find clear docs from Laravel about using token auth with 5.3, I think it's because there's a drive to make use of Passport, and it supports tokens in a different way. Here's the article that probably helped most getting it working: https://gistlog.co/JacobBennett/090369fbab0b31130b51

Sep
21
3 years ago
Activity icon

Replied to 5.3: Api Routes, Auth Middleware Confusion

Did you mean you want to see the routes? or that I should be able to see something in them that answers my question? Here they are anyway:

|        | GET|HEAD  | /                            |                 | Closure                                                                | web          |
|        | GET|HEAD  | api/v2                       |                 | Closure                                                                | api          |
|        | POST      | api/v2/members               | members.store   | App\Http\Controllers\[email protected]                           | api,auth:api |
|        | GET|HEAD  | api/v2/members               | members.index   | App\Http\Controllers\[email protected]                           | api,auth:api |
|        | GET|HEAD  | api/v2/members/create        | members.create  | App\Http\Controllers\[email protected]                          | api,auth:api |
|        | PUT|PATCH | api/v2/members/{member}      | members.update  | App\Http\Controllers\[email protected]                          | api,auth:api |
|        | GET|HEAD  | api/v2/members/{member}      | members.show    | App\Http\Controllers\[email protected]                            | api,auth:api |
|        | DELETE    | api/v2/members/{member}      | members.destroy | App\Http\Controllers\[email protected]                         | api,auth:api |
|        | GET|HEAD  | api/v2/members/{member}/edit | members.edit    | App\Http\Controllers\[email protected]                            | api,auth:api |
|        | GET|HEAD  | api/v2/user                  |                 | Closure                                                                | api,auth:api |
|        | GET|HEAD  | home                         |                 | App\Http\Controllers\[email protected]                              | web,auth     |
|        | GET|HEAD  | login                        | login           | App\Http\Controllers\Auth\[email protected]                | web,guest    |
|        | POST      | login                        |                 | App\Http\Controllers\Auth\[email protected]                        | web,guest    |
|        | POST      | logout                       |                 | App\Http\Controllers\Auth\[email protected]                       | web          |
|        | POST      | password/email               |                 | App\Http\Controllers\Auth\[email protected]  | web,guest    |
|        | POST      | password/reset               |                 | App\Http\Controllers\Auth\[email protected]                | web,guest    |
|        | GET|HEAD  | password/reset               |                 | App\Http\Controllers\Auth\[email protected] | web,guest    |
|        | GET|HEAD  | password/reset/{token}       |                 | App\Http\Controllers\Auth\[email protected]        | web,guest    |
|        | POST      | register                     |                 | App\Http\Controllers\Auth\[email protected]                  | web,guest    |
|        | GET|HEAD  | register                     |                 | App\Http\Controllers\Auth\[email protected]      | web,guest    |

Thanks!

Activity icon

Replied to 5.3: Api Routes, Auth Middleware Confusion

Ok, I've checked and I have the following guards:

'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
    ],

What does this tell you / me? As I'm using routes/api.php for my members route, I guess I should be using $this->middleware('auth:api');? I've added this to MembersController and I get the same thing, once logged in, if I try and go to http://domain.dev/api/v2/members I'm redirected to /home.

The fact that the guard driver is 'token' is probably key right? Do I need to be setting a token in the users table or something? If so any pointers how/where, or links to docs that explain it?

Thank you!

Activity icon

Started a new conversation 5.3: Api Routes, Auth Middleware Confusion

I'm getting very confused by the differences between routes set-up in web.php and ones in api.php. Also the differences between using $this->middleware('auth') and $this->middleware('auth:api'). Please be patient with me...

Setup:

  • I have fired up the standard auth setup with php artisan make:auth. registering and logging in with a user works and I end up at /home.
  • I have a controller called MembersController thats forming a API endpoint, returning JSON. With no auth, this is working as I want it to.
  • I have a route in routes/api.php like this:
Route::group(['prefix' => 'v2'], function() {
  Route::resource('members', 'MembersController');
});

To try and add authentication to MembersController I added:

public function __construct()
    {
        $this->middleware('auth');
    }

When I navigate to http://domain.dev/api/v2/members I get redirected to http://domain.dev/login. If I log in here I get redirected to /home "You are logged in!". GOOD. Now I'm logged in, if I try and go back to http://domain.dev/api/v2/members I get immediately redirected to /home. NOT GOOD.

Interestingly, if I add the members resource route to routes/web.php and not routes/api.php, after I log in I do get sent to /home, BUT if I try to go to http://domain.dev/api/v2/members it works, and I see my pretty pretty JSON :)

So... the reason I'm using the api routes is that I want to eventually get auth:api middleware working, and use token auth sent in a header, or a POST var. This is where I've found the docs get rather thin, but it's probably because I have some fundamental understanding missing.

By the way, if someone fancies some StackExchange points, this person is having exactly the same issue it seems: http://stackoverflow.com/questions/39561695/laravel-5-3-api (not my question)