ahoi

ahoi

Member Since 9 Months Ago

Experience Points 2,810
Experience Level 1

2,190 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 0
Lessons
Completed
Best Reply Awards 0
Best Reply
Awards
  • Start Your Engines Achievement

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • First Thousand Achievement

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • One Year Member Achievement

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • Two Year Member Achievement

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • Three Year Member Achievement

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • Four Year Member Achievement

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • Five Year Member Achievement

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • School In Session Achievement

    School In Session

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

  • Welcome To The Community Achievement

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • Full Time Learner Achievement

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • Pay It Forward Achievement

    Pay It Forward

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

  • Subscriber Achievement

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • Lifer Achievement

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • Laracasts Evangelist Achievement

    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 Achievement

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • Laracasts Veteran Achievement

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • Ten Thousand Strong Achievement

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • Laracasts Master Achievement

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • Laracasts Tutor Achievement

    Laracasts Tutor

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

  • Laracasts Sensei Achievement

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • Top 50 Achievement

    Top 50

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

19 Jun
6 days ago

ahoi left a reply on Serverside Breadcrumbs Or Clients Side

Basically, I think that there is nothing against generating the breadcrumbs on the server side. The relevant package has already been mentioned.

If you are planning to build a Vue.js SPA, the question is answered already - it would be best to build a client-side solution.

Conclusion: It depends on what you build and how :-)

17 Jun
1 week ago

ahoi started a new conversation Validation: String IS NOT

Hello everybody,

I am just writing an update method that should update roles. I would like to prevent a user to choose a reserved name (super-admin).

Is there a validation rule for string IS NOT or do I have to use the regex-rule here?

16 Jun
1 week ago

ahoi started a new conversation GroupBy And MapToGroups Returns Object In API Resource

Hello everybody,

I am creating an API resource:

public function toArray($request) { return [ 'permissions' => Permission::all() ]; }

This is the result Permission::all() in my browser's console:

{
  "data": {
    "permissions": [
      {
        "id": 1,
        "name": "index users",
        "guard_name": "web",
        "created_at": "2019-06-11 06:45:52",
        "updated_at": "2019-06-11 06:45:52"
      },
      {
        "id": 2,
        "name": "create users",
        "guard_name": "web",
        "created_at": "2019-06-11 06:45:52",
        "updated_at": "2019-06-11 06:45:52"
      },
      {
        "id": 3,
        "name": "view users",
        "guard_name": "web",
        "created_at": "2019-06-11 06:45:52",
        "updated_at": "2019-06-11 06:45:52"
      },
      {
        "id": 4,
        "name": "update users",
        "guard_name": "web",
        "created_at": "2019-06-11 06:45:52",
        "updated_at": "2019-06-11 06:45:52"
      },
      {
        "id": 5,
        "name": "delete users",
        "guard_name": "web",
        "created_at": "2019-06-11 06:45:52",
        "updated_at": "2019-06-11 06:45:52"
      },
      {
        "id": 21,
        "name": "index settings",
        "guard_name": "web",
        "created_at": "2019-06-11 06:45:52",
        "updated_at": "2019-06-11 06:45:52"
      },
      {
        "id": 22,
        "name": "view settings",
        "guard_name": "web",
        "created_at": "2019-06-11 06:45:52",
        "updated_at": "2019-06-11 06:45:52"
      },
      {
        "id": 23,
        "name": "update settings",
        "guard_name": "web",
        "created_at": "2019-06-11 06:45:52",
        "updated_at": "2019-06-11 06:45:52"
      }
    ]
  }
}

I would like to an array like this:

[
{ 'group': 'users', 'view': true, 'edit': false, 'create': true, 'delete':
true },
{ 'group': 'settings', 'view': true, 'edit': false, 'create': true, 'delete':
true },
]

This is what I got so far:

Permission::all()->mapToGroups(function
            ($item){
                $exploded = explode(' ', $item->name);
                $item->group = $exploded[1];
                $item->verb = $exploded[0];
                $item->can = [$item->verb => true];

                return [$item['group'] => $item['can']];
            })->map(function($group){
                $permission = $group->collapse();
                return $permission;
            })

This is the result in my browser's console:

{
    "data": {
        "permissions": {
            "users": {
                "index": true,
                "create": true,
                "view": true,
                "update": true,
                "delete": true
            },
            "settings": {
                "index": true,
                "view": true,
                "update": true
            }
        }
    }
}

These are my questions:

  • As you can see, the result is an object, not an array. How can I change it to an array?
  • How can I remove the key ('settings', 'user', ...) and move them to the single array like in my example?
14 Jun
1 week ago

ahoi started a new conversation Use Explode In Collection To Group By Second Value

Hello everybody,

I am using spatie/laravel-permission (https://github.com/spatie/laravel-permission) to define permissions and roles.

Now I'd like to create a view which lists all the permissions in a table.

To archive this, I am building an API resource, which should contain:

This is what I want to archive:

permissions: [
        { module: 'User', view: true, create: false, delete: false },
        { module: 'Todo', view: true, create: false, delete: false },
      ],

The name of the permission is always verb-model (view-user, create-user, delete-user, view-todo, create-todo, ...)

So I thought about splitting the name of each Permission using explode.

So I would get:

['view', 'user']
['create', 'user']
['delete', 'user']
...

This array could be grouped in my resource.

So I could do something like:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
use Spatie\Permission\Models\Permission;


class UserRoleResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request $request
     *
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id'          => $this->id,
            'name'        => $this->name,
            'permissions' => Permission::all()->each(function($permission){
                //return the exploded array
            })
        ];
    }
    
}

But there's maybe an easier way with Laravel?

Thank you for your thoughts about this :-)

08 Jun
2 weeks ago

ahoi started a new conversation V-validate On Dynamic Custom Component

Hello everybody,

