marvanni

marvanni

Member Since 4 Years Ago

Experience Points 25,515
Experience Level 6

4,485 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 305
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.

17 Jan
1 year ago

marvanni left a reply on Valet, Custom Driver With Other PHP Version

Did you got this working in nginx?

It seems that valet is ignoring the nginx config files in ~.valet/Nginx/

I only got the default php version working

02 Sep
1 year ago

marvanni left a reply on Laravel Certification. 2017!

$ 249,- to get a certificate. Yearly that is...

Very nice business model to let people compete with each other in how good they are in memorizing stuff and actually make money out of it year after year.

I personally don't believe business asked for it. I have certificates for Zend and Symfony, but no client ever asked for it.. Let alone in which year.

I'm not against making money. We all have to. But I think a lot of people will feel they have to jump in each year, because others will do to. And if everybody does that.... Nobody will stand out because of that certificate, because everybody has it.

A good resume with nice projects you can relate to, is much more convincing then a certificate that is 'valid' for a year...

05 Dec
2 years ago

marvanni left a reply on Getting Mailable Object When Scheduled Email Is Sent

No, I ended up to set the data on the model when I set the Mail to queue.

\Mail::to($to)->queue(new JobAlertEmail($this, $jobs));
$this->sent_count = $this->sent_count + 1;
// and some other attributes
$this->save();
10 Oct
2 years ago

marvanni started a new conversation Getting Mailable Object When Scheduled Email Is Sent

I want to update some data when an email is sent.

I have

    public static function boot()
    {
        parent::boot();
        
        static::created(function (App\Models\JobAlert $model) {
            \Mail::to($model->email)->send(new \App\Mailable\JobAlert($model));
        });
    }

In this example I know the sent date. But the emails will be send on intervals, so I want to keep track on the sent date when an Email is send with ->queue() or later().

I know there is a \Illuminate\Mail\Events\MessageSending event but that gives me the Swift_Message object and no related Mailable object.

01 Oct
2 years ago

marvanni started a new conversation Themable Controllers

I want to have my 'frontend' Controllers to have a dynamic set of views. But not all, like Admin Controllers. And I don't want to prefix all Controller method view() calls, or the need to have to subclass a base ThemeController.

This is what I came up with, and I would like some feedback on it:

Wrap the frontend routes with a themable middleware

Route::group(['middleware' => 'themable'], 
    function ($router) {
        require base_path('routes/frontend.php');
    });
});

Enable themes for the Controllers that have this middleware

class ThemableMiddleware
{
    public function handle($request, Closure $next)
    {
        config(['theme.enabled' => true]);
        return $next($request);
    }
}

config/theme.php

<?php
return [
    'enabled'   => false,
    'name'      => env('THEME_NAME', ''),
    'directory' => 'themes'
];

Replace the view helper method in a custom helper.php file so we can prefix the $view that is passed from the controller.

function view($view = null, $data = [], $mergeData = [])
{
    $factory = app(ViewFactory::class);

    if (func_num_args() === 0) {
        return $factory;
    }

    if (config('theme.enabled')) {
        // resources/views/themedirectory/themename/$view
        $view = implode('.', array_filter([
            config('theme.directory'),
            config('theme.name'),
            $view
        ]));
    }

    return $factory->make($view, $data, $mergeData);
}

Now this does not take into account themed email views.

Any recommendations or improvements?

08 Sep
2 years ago

marvanni left a reply on How To Print Curly Braces From Database

Try removing Vue.js ...

The {{ content }} is printed in the source code. When I remove the shipped app.js the {{ content }} is visible.

https://github.com/laravel/framework/issues/15340#issuecomment-245580433

22 Aug
2 years ago

marvanni left a reply on Table Row Actions Template Include Advice

Moved the php part to a view composer :

<?php

namespace App\Http\ViewComposers;

use Illuminate\View\View;

class RouteViewComposer
{
    /**
     * @param View $view
     */
    public function compose(View $view)
    {
        list($routePrefix, $routeResource) = explode('.', request()->route()->getName());
        $view->with(compact('routePrefix', 'routeResource'));
    }
}

marvanni started a new conversation Table Row Actions Template Include Advice

To avoid having to copy the buttons on each index view table, I put the buttons in a seperate template. But this requires picking some information of the current route to have the route actions dynamic. I did this with a little php snippet, but if feels a little weird to do it like this.

I would really like to see some point of views regaring this snippet :

# admin/_includes/tablerowactions.blade.php
# gets included like <td>@include('admin._includes.tablerowactions', ['item' => $organisation])</td>

<?php list($prefix, $resource, $action) = explode('.', \Route::currentRouteName()); ?>

<div class='btn-group pull-right'>
    @can('edit', $item)
        <a href="{{ route('admin.'.$resource.'.edit', $item->getKey()) }}" class='btn btn-default btn-xs'>
            <i class="fa fa-fw fa-edit"></i> {{ trans('labels.edit') }}
        </a>
    @endcan
    @can('show', $item)
        <a href="{{ route('admin.'.$resource.'.show', $item->getKey()) }}" class='btn btn-default btn-xs'>
            <i class="fa fa-fw fa-eye"></i>
        </a>
    @endcan
    @can('destroy', $item)
        <a href="{{ route('admin.'.$resource.'.destroy', $item->getKey()) }}" class='btn btn-danger btn-xs ajax-delete'>
            <i class="fa fa-fw fa-trash"></i>
        </a>
    @endcan
