markss

markss

Member Since 1 Month Ago

Experience Points
160
Total
Experience

4,840 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 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-in-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 Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist 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 1
160 XP
May
18
2 weeks ago
Activity icon

Started a new Conversation Pass Data From Tool Or ToolServiceProvider To Navigation.blade

Hey!

Laravel Nova Tools extend the abstract ServiceProvider which only offers a method to $this->loadViewFrom( $path, $namespace ), but there is no data field offered to provide any custom data to the navigation.blade.php.

I need some custom Root-Level Links that should only act as a default resource link - so not as submenu in resources where they are are stored by default.

I tried to add a Tool and then simply add the resource that is referenced in it's constructor, and also allowing adding children to it using a ->addChild() method. My initial idea was to misuse the config and update it on runtime, but quickly realized that this won't work, as the app boots for several routes and only the very last custom link will be stored in the config when dumping in the blade. Also, I won't be able to figure out which link to display in which position in the Navigation, as config would contain all CustomLinks.

Here is what I have now

The Tool

class CustomLink extends Tool
{
    protected $name;
    protected $uri;
    protected $resource;
    protected $icon;

    /**
     * CustomLink constructor.
     *
     * @param null $resource
     * @param null $name
     * @param null $uri
     * @param null $icon
     * @throws \Exception
     */
    public function __construct($resource = null, $name = null, $uri = null, $icon = null)
    {
        if (empty($resource) && empty($uri)) {
            throw new \Exception('Missing Resource or URI');
        }

        // Get current config
        $conf = config('bty.custom_links');

        // Add new element to config
        $conf[$this->getId()] = array(
            'name'     => empty($name) ? $resource::label() : $name,
            'uri'      => $uri,
            'icon'     => $icon,
            'children' => [],
        );

        // Store Config
        config(['bty.custom_links' => $conf]);

        parent::__construct();
    }

    /**
     * Add a SubNav Element
     *
     * @param null $resource
     * @param null $name
     * @param null $uri
     * @return $this
     */
    public function addChild($resource = null, $name = null, $uri = null)
    {
        if (empty($resource) && empty($uri)) {
            return $this;
        }

        // Find parent and append child
        $conf = config('bty.custom_links');
        $conf[$this->getId()]['children'][] =
            array(
                'name'     => empty($name) ? $resource::label() : $name,
                'uri'      => $uri,
                'resource' => $resource,
            );

        // Save
        config(['bty.custom_links' => $conf]);

        return $this;
    }

    /**
     * Generate an id as hash from own properties
     *
     * @return string
     */
    public function getId()
    {
        return md5($this->name . $this->uri . $this->icon . $this->resource);
    }

    /**
     * Build the view that renders the navigation links for the tool.
     *
     * @return \Illuminate\View\View
     */
    public function renderNavigation()
    {
        return view('custom-link::navigation');
    }
}

The ToolServiceProvider only loads the view with no options offered

class ToolServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->loadViewsFrom(__DIR__ . '/../resources/views', 'custom-link');
    }
}

Any suggestions on how I could get custom data into the blade or a better idea how to achieve custom top-level navigation links?

Thanks a lot!

Apr
07
1 month ago
Activity icon

Replied to Morph To Relationship

Depends if your images can be for several users and articles at the same time, or if an image is always only for one instance of either.

If its possible to have more than one: Polymorphic many to many https://laravel.com/docs/7.x/eloquent-relationships#many-to-many-polymorphic-relations You will have to have an imageables table with columns image_id,imageable_id,imageable_type

Otherwise, if one image is only for one (or none): Polymorphic one to many https://laravel.com/docs/7.x/eloquent-relationships#one-to-many-polymorphic-relations You can keep the imageable columns on the images table directly

Activity icon

Started a new Conversation Eloquent / Nova - Change Default OrderBy

Hey

I have this relation method, which applies a union to a relation, which is again required for a localization feature. My question is not about the union itself as it works fine, but about SQL errors caused by default sorting.

/**
 * Get all payment methods for this operator
 */