I am using Vee-validate (https://baianat.github.io/vee-validate/) to validate all my forms. Now I would like to do the following:

In my form the "value" field is a dynamic component, depending on the type of the current object. Type can be integer, string, decimal etc.

So if the type changes, the input changes, too.

This is how I did this:

   <component
                                            :name="'attribute-value'"
                                            v-model="attribute.value"
                                            :is="attribute.type">
                                    </component>

And

import string from '@/components/fields/String'
import integer from '@/components/fields/Integer'
import decimal from '@/components/fields/Decimal'

export default {
        name: 'edit',
        metaInfo: {
        title: 'Edit'
        },
        components: {
            string, integer, decimal
        },
}

Alright - each field should have it's own validation. The integer-field should only allow numbers. So I would like to do this:

<template>
    <b-input
            :id="name"
            :name="name"
            type="number"
            v-validate="{ required: true, numeric: true }"
            :state="errors.has(name) ? 'invalid' : ''"
            :value="value"
            v-on:input="$emit('input',$event)"/>
</template>
<script>
export default {
    name: 'Integer',
    inject: {
        $validator: '$validator'
    },
    props: ['name', 'value'],

    $_veeValidate: {
        name() {
            return this.name;
        },
        value() {
            return this.value;
        }
    },
}
</script>

Unfortunately, there are no errors shown, if I enter something else than a number. And: The submit-method on the parent component does not prevent the submission.

I am thankful for all of your comments :-)

30 May
3 weeks ago

ahoi left a reply on Set LC_MONETARY Globally

Hm, that's strange.

I added this to bootstrap/app.php:

setlocale(LC_MONETARY, 'de_DE');
echo money_format('%!n€', 23.50);
var_dump(localeconv());
die;

This is the output:

23.50€
/home/vagrant/code/bootstrap/app.php:15:
array (size=18)
  'decimal_point' => string '.' (length=1)
  'thousands_sep' => string '' (length=0)
  'int_curr_symbol' => string '' (length=0)
  'currency_symbol' => string '' (length=0)
  'mon_decimal_point' => string '' (length=0)
  'mon_thousands_sep' => string '' (length=0)
  'positive_sign' => string '' (length=0)
  'negative_sign' => string '' (length=0)
  'int_frac_digits' => int 127
  'frac_digits' => int 127
  'p_cs_precedes' => int 127
  'p_sep_by_space' => int 127
  'n_cs_precedes' => int 127
  'n_sep_by_space' => int 127
  'p_sign_posn' => int 127
  'n_sign_posn' => int 127
  'grouping' => 
    array (size=0)
      empty
  'mon_grouping' => 
    array (size=0)
      empty

If I run this code in a single PHP code runner, I get:

23,50€array(18) {
  ["decimal_point"]=>
  string(1) "."
  ["thousands_sep"]=>
  string(0) ""
  ["int_curr_symbol"]=>
  string(4) "EUR "
  ["currency_symbol"]=>
  string(2) "Eu"
  ["mon_decimal_point"]=>
  string(1) ","
  ["mon_thousands_sep"]=>
  string(1) "."
  ["positive_sign"]=>
  string(0) ""
  ["negative_sign"]=>
  string(1) "-"
  ["int_frac_digits"]=>
  int(2)
  ["frac_digits"]=>
  int(2)
  ["p_cs_precedes"]=>
  int(1)
  ["p_sep_by_space"]=>
  int(0)
  ["n_cs_precedes"]=>
  int(1)
  ["n_sep_by_space"]=>
  int(0)
  ["p_sign_posn"]=>
  int(1)
  ["n_sign_posn"]=>
  int(1)
  ["grouping"]=>
  array(0) {
  }
  ["mon_grouping"]=>
  array(2) {
    [0]=>
    int(3)
    [1]=>
    int(3)
  }
}

I had to run sudo locale-gen de_DE.UTF-8 on my homestead vm - now it works fine. Thanks a lot!

ahoi left a reply on Set LC_MONETARY Globally

Strange, I am getting a 500 when I try to store this text (on create and on edit).

The last two sentences are missing:

But this does not seem to affect LC_MONETARY? If I add @money(12.5) to a blade-file, the output is: 12.50€and not `12,50?as it was expected.

So my question is: How can I set LC_MONETARY correctly?

ahoi started a new conversation Set LC_MONETARY Globally

Hello,

I would like to migrate this little snippet to Laravel:

function money($value){
    setlocale(LC_MONETARY, 'de_DE');
    return money_format('%!n€', $value);

}

echo money(1620.5);

>> 1.620,50€

Well, now I would like to create a custom blade directive:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Blade;


class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Blade::directive('money', function ($value) {
            return "<?php echo money_format('%!n€', $value); ?>";
        });
    }
}

Hm, now I have to set the locale. I created a middleware for this:

<?php

namespace App\Http\Middleware;

use Closure;

class SetLocale
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        app()->setLocale('de_DE');
        
        return $next($request);
    }
}

And of course I registered that in Kernel.php:

 protected $middleware = [
        \App\Http\Middleware\SetLocale::class,
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\TrustProxies::class,
    ];

But this does not seem to affect LC_MONETARY? If I add @money(12.5) to a blade-file, the output is: 12.50€nd not `12,50?s it was expected.

So my question is: How can I set LC_MONETARY correctly?

29 May
3 weeks ago

ahoi left a reply on Map() Does Not Create A New Instance But Modifies Collection

Yep, that was my mistake. Thanks a lot for opening my eyes :-) It works as expected now.

ahoi started a new conversation Map() Does Not Create A New Instance But Modifies Collection

Hello,

I would like to group a collection by a specific key (interval). Before I do that, I would like to search for collection items, where setup > 0 and modify the findings, because I need to set "price" = "setup" for those items. I also need to change the interval, because a setup fee is only paid once.

This is what I did to prepare this:

$collection = collect(json_decode($items));

=> Illuminate\Support\Collection {#3086
     all: [
       {#3076
         +"price": 99,
         +"setup": 15,
         +"interval": 1,
       },
     ],
   }

Alright, now let's search for items with setup costs and create a new collection:

$setups = $collection->where('setup', '>', 0)->map(function (
            $item,
            $key
        ) {
            $item->price          = $item->setup;
            $item->setup          = 0;        
            $item->interval       = 0;        
            return $item;
        });

=> Illuminate\Support\Collection {#3071
     all: [
       {#3076
         +"price": 15,
         +"setup": 0,
         +"interval": 0,
       },
     ],
   }

Hmmmm... Thats not cool. The initial collection #3076 has been modified, but shouldn't map() create a new one?

$collection

=> Illuminate\Support\Collection {#3086
     all: [
       {#3076
         +"price": 15,
         +"setup": 0,
         +"interval": 0,
       },
     ],
   }


$setups

=> Illuminate\Support\Collection {#3071
     all: [
       {#3076
         +"price": 15,
         +"setup": 0,
         +"interval": 0,
       },
     ],
   }

https://laravel.com/docs/5.8/collections#method-map:

Like most other collection methods, map returns a new collection instance; it does not modify the collection it is called on. If you want to transform the original collection, use the transform method.

So my questions are:

  • How can I search for $items that have a setup fee and store them in a new collection?
  • Is there a more convenient way to duplicate items that have a setup fee and modify the duplicated value to have the price = setup? As a result I would like to get a grouped array that is grouped by interval. The interval of setup should always be 0;

Thanks for your help :-)

14 May
1 month ago

ahoi started a new conversation Webpack Chunk Names With Laravel Mix

I'd like to use Webpack chunks with Laravel Mix.

At the moment this list is outputted:

                                               Asset      Size        Chunks             Chunk Names
                                     /entry-point.js  3.37 MiB  /entry-point  [emitted]  /entry-point
                                                0.js  57.9 KiB             0  [emitted]  
                                                1.js  20.7 KiB             1  [emitted]  
                                               10.js  24.2 KiB            10  [emitted]  
                                               11.js  17.8 KiB            11  [emitted]  
                                               12.js  17.3 KiB            12  [emitted]  
                                               13.js  20.3 KiB            13  [emitted]  
                                               14.js  34.3 KiB            14  [emitted]  
                                               15.js  16.3 KiB            15  [emitted]  
                                               16.js  16.3 KiB            16  [emitted]  
                                               17.js  18.8 KiB            17  [emitted]  
                                               18.js  9.34 KiB            18  [emitted]  
                                               19.js  18.2 KiB            19  [emitted]  
                                                2.js   487 KiB             2  [emitted]  
                                               20.js  18.2 KiB            20  [emitted]  
                                               21.js  17.2 KiB            21  [emitted]  
                                               22.js  13.3 KiB            22  [emitted]  
                                               23.js    54 KiB            23  [emitted]  
                                               24.js  53.8 KiB            24  [emitted]  
                                               25.js  17.9 KiB            25  [emitted]  
                                               26.js  23.6 KiB            26  [emitted]  
                                               27.js  29.4 KiB            27  [emitted]  
                                               28.js  29.4 KiB            28  [emitted]  
                                               29.js  19.5 KiB            29  [emitted]  
                                                3.js   128 KiB             3  [emitted]  
                                               30.js    17 KiB            30  [emitted]  
                                               31.js  13.1 KiB            31  [emitted]  
                                               32.js  33.4 KiB            32  [emitted]  
                                                4.js   104 KiB             4  [emitted]  
                                                5.js  70.1 KiB             5  [emitted]  
                                                6.js  82.9 KiB             6  [emitted]  
                                                7.js  89.1 KiB             7  [emitted]  
                                                8.js   959 KiB             8  [emitted]  
                                                9.js  38.1 KiB             9  [emitted]  

This is my route definition:

export default [{
    path: '/user',
    component: Layout2,
    children: [
        {
            path: '/',
            name: 'user',
            component: () => /* webpackChunkName: "view-[request]" */ import('@/components/user'),
        },
    ]
}]

And this is my Webpack config:

/**
 * As our first step, we'll pull in the user's webpack.mix.js
 * file. Based on what the user requests in that file,
 * a generic config object will be constructed for us.
 */
let mix = require('laravel-mix/src/index');

let ComponentFactory = require('laravel-mix/src/components/ComponentFactory');

new ComponentFactory().installAll();

require(Mix.paths.mix());

/**
 * Just in case the user needs to hook into this point
 * in the build process, we'll make an announcement.
 */

Mix.dispatch('init', Mix);

/**
 * Now that we know which build tasks are required by the
 * user, we can dynamically create a configuration object
 * for Webpack. And that's all there is to it. Simple!
 */

let WebpackConfig = require('laravel-mix/src/builder/WebpackConfig');

const config = new WebpackConfig().build();

// Inject sass-loader options
config.module.rules
.filter(rule => rule.test.test && (rule.test.test('.sass') || rule.test.test('.scss')))
.forEach(rule => {
    const sassLoader = rule.loaders.find(loader => loader.loader === 'sass-loader');

    if (sassLoader) {
        Object.assign(sassLoader.options, {
            precision: 5,
            implementation: require('node-sass')
        });
    }
});