</div>
16 Aug
2 years ago

marvanni left a reply on Laravel5.3 - Controller Auth Problems

For the time being this works for me :

class MyController extends Controller 
{
    public function callAction($method, $parameters)
        {
            dd(app('auth')->user()); // this works

            return parent::callAction($method, $parameters);
        }
}

11 Jul
2 years ago

marvanni left a reply on All Fillable For Admins

ok, that will become a mess if you ask me...

I guess I'll stick to this until a cleaner approach pops up.

Thanks again !

<?php

namespace App\Traits;

trait AddAdminFillables
{
    /**
     * Add adminFillable to fillable if the current user is an admin
     *
     * @return mixed
     */
    public function getFillable()
    {
        if (auth()->user() && auth()->user()->isAdmin()) {
            if(isset($this->adminFillable)) {
                $this->fillable = array_merge($this->fillable, (array)$this->adminFillable);
            }
        }

        return parent::getFillable();
    }
}

marvanni left a reply on All Fillable For Admins

"You should also not be using $_POST variables directly:" I know, it was as an example to tell I need the values from a request.

I will dive in it deeper. I use the pretus repository package and the dingo api package, so I need overload the prettus repository create and update methods, which will cause the model gets saved twice as it looks now..

Thanks anyway you all :)

marvanni left a reply on All Fillable For Admins

hm.. that might work :

$model = Model::fill($request->all()); // Fills fillable fields
$model->published = $request->input('published'); // Sets published to value in form
$model->expires = $request->input('expires'); // Same as above

marvanni left a reply on All Fillable For Admins

Is it really that weird that to have fields on a Model, that cannot be changed by every user that is allowed to submit a Form?

I can think of loads of usecases:

Employees can change product content, but not prices. Editors can change publish dates (with a dateform), but authors can't. Admins can block members (with a checkbox), but other members cannot.

All would use the same form, but the 'non-fillable' fields, could be disabled or not shown.

While you example might fit, it does not fetch any data from a Form Request in the save method.

Or am I fundamentaly misunderstand the 'Laravel' way of dealing with condional fields?

marvanni left a reply on All Fillable For Admins

Yes, but I need to set the data by a form, so with Snapey's example:

$user->is_admin = $_POST['is_admin']; // or publish_up, or publish_down

and the update is handled by Pretus Repository, I would realy like to have the fillable array and a way to bypass that fillable, so some FORM submissions will just change some data.

marvanni left a reply on All Fillable For Admins

Yes, thats true.

But having a real use case scenario where - to start with - a publish and expire date that are once set, can only be changed by an admin. And those dates should be changed with form fields that have a date picker.

10 Jul
2 years ago

marvanni left a reply on All Fillable For Admins

mark users as blocked or admin. change publish and expire dates with a form (not allowed by users, but editable for admins) select a user to be a company master user. add a note field to a customer.

could be anything....

marvanni started a new conversation All Fillable For Admins

I need protected attributes from Models to be fillable by admins.

How do you guys assess this solution:

<?php

namespace App\Traits;

trait FillableAllForAdmins
{
    /**
     * Mark all attributes as fillable for admins
     * @return mixed
     */
    public function getFillable()
    {
       if (auth()->user() && auth()->user()->isAdmin()) {
            return \Schema::getColumnListing($this->getTable());
        }

        return parent::getFillable();
    }
}

Do you see any caveats? Or is there something build-in I have missed?

04 Jul
2 years ago

marvanni started a new conversation How To Prevent This Type Of Duplication

So I'm having like 15 Models. (7 of them only have title field for things like Catagory, Education, Salary) Each model is unlocked by a (Dingo) API REST Controller. Each model is managed with a AdminLTE themed Controller that uses the Dingo Controller with an InternalRequest.

I already abstracted a lot of the redundant REST methods to Traits and views to reusable template includes to prevent code repetition (that a lot of scaffolders and generator packages generate), so I can create minimal classes like this (i leave the docblocks and namespaces out):

class ContractType extends Model
{
    protected $fillable = [
        'title'
    ];
}

// Api endpoint : REST methods are moved to a custom RequestlessRestMethodsTrait 
// and a DingoCrudRequestHandlerTrait that injects the ContractTypeRequest
class ContractTypesApiController extends AbstractApiController
{
    public $model = ContractType::class; // resolves to ContractTypeRequest and ContractTypeTransformer
}

// admin crud controller : this class calls the ContractTypesApiController with Dingo InternalRequest
// CRUD methods are moved to a custom RequestlessRestMethodsTrait and a DingoApiConsumerTrait
class ContractTypesController extends AbstractTitleOnlyModelController
{

}