function paymentMethods() {

//... some logic filling the $fields with null values for the union
//... some logic finding $res existing relations

// Morph To Payment Method
return $this->morphToMany('App\PaymentMethod', 'payable')
            ->withPivot(Payables::PIVOT_FIELDS)
            ->using(Payables::class)
            ->where(function ($q) {
                if (isset($this->paymentMethods_checkboxes)) {
	            // remove payment methods that are defined absent for this localization
                    $q->whereIn('payment_methods.id', $this->paymentMethods_en)
            })
	    // append payment methods that are defined present for this localization
            ->union(function ($q) use ($fields, $res) {
                $q->select($fields)
                    ->from('payment_methods')
                    // append additional ids
                    ->whereIn('payment_methods.id', $this->paymentMethods_en ?? array())
		    // but avoid appending existing relations as duplicates
                    ->whereNotIn('payment_methods.id', $res);
            });
}

Due to the union I get the following error when viewing the models detail view: Syntax error or access violation: 1250 Table 'payment_methods' from one of the SELECTs cannot be used in ORDER clause [... long sql statement...] ) order by `payment_methods`.`id` desc

According to SQL docs on https://dev.mysql.com/doc/refman/8.0/en/union.html

This kind of ORDER BY cannot use column references that include a table name (that is, names in tbl_name.col_name format). Instead, provide a column alias in the first SELECT statement and refer to the alias in the ORDER BY. (Alternatively, refer to the column in the ORDER BY using its column position. However, use of column positions is deprecated.)

So it is not allowed to set the payment_methods. prefix on a union.

When changing the orderBy in the relation method like ->select(payment_methods.id as sort_id)->orderBy(sort_id) the order by clause only gets appended as additional clause.

When changing it like this: ->select(payment_methods.id as sort_id)->orderBy(payment_methods.sort) the default orderBy gets overwritten, but due to the table-prefix the statement is invalid again.

Any suggestions how to remove the default order clause?!

Appreciate your help!

Apr
06
1 month ago
Activity icon

Started a new Conversation Eloquent Relationship - Append Data With Union

I have defined a Relation between several Shop-Types and PaymentMethods representing which shop offers which payment method. This is defined through a morphToMany in $shop->paymentMethods().

Now I also have a Localization-Feature implemented, which works the following way: The current locale you're working in is stored in the session. Then, there is a localizations table, which stores the localized elements (in this case: the modified shop model), as the different countries will again provide different payment methods for the same shop. This localization then also stores an array of attached IDs when the relation is modified while in localization view, so that payment methods can be added and removed while in the sub-view. In this example, they're stored in $shop->paymentMethods_en

Now its easy to exclude relations that exist in the root view by calling the sub-query ->whereIn('payment_methods.id', $this->paymentMethods_en).

What's causing problems is showing additional payment methods that don't exist in root and therefore also don't exist in the relations-table. I tried using a union and then left outer join the relations table, which excludes all elements that are already defined in the root dataset. Otherwise the ID 1 for example would get loaded twice. And then, all remaining payment method ids are appended to the output.

So far, soo good. Actually, the table-view loads as expected (laravel nova), showing the additional payment methods as well, but when nova is trying to count the existing models for the table pagination, I get the error: Column already exists (1060): duplicate column name 'id'

Shop.php

function paymentMethods() {
  
  $fields = array_map(function ($el) {
    return DB::raw( 'null as pivot_' . $el );
  }, Payables::PIVOT_FIELDS);

  return $this->morphToMany('App\PaymentMethod', 'payable')
    ->withPivot(Payables::PIVOT_FIELDS)
    ->using(Payables::class)
    ->where(function ($q) {
        if (isset($this->paymentMethods_en)) {
            $q->whereIn('payment_methods.id', $this->paymentMethods_en);
        }
    })
    ->unionAll(function ($q) use ($fields) {
        $q->select($fields)
            ->from('payment_methods')->join('payables', 'payment_methods.id', '=', 'payables.id', 'left outer')
            ->where('payables.payable_id', '=', $this->id)
            ->where('payables.payable_type', '=', self::class)
            ->whereIn('payment_methods.id', $this->paymentMethods_en);
    });
}

According to https://stackoverflow.com/questions/7664378/sql-union-of-two-queries-duplicate-column-name-error I would have to explicitly name the columns, which is not possible using the eloquent methods. Any ideas how to work around that problem - or a different approach on how to attach the missing relations?!

One additional thing. When sorting by ID - as it is the default behaviour - I also get the error Syntax Error or access violation: 1250 Table 'payment_methods' from one of the SELECTs cannot be used in ORDER clause. When sorting by name everything is fine though. How does this make sense?

Appreciate your help!