// Fix Hot Module Replacement bug
if (Mix.isUsing('hmr')) {
    // Remove leading '/' from entry keys
    config.entry = Object.keys(config.entry)
    .reduce((entries, entry) => {
        entries[entry.replace(/^\//, '')] = config.entry[entry];
        return entries;
    }, {});

    // Remove leading '/' from ExtractTextPlugin instances
    config.plugins
    .forEach((plugin) => {
        if (plugin.constructor.name === 'ExtractTextPlugin') {
            plugin.filename = plugin.filename.replace(/^\//, '');
        }
    });
}



module.exports = config;

Now I am wondering why all the files are named 0.js etc. and not like the webpackChunkName.

Additionally I'd like to use cache-busting on the chunks as they are always cached by my browser, so if I re-run Webpack, I often need to clear my cache completely.

My questions are:

  • How can I make use of the WebpackChunkName correctly?
  • How can I prevent caching of the chunks?
06 May
1 month ago

ahoi left a reply on Missing Parameter For Vue-router When Using BeforeRouteEnter

Hi @bobbybouwmann

I am using vuex to store the data of the logged-in user. The user the edit link is placed for is a user the authenticated user is managing.

ahoi started a new conversation Missing Parameter For Vue-router When Using BeforeRouteEnter

Hello everybody,

I am using the vue-router to navigate through my SPA.

This is my router:

export default [{
    path: '/user',
    component: Layout2,
    meta: {
        requiresAuth: true
    },
    children: [
        {
            path: '/',
            name: 'user',
            component: () => /* webpackChunkName: "view-[request]" */ import('@/components/Index'),
            meta: {
                requiresAuth: true
            },
        },
        {
            path: ':id',
            name: 'user.view',
            component: () => /* webpackChunkName: "view-[request]" */ import('@/components/View'),
            meta: {
                requiresAuth: true
            },
        },
        {
            path: ':id/edit',
            name: 'user.edit',
            component: () => /* webpackChunkName: "view-[request]" */ import('@/components/Edit'),
            meta: {
                requiresAuth: true
            },
        },
    ]
}]

Now I added this:

<b-btn variant="primary" size="sm" :to="{ name: 'user.edit', params: { id: user.id }}">Edit</b-btn>

It's a part of vue-bootstrap.

I also make use of beforeRouteEnter:

data: () => ({
        user: {},
    }),
    beforeRouteEnter (to, _from, next) {
        axios
        .get ('/api/user/' + to.params.id).then ((resp) => {
            next ((vm) => {
                vm.user = resp.data.data;
            });
        });
    },

Alright - this seems to work - but I am receiving this warning:

[vue-router] missing param for named route "user.edit": Expected "id" to be defined

If I dump user.id in my component, 1 is being returned.

So now I am wondering: The component shouldn't be rendered if beforeRouteEnter is not finished, right? But why do I get this warning?

29 Apr
1 month ago

ahoi left a reply on Using Vue To Authenticate With Laravel/passport?

I had a look at this project: https://github.com/andranikbadalyan/Laravel-Passport-Vue-Auth/tree/c92b3f5df210c46a271b9a93e45f7c3fa86a3209

You can use this to set up auth with passport. I did it and it works (for now ;-) )

27 Apr
1 month ago

ahoi started a new conversation Using Vue To Authenticate With Laravel/passport?

Hello,

I would like to create my first SPA; I am using vue-router and vuex to handle routes and states.

Now I'd like to use laravel/passport with Vue to authenticate, but to be honest: I only find tutorials with using tymondesigns/jwt-auth.

So my question is: Are there good docs for user login/logout with Passport? Thank you very much!

24 Apr
2 months ago

ahoi left a reply on Alias For Model?

Ok, so I misunderstood your post. Thank you very much ?

ahoi left a reply on Alias For Model?

Hi @snapey ,

I'm sorry, I didn't make myself clear.

I referred to your blog and its profile types AdminProfile and CustomerProfile.

It would be great if a user could have both types. A third profile type would not be necessary, would it? But at the moment I can't manage that a user can have both profile types.

Thanks again in advance :-)

ahoi left a reply on Alias For Model?

Hi @snapey

Your answer fits my needs. But I got another question: Would it be possible somehow that a User can have both user profile types?

So a User could be an AdminUser and a Customer the same time.

I tinkered around with morphMany but there I only got it working if the profiles have the same class.

15 Apr
2 months ago

ahoi started a new conversation Watch Array For Changes And Prevent Items To Be Empty

Hello everybody,

I got an array of objects like this:

item.list:

[
  {
    price: 1,
    factor: 1
  },
  {
    price: 1,
    factor: 2
  },
]

Now I would like to create a watcher, that prevents price or factor to be empty. If it is, it automatically should be set to 0.

I would do it like this:

'item.list': {
    handler: function (val, oldVal) {

        //how to get the key of the changed object here? 
    },
    deep: true
}

But unfortunately I don't get the key of the changed element?

12 Apr
2 months ago

ahoi left a reply on Alias For Model?

Hi @snapey

That's what I would love to do... But how can I make sure that only users having the "customers" role are linked to that model?

11 Apr
2 months ago

ahoi started a new conversation Alias For Model?

Hello everybody,

I got a Model called User. Each user can have an id, name, email, role etc.

Now I would like to create a model that is called Customer, which allows a customer to log in. But a Customer should always be a User with the role customer.

Is it possible to create an alias that defines a Customer to be a User that has a specific role assigned like this:

$customer->assignRole('customers');
09 Apr
2 months ago

ahoi started a new conversation Update Model With Dynamic HasMany-relation

Hello everybody,

I got a model that is called Car. This Car hasMany Attributes.

An attribute looks like this:

id = int
car_id = int
description = text

Now I can create a new Car and assign many Attributes. If I update the Car, I also would like to update the Attributes.

This is how I'd do this at the moment:

public function update(Request $request)
{
    /*Get car*/
    $car = Car::findOrFail($request->car_id);
    
    /*Get car attributes and delete them*/
    $car->attributes->each(function ($attribute) {
        $attribute->delete();
    });
    
    /*Save new attributes*/
    $attributes = $request->input('data.attributes');
    
    foreach ($attributes as $attribute) {
        Attribute::create([
            'car_id'      => $car->id,
            'description' => $attribute['description'],
        ]);
    }
    
    /*Update car title*/
    $car->title = $request->input('data.title');
    $car->save();
    
    return response()->json(['message' => 'success']);
}

So first of all I'd delete all attributes and recreate them afterwards according to the input. Is there any room for improvements here? How would you update these dynamic fields?

27 Mar
2 months ago

ahoi started a new conversation Add Object To An Array And Modify It Without Modifying The Initial Object

Hello everybody,

I created a little codepen to demonstrate my issue: https://codepen.io/spqrinc/pen/moYKZo

If you add "hello" from the select field multiple times, there will be text input fields where you can edit the value of this specific element. Well: That's the plan.

But if you change the title of one "hello" field, all other entries are getting a new title, too. How can I prevent this? I would like to have this new title only on the specific entry.

This is my source:

new Vue({
    el: '#app',
    data: {
        items: [
            {title: 'hello'},
            {title: 'world'}
        ],
        itemlist: [],
        newItem: {}
    },
    methods: {
        addItem: function (option) {
            this.itemlist.push (this.newItem);
        },
    },
});
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<div id="app">
    <select v-model="newItem">
        <option v-for="item in items"
                :value="item">{{item.title}}
        </option>
    </select>
    <button v-on:click="addItem">Add</button>
    <div v-for="item in itemlist">
        <input v-model="item.title"/>
    </div>
</div>
</body>
</html>
16 Mar
3 months ago

ahoi started a new conversation 70GB Of Logs (Laravel.log) Because Of Failing Job?

Hi there,

today, my queue worker wrote round about 70GB of logs (laravel.log). It was always the same message:

[2019-03-16 21:09:07] local.ERROR: include(/var/www/example.org/example/vendor/composer/../laravel/framework/src/Illuminate/Queue/FailingJob.php): failed to open stream: No such file or directory {"exception":"[object] (ErrorException(code: 0): include(/var/www/example.org/example/vendor/composer/../laravel/framework/src/Illuminate/Queue/FailingJob.php): failed to open stream: No such file or directory at /var/www/example.org/example/vendor/composer/ClassLoader.php:444)
[stacktrace]
#0 /var/www/example.org/example/vendor/composer/ClassLoader.php(444): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'include(/var/ww...', '/var/www/netzhe...', 444, Array)
#1 /var/www/example.org/example/vendor/composer/ClassLoader.php(444): include()
#2 /var/www/example.org/example/vendor/composer/ClassLoader.php(322): Composer\Autoload\includeFile('/var/www/netzhe...')
#3 [internal function]: Composer\Autoload\ClassLoader->loadClass('Illuminate\\Queu...')
#4 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(440): spl_autoload_call('Illuminate\\Queu...')
#5 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(426): Illuminate\Queue\Worker->failJob('redis', Object(Illuminate\Queue\Jobs\RedisJob), Object(ErrorException))
#6 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(358): Illuminate\Queue\Worker->markJobAsFailedIfWillExceedMaxAttempts('redis', Object(Illuminate\Queue\Jobs\RedisJob), 3, Object(ErrorException))
#7 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(331): Illuminate\Queue\Worker->handleJobException('redis', Object(Illuminate\Queue\Jobs\RedisJob), Object(Illuminate\Queue\WorkerOptions), Object(ErrorException))
#8 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(277): Illuminate\Queue\Worker->process('redis', Object(Illuminate\Queue\Jobs\RedisJob), Object(Illuminate\Queue\WorkerOptions))
#9 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(118): Illuminate\Queue\Worker->runJob(Object(Illuminate\Queue\Jobs\RedisJob), 'redis', Object(Illuminate\Queue\WorkerOptions))
#10 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(102): Illuminate\Queue\Worker->daemon('redis', 'default', Object(Illuminate\Queue\WorkerOptions))
#11 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(86): Illuminate\Queue\Console\WorkCommand->runWorker('redis', 'default')
#12 [internal function]: Illuminate\Queue\Console\WorkCommand->handle()
#13 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(29): call_user_func_array(Array, Array)
#14 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(87): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#15 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(31): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#16 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Container/Container.php(572): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#17 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Console/Command.php(183): Illuminate\Container\Container->call(Array)
#18 /var/www/example.org/example/vendor/symfony/console/Command/Command.php(255): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#19 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Console/Command.php(170): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#20 /var/www/example.org/example/vendor/symfony/console/Application.php(901): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#21 /var/www/example.org/example/vendor/symfony/console/Application.php(262): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Queue\Console\WorkCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#22 /var/www/example.org/example/vendor/symfony/console/Application.php(145): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#23 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Console/Application.php(89): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#24 /var/www/example.org/example/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(122): Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#25 /var/www/example.org/example/artisan(37): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#26 {main}
"} 

Is it correct that a specific file could not be found by ClassLoader or don't I understand that correctly?

I just did a composer dump-autoload...

03 Mar
3 months ago

ahoi left a reply on Modify Array Before Saving It

This helps a lot! Thank you very much!

02 Mar
3 months ago

ahoi started a new conversation Modify Array Before Saving It

Hello everybody,

I am using a JSON field in my database. Now, I am saving an Array in it that is converted to JSON before:

User model

 protected $casts
        = [
            'options' => 'array',
        ];

Saving an option

$options = $user->options;                                                                                                                                                                       $options['notify'] = true;                                                                                                                                                               $user->options = $options;                                                                                                                                                                       $user->save();    

Now the Array comes from an user form input, this is validated as array.

Is it possible to modify this array before saving to make sure that it contains at least the field notify? If the array does not contain thenotify field, create one with value false.

I thought I could use something like this:

    public function setOptionsAttribute($value)
    {
        $this->attributes['options'] = json_encode($value); //TODO: Check for correct entries, ...
    }

Is this the suggested way?

Another question: On saving, does

            'options'              => 'array',

prevent my app from SQL-injection attacks or do I have to manually check the input?

ahoi left a reply on JSON In API Resource Is Quoted?

Hm, that's strange...

In my browser (app) the JSON user.options looks like this:

{"notify_on_mail":true}

But if I try to access user.options.notify_on_mail I am getting undefined. I also renamed notify_on_mail to notify, without success.

01 Mar
3 months ago

ahoi started a new conversation JSON In API Resource Is Quoted?

Hi everybody,

I my API Resource I am accessing $user->options, which is a JSON field:

        Schema::table('users', function (Blueprint $table) {
            $table->json('options');
        });
<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Gate;

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

Now my result (seen on my browser's network console) is this:

options: "{\"notify_on_mail\":true}"

How can I return this unquoted?

The problem: I can not access this in Vue.js:

undefined is not an object (evaluating '_vm.user.options.notify_on_mail')

Your help is highly appreciated :-)

20 Feb
4 months ago

ahoi started a new conversation Get ID Of Created Element In Observer

Hey there,

I am using an observer (https://laravel.com/docs/5.7/eloquent#observers) to create a App\Team, once a App\Group is created:

    public function created(Group $group)
    {
        if (request()->has('data.name')) {
            Team::create([
                'name'       => $company->name,
                'owner_id'   => request()->user()->getKey(),
                'group_id'   => $group->id,
            ]);
            
            request()->user()->attachTeam($team);

            $group->team_id = $team->id;
            $group->save();
        }
    }

Unfortunately

'group_id'   => $group->id,

is always saving null, as $group->id is empty. I thought the created event fires after the entry is created? At this moment it should already have an ID?

I am very happy for every hint you can give me :-)

10 Feb
4 months ago

ahoi started a new conversation Axios.get(): Not Allowed By Access-Control-Allow-Headers.

Hello everybody,

at the moment, I am trying to use axios to send a little GET request:

axios.get (process.env.MIX_MATOMO_URL + '/index.php?module=API&method=AjaxOptOut.isTracked&format=json').then ((response) => {
                this.tracked = response.value;
});

This fails with:

Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers.

Alright - I added my domain to Matomo's cors_domains - but without success.

Any help is highly appreciated :-)

ahoi started a new conversation Send Verification Mail On Socialite Login

Hello everybody,

actually I am using MustVerifyEmail on user's registration:

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Laravel\Scout\Searchable;


class User extends Authenticatable
    implements MustVerifyEmail
{
    use Notifiable,  Searchable;
}
    

Now I am additionally using Laravel Scout to login using Facebook and Twitter.

I created a login controller and added this:

function findOrCreateUser($providerUser, $provider)
{
    
    $user = User::create([
        'email'     => $providerUser->getEmail(),
        'lastname'  => $providerUser->user['last_name'],
        'firstname' => $providerUser->user['first_name'],
    ]);
    
    
    event(new Registered($user));    
    
    return $user;
}

Now I am triggering this event manually: event(new Registered($user)); to send the verification mail. I am just wondering: Is there a more elegant way to archive this?

03 Feb
4 months ago

ahoi left a reply on Use More Complex Where Clauses In Scout

Hm, unfortunately I did not solve this issue yet.

The problem is that Scout allows only numeric values here.

Scout does not allow < or >.

I solved the status-problem like this:

 /**
     * Get the indexable data array for the model.
     *
     * @return array
     */
    public function toSearchableArray()
    {
        return [
            'id'       => $this->id,
            'status'   => $this->status == 'active' ? 1 : 0,
        ];
    }

But I still can not search for entries that have been published between two dates.

I thought I could use the shouldBeSearchable() like this:

public function shouldBeSearchable()
{
    return $this->starts_on > now();
}

But as I understood it, this method only defines, whether an entry is pushed to Algolia or not. As the entry is not updated between the creation-date and now(), it will not be deleted from Algolia, right?

28 Jan
4 months ago

ahoi started a new conversation Session Expired -> Redirect To / Instead Of /login

Hello everybody,

I am just wondering, why Laravel is redirecting a user to /login by default.

Could it be possible to redirect to / instead?

Maybe by changing the ExceptionHandler?

What's best practice here?

26 Jan
4 months ago

ahoi started a new conversation Use More Complex Where Clauses In Scout

Hi,

I am a happy user of Laravel Scout.

Now I'd like to extend my search:

            $data
                = new UserOverviewResourceCollection(User::search($searchphrase)
                ->currentStatus('active')->orderBy('lastname', 'asc')
                ->orderBy('firstname', 'asc')
                ->paginate(config('pagination.length')));

currentStatus comes from https://github.com/spatie/laravel-model-status .

Now I am getting a response, that currentStatus is not supported. I thought I could be a good idea to filter the result of User::search after it has been returned from scout?

Another idea: I'd like to add more complex where clauses:

>where([
                [
                    'starts_on',
                    '<',
                    Carbon::now()->toDateTimeString(),
                ],
                [
                    'ends_on',
                    '>',
                    Carbon::now()->toDateTimeString(),
                ],
            ])

Maybe you got a better idea?

17 Jan
5 months ago

ahoi left a reply on Install And Laravel-echo-server Multiple Times On The Same Server

Hi and thank you for your response.

I just had a look at laravel-websockets. Is it correct that I still have to register at pusher.com (because the example uses PUSHER_APP_KEY etc.)?

16 Jan
5 months ago

ahoi started a new conversation Install And Laravel-echo-server Multiple Times On The Same Server

Hello everybody,

I am using Laravel Echo Server for a real-time-notification of my users.

As I got a staging-system on the same server as my live-system, I'd like to install (and run) the echo-server twice.

Is that possible?

ahoi left a reply on Using Private Channels On Laravel Echo

Solved it. The variable has to be included somewhere in your JS.

Actually I'm doing it like this at the moment (example with user):

  <script>
        window.App = {!! json_encode([
        'user' => auth()->check() ? auth()->user()->id : null,
    ]) !!};
    </script>
window.Echo.private('App.User.'+window.App.user)

ahoi left a reply on Event Is Emitted Twice?

@BOBBYBOUWMANN - The component was included twice (once for large devices and once for mobile devices).

Thanks to your hint I figured out, how scatterbrained I can be sometimes :-D

Thank you!

15 Jan
5 months ago

ahoi started a new conversation Event Is Emitted Twice?

Hello everybody,

I got the problem that an event is emitted twice somehow. I can not explain this behavior:

This is my bootstrap.js:

//
window._ = require("lodash");

window.Vue = require("vue");

Vue.prototype.$eventHub = new Vue();

Vue.component('messagebar', require('./components/MessageBar.vue'));

/**
 * We'll load the axios HTTP library which allows us to easily issue requests
 * to our Laravel back-end. This library automatically handles sending the
 * CSRF token as a header based on the value of the "XSRF" token cookie.
 */

window.axios = require("axios");

window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";

/**
 * Next we will register the CSRF Token as a common header with Axios so that
 * all outgoing HTTP requests automatically have it attached. This is just
 * a simple convenience so we don't have to attach every token manually.
 */

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
  window.axios.defaults.headers.common["X-CSRF-TOKEN"] = token.content;
} else {
  console.error(
    "CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token"
  );
}