class ContractTypeTransformer extends ApiTransformer
{
    public function transform(ContractType $item)
    {
        return [
            'id'    => $item->getKey(),
            'title' => $item->title,
            'links' => $this->getLinks($item),
        ];
    }
}

class ContractTypeRequest extends ApiRequest
{
    public function authorize()
    {
        return true; // for now ... untill permissions and roles are clear
    }

    public function rules()
    {
        // all API REST methods need to pass this Request
        switch ($this->method()) {
            case 'GET':
            case 'DELETE': {
                return [];
            }
            case 'POST': {
                return [
                    'title' => 'required'
                ];
            }
            case 'PUT':
            case 'PATCH': {
                return [
                    'title' => 'required'
                ];
            }
            default:
                break;
        }
    }
}

But still, trying to DRY and SOLID all the way, that still leaves me with:

15 SomeModelFormRequests 15 SomeModelTransFormers (Fractal) 15 SomeModelRepositories (Prettus) 8 A list (table) blade template (7 of them default to a fallback template) 8 A form blade template (7 of them default to a fallback template)

By using a seperate class for Model, ApiController, CrudAdminController, FormRequest, FractalTransformer, RepositoryClass, a set of resource routes (api, admin) a set of blade templates (list, edit), gives me 8 files to handle 1 Model. Without the abstraction layers, I would end up with 8 * 15 models = 120 seperate files.. When using the abstraction a simple title only model can be managed with around 7 files.

That feels like a lot of repetition and a lot of fragmentation(or 'separation of concerns' as we have been taught..) and in case of the templates some code duplication.

Yes, once the most of the classes are in place ,they probably won't change very often. But regardering the templates I forsee a lot of applying the same html change for seperate file that do more or less the same for a lot of models.

Is there a design flaw in my solution, or should I deal with the fact that SOLID will lead to some code repetition and fragmentation? I cannot see how working with Laravel generators or one of the thirdparty scaffolder packages leads to DRY code...

How do you guys handle this? Am I missing something obvious?

14 Jun
4 years ago

marvanni left a reply on Is This Approach Of A BaseRepository Any Good?

Yes, that is how the most Repository examples are done. But does that example not also use setModal();? Thanks fir the link btw, nice example code to dive in!

What I was after, that I did not want to 'replicate' the find, delete, all etc methods that are already present in Eloquent Model.

That's why I used the __call method to forward repo methods to the existing Model methods.

Do you see any disadvantages in that?

marvanni started a new conversation Is This Approach Of A BaseRepository Any Good?

So I'm getting my head around Repository classes after viewing this video, and also the comments on that vid: https://laracasts.com/lessons/repositories-simplified

Did some further reading and found these interesting:

http://slashnode.com/reusable-repository-design-in-laravel/ http://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/

Especially the 'slashnode' approach where you would 'interface' all Model methods for the Base Repository class, where other Model Repositories should extend from.

I had no idea which methods would be required to 'copy' from the Eloquent Model Class to the Repository class, so I came up with this idea:

<?php namespace App\Repositories;

use App\Contracts\RepositoryInterterface;

abstract class ModelRepository implements RepositoryInterterface {

    /**
     * @var $model \Illuminate\Database\Eloquent\Model subclass
     */
    protected $model;

    /**
     * @param $model \Illuminate\Database\Eloquent\Model subclass
     */
    function __construct($model) {
        $this->model = $model;
    }

    /**
     * @param $model \Illuminate\Database\Eloquent\Model object
     *
     * @return $this
     */
    public function setModel($model)
    {
        $this->model = $model;
        return $this;
    }

    /**
     * @param $method
     * @param $parameters
     *
     * Forward all method calls to \Illuminate\Database\Eloquent\Model
     *
     * @return mixed
     */
    public function __call($method, $parameters)
    {
       return call_user_func_array(array($this->model, $method), $parameters);
    }

}

This would forward all method calls on the Repo class to the Eloquent Model, but still subclasses of this Repository can have additional query methods.

My UserController could look like this;

class UserController extends Controller {

    private $users;

    public function __construct(UserRepositoryInterface $users)
    {
        $this->users = $users;
    }

    public function index()
    {
        $users = $this->users->all();

        return view('users.index', compact('users'));
    }

    public function update(User $user, UserRequest $request)
    {
        $this->users->setModel($user)->update($request->all());
        
        return redirect()->back();
    }

Where UserRepositoryInterface is bind to UserRepository that look likes :

<?php namespace App\Repositories;

use App\Contracts\UserRepositoryInterface;

use \App\User;

class UserRepository extends ModelRepository implements UserRepositoryInterface {

    function __construct(User $model) 
    {
        parent::__construct($model);
    }

    public function findByEmail($email)
    {
        //
    }
}

This seems to work when having a simple CRUD controller, but I did not tested it extensively. The one weird thing is maybe always pass an (non persisted) instance of User in the constructor and a persisted User before we can update with like

$this->users->setModel($user)->update($request->all());

and PHPStorm's autocompletion for Model is gone....

Im pretty new to this Repository pattern, so I would love to get some opinions about this approach of creating a Base Repository for all subclassed Model Repositories?

Are there any possible culprits / bad practices with this approach?

Thanks in advance!