/**
 * Echo exposes an expressive API for subscribing to channels and listening
 * for events that are broadcast by Laravel. Echo and event broadcasting
 * allows your team to easily build robust real-time web applications.
 */

// import Echo from 'laravel-echo'

// window.Pusher = require('pusher-js');

// window.Echo = new Echo({
//     broadcaster: 'pusher',
//     key: process.env.MIX_PUSHER_APP_KEY,
//     cluster: process.env.MIX_PUSHER_APP_CLUSTER,
//     encrypted: true
// });


import Echo from 'laravel-echo'

window.io = require('socket.io-client');

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001'
});

window.Echo.private('App.User.'+window.App.user)
.notification((notification) => {
    if(notification.type === "App\Notifications\MessageCreatedNotification"){
        console.log("Trigger in the Listener");
        window.Vue.prototype.$eventHub.$emit('FOO', notification);
    }
});

This is my MessageBar.vue:

<!--
<template>
    <a :href="route" data-uk-icon="icon: mail" title=""
       data-uk-tooltip="Nachrichten"
       aria-expanded="false" class="uk-icon-link uk-icon"> <span v-if="count > 0"
                                                                 class="uk-badge wmp-badge-icon">{{count}}</span></a>

</template>
<script>

export default {
    name: "messagebar",

    props: {
        route: {
            type: String,
            default: ''
        },
    },
    data () {
        return {
            count: null
        }
    },
    computed: {},
    mounted () {
        let vm = this;
        this.$eventHub.$on ('CONVERSATION_MESSAGE_CREATED', function (val) {
            vm.count = val.unread_count;
        });
    },
    created: function created () {
        axios
        .get ('/api/conversation/count/')
        .then ((response) => {
            this.count = response.data;
        });
    },
    watch: {
    },
    methods: {}
};
</script>-->
<template>
    <a :href="route" data-uk-icon="icon: mail" title=""
       data-uk-tooltip="Nachrichten"
       aria-expanded="false" class="uk-icon-link uk-icon"> <span v-if="count > 0"
                                                                 class="uk-badge wmp-badge-icon">{{count}}</span></a>

</template>
<script>

export default {
    name: "messagebar",

    props: {
        route: {
            type: String,
            default: ''
        },
    },
    data () {
        return {
            count: null
        }
    },
    computed: {
    },
    mounted () {
        let vm = this;
        this.$eventHub.$on ('FOO', function (val) {
            console.log("Output: "+val.id);
        });
    },
    created: function created () {
    },
    watch: {
    },
    methods: {
    }
};
</script>

Now I get this output:

> Test
> Output: 1
> Output: 1

I can not explain why this is called twice. FOO does only exist on this two places in my project.

14 Jan
5 months ago

ahoi started a new conversation Prevent Login Of A User, If $user->status == "blocked"

Hello everybody,

I got a default Laravel app using php artisan make:auth.

Now my users should be "excluded" from logging in when their status is "blocked".

$user->status

returns a simply string (as you can read here: https://github.com/spatie/laravel-model-status#retrieving-statuses).

So is there an elegant way to prevent such users from logging in?

ahoi started a new conversation Broadcasting To All Recipients Of A Message

Hello everybody,

I am a little stuck at the moment. So I really hope you can help me out :-)

I am building a little private message system for my Laravel app.

I would like to notify my users on the Event MessageCreated.

This is my event:

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Cmgmyr\Messenger\Models\Message;

class MessageCreated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    
    public $message;
    
    /**
     * MessageCreated constructor.
     *
     * @param \App\Message $message
     */
    public function __construct(Message $message)
    {
        $this->message = $message;
    }
    
    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('conversation.'.$this->message->user_id);
    }
}

This is my notification:

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Lang;

class MessageCreated extends Notification
{
    use Queueable;
    
    protected $message;
    
    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct($message)
    {
        $this->message = $message;
    }
    
    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed $notifiable
     *
     * @return array
     */
    public function via($notifiable)
    {
        return ['mail'];
    }
    
    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed $notifiable
     *
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        
        return (new MailMessage)->subject('...'));
    }
    
    /**
     * Get the array representation of the notification.
     *
     * @param  mixed $notifiable
     *
     * @return array
     */
    public function toArray($notifiable)
    {
        return [//
        ];
    }
}

This is my event subscriber

<?php

namespace App\Listeners;

use App\Message;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Events\MessageCreated;
use Cmgmyr\Messenger\Models\Thread;
use Illuminate\Support\Facades\Auth;
use App\Notifications\MessageCreated as MessageCreatedNotification;
use App\User;

class MessageEventSubscriber
{
    
    /**
     * MessageEventSubscriber constructor.
     */
    public function __construct()
    {
        //
    }
    
    /**
     * @param \App\Events\MessageCreated $event
     */
    public function handle(MessageCreated $event)
    {
        $participants = Thread::findOrFail($event->message->thread_id)
            ->participantsUserIds();
    
        
        foreach ($participants as $participant) {
            if ($participant != $event->message->user_id) {
                $user = User::findOrFail($participant);
                $user->notify(new MessageCreatedNotification($event->message));
            }
        }
    }
}

I am also working with Laravel Echo:

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001'
});

window.Echo.private('conversation.'+App.user)
.listen('MessageCreated', (e) => {
    console.log(e);
});

Well - the Mails are being sent without problems. But now I'm a bit stuck on how to send a broadcast message to all the users in the recipients list. And of course I need to do this the most secure way.

I read the Laravel docs the whole day, but unfortunately I did not get a correct solution yet.

Your help is highly appreciated!

ahoi started a new conversation Using Private Channels On Laravel Echo

Hello everybody,

Actually I am still working on my private messaging app.

To load new notifications, I would like to use a PrivateChannel.

This is what I'm doing at the moment:

bootstrap.js

import Echo from 'laravel-echo'

window.io = require('socket.io-client');

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001'
});

window.Echo.private('conversation.${messageId}')
.listen('MessageCreated', (e) => {
    console.log(e);
});

MessageChannel.php

<?php

namespace App\Broadcasting;

use App\User;
use App\Message;
use Illuminate\Support\Facades\Log;

class MessageChannel
{
    /**
     * Create a new channel instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
    
    
    /**
     * @param \App\User    $user
     * @param \App\Message $message
     *
     * @return bool
     */public function join(User $user, Message $message)
    {
        return $user->id === $message->user_id;
    }
}

MessageCreated.php

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Cmgmyr\Messenger\Models\Message;

class MessageCreated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    
    public $message;
    
    /**
     * MessageCreated constructor.
     *
     * @param \App\Message $message
     */
    public function __construct(Message $message)
    {
        $this->message = $message;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('conversation.'.$this->message->id);
    }
}

channels.php

Broadcast::channel('conversation.{messageId}', function($user, $messageId){
    return Auth::check(); //has to be improved. Check, whether the user is in recipients list
});

web.php (test route)

Route::get('test', function(){
    $message = App\Message::find(1);
    broadcast(new \App\Events\MessageCreated($message));
});

Now I'm getting this in my Echo console:

[13:44:07] - Sending auth request to: https://test.app/broadcasting/auth

[13:44:10] - Do63uEo-ePk8Nh9jAAC0 authenticated for: private-conversation.${messageId}
[13:44:10] - Do63uEo-ePk8Nh9jAAC0 joined channel: private-conversation.${messageId}

I got this from https://laravel.com/docs/5.7/broadcasting -> Listening For Event Broadcasts

Echo.private(`order.${orderId}`)
    .listen('ShippingStatusUpdated', (e) => {
        console.log(e.update);
    });

But where does Echo.private get ${orderId} from in this example?

12 Jan
5 months ago

ahoi left a reply on Socialite: GitHub Login Shows 404

Got it: I had to clear and cache my config again, as

GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
GITHUB_REDIRECT=https://.../login/github/callback

were null.

ahoi started a new conversation Socialite: GitHub Login Shows 404

Hello everybody,

I am using laravel/socialite to log in with Facebook and Twitter. Now I'd like to add GitHub.

This is what I am doing:

 public function redirectToProvider($provider)
    {
        return Socialite::driver($provider)->redirect();
    }
    
    public function handleProviderCallback($provider)
    {
        try {
            if ($provider == 'facebook') {
                $user = Socialite::driver($provider)->fields([
                    'first_name',
                    'last_name',
                    'email',
                ])->user();
            } else {
                $user = Socialite::driver($provider)->user();
            }
        } catch (Exception $e) {
            return redirect('/');
        }
        
        $authUser = $this->findOrCreateUser($user, $provider);
        Auth::login($authUser, true);
        
        return redirect($this->redirectTo);
    }

Now if I try to log in, I am being redirected to GitHub's login page (https://github.com/login?return_to=%2Flogin%2Foauth%2Fauthorize%3Fresponse_type%3Dcode%26scope%3Duser%253Aemail%26state%3D8x3twY...PQEkrUz).

(https://imgur.com/dxKFGz0)

If I enter my Credentials, I am getting 404 (https://github.com/login/oauth/authorize?response_type=code&scope=user%3Aemail&state=8x3twYHo0mArfLd80o...PQEkrUz).

(https://imgur.com/ctbvpnE)

Is this a bug? Did I do something incorrect?

09 Jan
5 months ago

ahoi started a new conversation Revoke Notification (from Queue?) If Model-item Has Been Shown

Hello everybody,

I would like to notify my users if they got a new private message. The private message has a isUnread-property, which is set true on a new message and can be set false if the show action in the controller is called.

Well - now my idea: To prevent thousands of messages, I'd like to revoke the notification from the queue, if the user has seen the new message before the notification has been sent.

Unfortunately I don't get a way to do so. Maybe the community has an idea?

Your help is much appreciated :-)

ahoi started a new conversation Translation Of A Specific Part Of A Notification Does Not Work

Hello,

I got this notification (resources/views/vendor/notifications/email.blade.php):

@lang( "If you’re having trouble clicking the ":actionText" button, copy and paste the URL below\n". 'into your web browser: :actionURL', [ 'actionText' => $actionText, 'actionURL' => $actionUrl, ] )

Now I'd like to translate that one using de.json in resource/lang-directory:

{ 
"If you’re having trouble clicking the \":actionText\" button, copy and paste the URL below into your web browser: [:actionURL](:actionURL)": "Falls Du Probleme dabei hast, den \":actionText\" Button anzuklicken, rufe folgende URL auf: [:actionURL](:actionURL)"
}

All other translations I created this way are working fine

08 Jan
5 months ago

ahoi started a new conversation Send Mail On Model Created

Hello everybody,

I am new to Laravel events and notifications. I'd like to send a simple mail, once a model is created.

 Message::create([
            'user_id'   => auth()->user()->id,
            'body'      => $request->data['message'],
        ]);

Is it possible to fetch this create event and trigger a notification which sends a mail via toMail?

I followed this one: https://sujipthapa.co/blog/automatically-posting-to-facebook-page-via-laravel-notifications

This is my model:

<?php

namespace App;

use Cmgmyr\Messenger\Models\Message as BaseMessage;
use Illuminate\Notifications\Notifiable;

class Message extends BaseMessage
{
    use Notifiable;
}

This is my listener:

<?php

namespace App\Listeners;

use App\Notifications\MessageSaved;

/**
 * Class MessageEventSubscriber
 * @package App\Listeners
 */
class MessageEventSubscriber
{
    
    /**
     * Handle message creating events.
     *
     * @param $message
     */
    public function onSaved($message)
    {
        $message->notify(new MessageSaved());
    }
    
    /**
     * @param $events
     */
    public function subscribe($events)
    {
        $events->listen(
            'eloquent.saved: App\Message',
            'App\Listeners\[email protected]'
        );
    }
}

This is my notification:

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;

class MessageSaved extends Notification
{
    use Queueable;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['mail'];
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->line('The introduction to the notification.')
                    ->action('Notification Action', url('/'))
                    ->line('Thank you for using our application!');
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
}

and this is my EventServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen
        = [
            'App\Events\Event'               => [
                'App\Listeners\EventListener',
            ],
            Registered::class                => [
                SendEmailVerificationNotification::class,
            ],
        ];
    
    protected $subscribe = [
        'App\Listeners\MessageEventSubscriber',
    ];
    
    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();
        
        //
    }
}

Unfortunately the notification is not being triggered this way.

Your help is highly appreciated :-)

07 Jan
5 months ago

ahoi left a reply on Event Fire On Vendor Package's Model Change?

Thanks for your reply...

Well, I got it working. Maybe you could check my work?

MyController:

<?php
use App\User;
use App\Message;
[...]
//use Cmgmyr\Messenger\Models\Message;
use Cmgmyr\Messenger\Models\Thread;
use Carbon\Carbon;

[...]

public function store(Request $request)
    {
      [...]
        
        // Message
        Message::
            'user_id'   => auth()->user()->id,
            'body'      => $request->data['body']
        
        return response()->json($thread);
    }

The wrapper:

<?php

namespace App;

use Cmgmyr\Messenger\Models\Message as BaseMessage;

class Message extends BaseMessage
{
    protected $dispatchesEvents
        = [
            'saving' => \App\Events\MessageSaving::class,
        ];
}

The event:

<?php

namespace App\Events;

use App\User;
use Cmgmyr\Messenger\Models\Message;
use Illuminate\Queue\SerializesModels;

class MessageSaving
{
    use SerializesModels;
    
    public $message;
    
    /**
     * MessageSaving constructor.
     *
     * @param \App\Message $message
     */
    public function __construct(Message $message)
    {
        $this->message = $message;
    }
}

The Listener:

<?php

namespace App\Listeners;

use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Events\MessageSaving as MessageSavingEvent;

class MessageSaving
{
    /**
     * Handle the event.
     *
     * @param  object  $event
     * @return void
     */
    public function handle(MessageSavingEvent $event)
    {
        app('log')->info($event->message);
    }
}

The Event Service Provider:

protected $listen
        = [
            'App\Events\Event'               => [
                'App\Listeners\EventListener',
            ],
            \App\Events\MessageSaving::class => [
                \App\Listeners\MessageSaving::class,
            ]
        ];

If you see something to improve, please tell me :-)

ahoi started a new conversation Event Fire On Vendor Package's Model Change?

Hello everybody,

I am using https://github.com/cmgmyr/laravel-messenger to create a little messaging-system for my users.

Now I'd like to update them, if there is a new message.

Well: If I created this model, I could add a model event, something like that:

protected $dispatchesEvents = [
    'saving' => \App\Events\MessageSaving::class,
];

But as this is a vendor package, I am not sure, how to do that or whether this is possible at all.

This is the class I'd like to listen for: https://github.com/cmgmyr/laravel-messenger/blob/master/src/Models/Message.php

So my question: Is this possible out of the box or do I have to fire an event by myself, for example in my controller's method, which adds a new message...?