oliverbusk

oliverbusk

Member Since 1 Year Ago

Experience Points
10,390
Total
Experience

4,610 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
68
Lessons
Completed
Best Reply Awards
0
Best Reply
Awards
  • start-engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-session Created with Sketch.

    School In Session

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

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

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

  • subscriber-token Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer-token Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • lara-evanghelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

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

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

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

Level 3
10,390 XP
Oct
17
3 weeks ago
Activity icon

Replied to Passing Model Through A Prop, Or Getting It By An API?

This is what I settled for:

I pass the documents id through to the modal:

@click="$modal.show('showDocument', {document: '{{($document->id)}}'})"

In my controllers show method, I have this:

public function show(Document $document)
{
  
    return response()->json([
            'document'    => $document,
    ], 200);
}

In my Vue view, the axios get request is simply hitting the show method:

getDocument: function (document) {
      axios.get('documents'/ + document).then((response) => {
                this.document = response.data.document;
      }).catch(error => {
                console.log(error);
      })
},

To ensure that this specific show method can only be accessed from an AJAX request, I have created a custom middleware:

RequestIsAjax.php:

    public function handle($request, Closure $next)
    {
        if (! $request->ajax())
            return abort(403);

        return $next($request);
    }

And applied it to my controller, like so:

$this->middleware('ajax', ['only' => ['show']]);

Above seems to be working. However, I am still unsure if this is the most optimal way to go about this? Any input would be appreciated!

Oct
16
3 weeks ago
Activity icon

Replied to Getting Resources Through Route Model Binding

I mean probably? I was just thinking, that since a document belongs to a stream, the URL should reflect this?

Activity icon

Replied to Getting Resources Through Route Model Binding

OK, that makes sense. I thought that this was handling in the route model binding.

Would I need to define, for example a Policy, for both my Stream and Document model?

Activity icon

Started a new Conversation Getting Resources Through Route Model Binding

I have below two models:

Stream and Document

A Stream can have many documents, and a document belongs to a Stream.

I have these two resources defined in my routes file:

Route::resource('streams', 'Stream\StreamsController');
Route::resource('streams/{stream}/documents', 'Stream\StreamDocumentsController');

Let's say I have below data in my database:

streams

id |  name 
1  | Awesome Stream
2  | Also awesome Stream

And two documents - one in each stream.

documents

id | stream_id | name 
1  | 1         | Document1.pdf
2  | 2         | Document2.pdf

Now, if I visit the first stream and the document attached to it:

/streams/1/1

All is good. I can see the document information. However, if I visit the second stream - but with the id of the first document, like:

/streams/2/1

I can still see the document. How can this be? Since the document.id.1 belongs to the first stream and not the second?

Activity icon

Started a new Conversation Passing Model Through A Prop, Or Getting It By An API?

I have a web application, where users can upload different documents. I have a model, simply called Document.

I then have an index view, so users can view all their uploaded documents:

index.blade.php

@foreach($documents as $document)
   <ul>
      <li><a href="#" @click="$modal.show('showDocument', {document: json_encode($document)})">{{$document->name}}</a></li>
   </ul>
@endforeach

Now, I want to do so when users click on a specific document, a modal will open up on the current page. This is done with the following Vue code:

@click="$modal.show('showDocument', {document: json_encode($document)})"

This works fine. The modal opens up and the document object is attached to it.

My question is - is this the best approach? Consider I have 50 uploaded documents and on top of that, I would need to access relationship data on the Document model.

Another approach I have been thinking about was simply just to pass the id of the document to the modal, and then simply GET the document information by an API when the modal is loading:

@click="$modal.show('showDocument', {documentId: '$document->id'})"

And then, on the Vue view:

getDocument: function () {
      axios.get(this.route).then((response) => {
                this.document = response.data.document;
      }).catch(error => {
                console.log(error);
                this.document = {};
      })
},

Not sure if it really makes any difference (performance or design-pattern wise?)

Any input is appreaciated!

Oct
14
4 weeks ago
Activity icon

Started a new Conversation Carbon - Get Past And Next 4 Weeks

I am trying to show the previous 4 weeks and next 4 weeks (in numbers), like below:

Current week: 42

Week: 38
Week: 39
Week: 40
Week: 41
Week: 42
Week: 43
Week: 44
Week: 45
Week: 46

This is the code I have so far:

$this->week = '42'

$date = Carbon::now();
$date->setISODate(date('Y', time()), $this->week);

$start = $date->copy()->subWeeks(4)->week();
$end = $date->copy()->addWeeks(4)->week();

$weeks = CarbonPeriod::create($start, '1 week', $end);

And then in my blade view, I have this:

@foreach($weeks as $week)
              <a href="?week={{$week}}">
                        <div>{{\Carbon\Carbon::create($week)->week()}}</div>
              </a>
@endforeach

However, above prints out the following 38 weeks.

Any idea on how I can print out the past 4 and next 4 weeks?

Oct
02
1 month ago
Activity icon

Started a new Conversation Design Pattern Question

Hi all!

I have a question, I hope you can assist me with, regarding a design pattern in my web application.

I have a web application where users can upload documents to what I call a stream. A stream can then have fields, which will ultimately be used to parse something in the uploaded document.

So currently, this looks like:

A stream can have many documents. A stream can have many fields. A document can have many field parsing results.

This all works fine with standard relationships.

Now, I am trying to build a new feature, where inside a stream, documents can be routed to multiple different "layout routes".

So consider a stream called "My Invoices". Inside of this, a user has created two layout routes:

  1. Invoices from Acme Inc.
  2. Invoices from Machinery Inc.

Now, here comes the tricky part I think: If the stream has routes enabled (like in above example), the fields attached it will still be needed. However, now users can also define fields for each layout route.

So: A stream can have many fields A route can have many fields

My current setup: Currently, I have a stream table, a fields table and a route table.

My question is regarding the fields. Should I simply just add a column on my current field table called route_id, that if null indicate that the field does not belong to any route (and therefore only to the Stream). And if it have an ID, it indicates that it belongs to a specific route.

OR should I create a new table called route_fields, that works the same way as the fields table, but instead of referring to the streams, it refers to the routes table?

I am trying to wrap my head around this, but I simply cannot figure out the best way...

Oct
01
1 month ago
Activity icon

Started a new Conversation Fire Off Event When Job-chain Has Finished

I have below Listener called ProcessDocumentFields. My listener class implements the ShouldQueue.

In this, I fire off two jobs by using the withChain method as below:

ParseFieldContent::withChain([
        new ParseFieldRules($event->document, $fields),
])->dispatch($event->document, $fields);

Now, I want to conditionally fire off an event, which ultimately trigger another job.

The thing is, both jobs (ParseFieldContent and ParseFieldRules) must have finished running.

#If below is true, fire off
if ($event->document->stream->settings()->get('field_routing')) {
   event(new DocumentDefaultRulesWasProcessed($event->documents));
}

The above event, will trigger the same two jobs, but I have to do some other checks first:

#EventServiceProvider.php
DocumentDefaultRulesWasProcessed::class => [
     ProcessDocumentRouteFields::class,
],

Inside my ProcessDocumentRouteFields, I have:

foreach ($event->routes as $route) {
        if ($this->assertIfRouteFieldsShouldBeHandled($route, $event->document)) {
            ParseFieldContent::withChain([
                new ParseFieldRules($event->document, $route->fields, false),
            ])->dispatch($event->document, $route->fields);
        }
}

As you can see in above, I run the two same jobs (ParseFieldContent and ParseFieldRules) - but only if a certain assertion is true.

My question is: how can I ensure, that the jobs placed in ProcessDocumentFields runs first, then fier off the event, that triggers the jobs in ProcessDocumentRouteFields?

Sep
30
1 month ago
Activity icon

Started a new Conversation Multiple Forms, Different Models

I am trying to figure out how to update a set of rules, that belongs to what I call a "route". Consider below two routes:

Route::resource('streams/{stream}/routes', 'Stream\StreamRoutesController');
Route::resource('streams/{stream}/routes/{route}/rules', 'Stream\StreamRoutesController')->only(['update']);

The first one is for my routes. Here I can create, read, update or delete any routes from my web application.

The thing is, a route can contain a set of rules (hasMany):

# Route.php
 public function rules()
{
    return $this->hasMany(RouteRule::class);
}

Now, I am trying to figure out how I can mass update all the available rules on a route, by going to my route settings:

streams/{stream}/routes/{route}/edit      | App\Http\Controllers\Stream\[email protected]

On above page, users can:

  1. Modify the given route
  2. Modify the given route rules (all of them, at one time)

My problem is, on this edit page, I will then have two edit forms. The first for the route and the second for the route rules:

#edit.blade.php

<!-- for the route -->
<form method="POST">
@csrf
@method('PATCH')

<input type="text" value="$route['name']}" name="name">
<input type="text" value="$route['url']}" name="url">

<button type="submit">Save Route</button>
</form>

<!-- for the rules -->
<form method="POST">
@csrf
@method('PATCH')

@foreach($rules as $rule)
<input type="text" value="{$rule['value']}" name="value[]">
@endforeach
<button type="submit">Save Rules</button>
</form>

My question is: how can I structure this? Should all of the logic go in the [email protected] method?

Aug
22
2 months ago
Activity icon

Replied to Dynamically Load Views That Corresponds To Database Classes

Thanks - how would you utilize the View::make() method in this example?

Activity icon

Started a new Conversation Dynamically Load Views That Corresponds To Database Classes

I have created a rule-based engine, that can transform text in a couple of different ways, that my users decide. Consider below string of text:

Raw string Now as explained, I wish to allow my users to perform/apply a range of different methods to the above text. They should be able to apply all rules, in any given order. Consider below example where I have performed 4 rules to the original text document:

Rules

Below is the database content of above rules:

1 | 5 | remove_empty_lines | null
2 | 5 | text_replace | a:2:{s:6:"search";s:9:"Laracasts";s:7:"replace";s:6:"Google";}
3 | 5 | regex_text_replace | a:2:{s:7:"pattern";s:9:"/Google/i";s:11:"replacement";s:6:"Amazon";}
4 | 5 | start_position_no_lines | a:1:{s:4:"Line";s:1:"2";}

Now the images above is hardcoded, as I am having troubles on how to display the rules dynamically.

For example, for rule #2 ("Replace Text"), I have two arguments:

a:2:{s:6:"search";s:9:"Laracasts";s:7:"replace";s:6:"Google";}

Which can look like this in my blade view:

@foreach ($rules as $rule)
<div class="w-1/3 flex items-center">{{ucwords(str_replace('_', ' ', $rule->method))}}</div>
<input type="text" value="{{$rule->arguments['search']}}" placeholder="Search for...">
<input type="text" value="{{$rule->arguments['replace']}}" placeholder="Replace with...">
@endforeach

Now, the problem arises when a new rule is to be shown. For example rule #4 ("Choose Start Position"). For this rule, it takes two arguments as well.

a:1:{s:4:"Line";s:1:"2";}

But this does not match the code I have in my .blade.php file. This rule does not have a search or replace argument.

What to do?

I am not quite sure on how to proceed here. I was thinking that I might be able to extend blade views dynamically. Something like:

foreach($rules as $rule)
@include('layouts.rules.' . $rule->method)

<!-- for example: views/layouts/rules/text_replace-blade.php -->
<!-- for example: views/layouts/rules/regex_text_replace-blade.php -->
<!-- for example: views/layouts/rules/start_position_no_lines-blade.php -->

@endforeach

Not sure if this approach makes sense though?

Have anyone tried something like this - or maybe just have some comments?

Aug
08
3 months ago
Activity icon

Replied to Integrate Different Sources Of Notifications

No worries, I am trying to understand it myelf as well!

So I think something like this looks good.

$stream->integrations-each->notify($payload);

However, my problem is how should I define the integrations() method on the Stream model?

Stream.php:

public function integrations()
{
    return $this->???
}

I am not sure what the relationship should look like here - or if it should even be a relationship? Since an integration can be:

  • Email
  • Webhook
  • Zapier
  • Etc
Activity icon

Replied to Integrate Different Sources Of Notifications

Thanks for posting the link to the other post!

Ive though about the polymorphic relationship approach a bit, but cant quite conclude how it should look like?

For example, I imagine that it should be a one-to-many polymorphic relationship, but I am not sure.

For example, whenever a I want to dispatch notifications for a stream, it could potentially have many different endpoints (email, webhook, Zapier) - so how would this be stored in the database? What table should store this information? stream_integrations?

Activity icon

Started a new Conversation Integrate Different Sources Of Notifications

Notification Integrations

I am struggling a bit with how to design a flexible/dynamic notification system in my Laravel 5.8 web application. Consider that I have something called streams. Each streams can have many fields - and these fields ultimately contains a string.

Now, I want to be able from within my web application to dispatch all the fields on a stream to various 3rd party sources that my users can set up integrations to, such as:

  • Simple webhooks
  • Zapier
  • Microsoft Flow
  • Emails

I am unsure on how to design the database to allow for this, as well as the code.

My initial thoughts was just to create a table for each type of integration, and then check if a Stream have any integrations defined.

webhook_integrations

id | stream_id | url                | fields
1  | 3         | www.external.com   | 1, 3, 5, 10
2  | 5         | www.other.com      | 2, 4, 5, 10

I then imagine I can use it like this:

$stream = Stream::Find(3);

//If the stream have any webhooks defined, fire them off.
if($stream->webhooks)
{
    foreach($stream->webhooks as $webhook)
    {
        //Fire off each webhook here!
        $FireWebhook = new Webhook();
        return $FireWebhook->url($webhook->url)->payload($webhook->fields);
    }
}

Please note the above code is simply dummy code, and is just how I imagined firing off webhooks for a specific resource can be carried out.

Now imagine if I wants to introduce another integration into my web application. For example Zapier that uses a Oauth 2.0 authenticaion layer.

A database design for that could for example be:

zapier_integrations

id | stream_id | client_id | client_secret | auth_url | token_url | refresh_url | fields

But now, I have to check if my code if I need to send a notification to my Zapier integration:

$stream = Stream::Find(3);

//If the stream have any webhooks defined, fire them off.
if($stream->webhooks)
{
    foreach($stream->webhooks as $webhook)
    {
        //Fire off each webhook here!
        $FireWebhook = new Webhook();
        return $FireWebhook->url($webhook->url)->payload($webhook->fields);
    }
}

if($stream->zapierWebhooks)
{
    foreach($stream->zapierWebhooks as $zapierWebhook)
    {
        //Fire off each webhook here!
        $zapierWebhook = new zapierWebhook();
        return $zapierWebhook->payload($webhook->fields);
    }
}

(And so on.. if I example decide to add another notification integration - for example: sms, email, slack).

I am very unsure on how to go about designing such a setup. How can I allow for different type of notification endpoints (webhook, Zapier, SMS, Email and so on), and check against all these notification types for a specific resource - and if any exist, dispatch it?

Jul
27
3 months ago
Activity icon

Started a new Conversation Laravel Vapor - Queue Worker Serverless

Hi all

I just watched Taylots presentation of Laravel Vapor and so far it seems like a great tool. I already have a website running Laravel (using Forge), where I currently use a load balancer setup through DigitalOcean.

I specifically have one server that is only handling the queue jobs from my main application (Redis).

I was wondering - would it make sense (and can it be done), to change the setup so the queue server is living on Laravel Vapor (serverless), so it could just auto-scale, and still connect to my main application in Forge?

Jul
15
3 months ago
Activity icon

Replied to Managing Mass User Settings

That gives me:

Trying to get property 'notes' of non-object

And doesnt' really make use of the function that Jeffrey creates in the video I guess?

I have further defined a cast on my model:

    protected $casts = [
        'settings' => 'json'
    ];

Activity icon

Started a new Conversation Managing Mass User Settings

So I just finished the two part videos https://laracasts.com/lessons/managing-mass-user-settings-part-2.

I have implemented what Jeffrey is talking about - but I am not using the mass settings on an user, but on what I call a Stream.

So a user can create multiple streams, that all can have specific settings.

My question is when registering the settings() function in the ServiceProvider:

$this->app->singleton('App\Settings', function() {
            return User::first()->settings();
});

Jeffrey is simply returning the first user (or this can be changed to return the authenticated user).

However, my question is - how can I implement this, so I can use it on a specific stream?

In my Stream model, I have this:

    /**
     * The settings class, that is used to store mass settings for a Stream.
     */
    public function settings()
    {
        return new Settings($this->settings, $this);
    }

This means I can use it like this:

$stream->settings()->notes;

However, I am not sure if this is the right approach? For example, how can I use it within a blade file?

Doing this:

{{ $stream->settings()->notes }}

I get below error:

htmlspecialchars() expects parameter 1 to be string, array given

Activity icon

Replied to Caching A Specific Column In Relationship?

The stream token is created when a user created a stream and will never be changed for the specific stream. I guess a path column makes sense! :)

Activity icon

Replied to Caching A Specific Column In Relationship?

So simply store the entire actual path on the documents table instead? And just reference that directly?

$document->path

?

Activity icon

Replied to Caching A Specific Column In Relationship?

But as a session is unique to each user, and the stream token will never change - wouldn't it be slower to create a session every time?

Activity icon

Started a new Conversation Caching A Specific Column In Relationship?

I have a model called Document, in this I have a method that I use throughout my website to get the full path to the specific document:

public function getDocument($documentName = true)
{
    $documentName = $documentName ? $this->name : null;

    return storage_path('app/' . $this->getPath() . $documentName);
}

public function getPath()
{
    return "{$this->stream->token}/{$this->unique_id}/";
}

I use it like this (example):

$documentPath = $this->document->getDocument();

However, as you can see, the document path is made up of:

$this->stream->token/$this->unique_id/

Where $this->stream->token is calling a relationship in my Document model.

public function stream()
{
    return $this->belongsTo(Stream::class);
}

Now the method works - I can use the getDocument() to get the full path to the actual file (or just the folder, if I pass in false).

However, this code is fired out multiple places at different times - and because the folder structure is dependant on the stream_token, it makes a query to get the associated stream on each request.

Solution(s)?

I have tried adding a $with = ['stream'] property to my Document model, so the associated stream is always loaded when fetching the model - but this I don't believe is a good option either, since then all the other queries I have for the document model, that doesn't care about the stream property get's an extra query.

I was wondering - is it possible to cache the token column from the Stream model? Since this column will never change.

Jul
14
3 months ago
Activity icon

Started a new Conversation Relationship BelongsTo Two Columns

I have three models:

  1. File
  2. Field
  3. Result

A file can have many fields, and a field can belong to many files. This gives me:

Files.php

public function fields()
{
    return $this->hasMany(Field::class);
}

Fields.php

public function files()
{
    return $this->belongsToMany(Files::class);
}

Now, my users can upload files to my website and create fields. All files uploaded will "inherit" the fields.

A field could, for example, be called Invoice Number. My user can then add the invoice number from the uploaded file to the field.

However, as each uploaded file is unique, this means that the final field content will also be unique, thus requiring me to create a third model result.

I am not sure how to define this relationship because a result belongs to a field and a file.

Example

files

id | name
1  | invoice1.pdf
2  | invoice2.pdf

fields

id | name
1  | Invoice Number

results

id | file_id | field_id | content
1  | 1       | 1        | #1234
2  | 2       | 1        | #8888

I would then like to be able to get the result for the field, for a specific file, such as:

Filename = invoice1.pdf Fields = Invoice Number Results = #1234

Jul
10
4 months ago
Activity icon

Started a new Conversation Creating A Correct JSON Output That Follows JSON:API Convention

I am trying to parse some JSON that is stored in my database, transform it and then send it to a 3rd party API (by webhook). I am currently stuck at the JSON output format. I am trying to follow the standards of JSON:API.

This is my input from my database column fields.content:

[{"0": "Page 1, col 1.", "1": "", "2": ""}, {"0": "", "1": "Page 1, col 2.", "2": ""}, {"0": "", "1": "", "2": "Page 1, col 3"}]

As you can see, this is a JSON array that consists of objects. Each object represents a row, and each key represents a column. This can be visualed like:

________________________________________________
| COL 1         | COL 2          | COL 3                     |
________________________________________________
| Page 1, col 1.|                         |                          |
|------------------- |--------------------|---------------------|
|                         |Page 1, col 2.  |                         |
|--------------------|--------------------|---------------------|
|                         |                         | Page 1, col 3. |
-------------------------------------------------------------------

In my model Field.php, I use Laravel casting like:

protected $casts = [
     'content' => 'array'
];

Which automatically converts the json string to an array:

dd($content) //$content is the json string from the database

Returns:

array:3 [▼
  0 => array:3 [▼
    0 => "Page 1, col 1."
    1 => ""
    2 => ""
  ]
  1 => array:3 [▼
    0 => ""
    1 => "Page 1, col 2."
    2 => ""
  ]
  2 => array:3 [▼
    0 => ""
    1 => ""
    2 => "Page 1, col 3"
  ]
]

So consider that I do something with this array, like performing a replace on the word Page to Section:

$out = [];
foreach ($content as $col => $rows) {
    $out[$col] = str_replace('Page', 'Section', $rows);
}
dd($out);

This returns:

array:3 [▼
  0 => array:3 [▼
    0 => "Section 1, col 1."
    1 => ""
    2 => ""
  ]
  1 => array:3 [▼
    0 => ""
    1 => "Section 1, col 2."
    2 => ""
  ]
  2 => array:3 [▼
    0 => ""
    1 => ""
    2 => "Section 1, col 3"
  ]
]

I now want to update my database fields.content, to reflect this change. However when re-saving it to the database like:


$field = Field::find(1);
$field->content = $out;
$field->save();

It is now saved as an array of arrays:

[["Section 1, col 1.", "", ""], ["", "Section 1, col 2.", ""], ["", "", "Section 1, col 3"]]

This means that when I send this through my webhook, it no longer follows the same JSON schema like it started out with.

I have tried to json_encode the array, like:

$field->content = [json_encode($out, JSON_FORCE_OBJECT)]

But this doesn't produce the desired output/valid JSON.

Can anyone help me on how to transform my JSON object with Laravel/PHP, and re-save it to my database and keeping the initial valid JSON:API format?

Jul
08
4 months ago
Activity icon

Started a new Conversation Select Model With Relationship (limit Relationship Columns)

I have a controller called SelectDocumentsController.php with one method index:

I am trying to return the latest 10 documents, where stream_id equals $stream_id in the URL. I have below AXIOS get:

getDocuments() {
    axios
        .get("/api/editor/stream/" + this.$parent.current.stream_id + "/documents")
        .then(response => {
            this.output = response.data;
        })
        .catch(function (error) {
            console.log(error);
        });
}

In my API file I have below route:

Route::apiResource('editor/stream/{id}/documents', 'Editor\SelectDocumentsController')->only(['index']);

And this is my index method:

public function index($stream_id)
{

    return Stream::with(['documents' => function ($query) {
        $query->select('name');
    }])->findOrFail($stream_id);
    
}

I only want to return the column name from the documents - and I don't really need the columns from the Stream model.

Above index method retuns all columns from Stream, but the documents relationship is empty.

What am I doing wrong?

Jun
20
4 months ago
Activity icon

Replied to Vue - Parse JSON String

OK so I played around a bit more.. This is what I came up with:

{
   "1":[
      {
         "text":"Some text here on first column."
      },
      {
         "text":"2nd column text."
      },
      {
         "text":"Even more text. But on the third column"
      }
   ],
   "2":[
      {
         "text":"And more text. Second row."
      },
      {
         "text":""
      },
      {
         "text":""
      }
   ],
   "3":[
      {
         "text":"Text!"
      },
      {
         "text":""
      },
      {
         "text":""
      }
   ]
}

And the vude code:

<table class="text-left w-full border-collapse m-3">
  <thead>
    <tr class="bg-gray-100">

      <th v-for="(item, idx) in this.content" class="p-1">
        {{idx}}
      </th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="(row, rid) in this.content">
      <td v-for="(col, cid) in row">{{ col.text }} </td>
    </tr>
  </tbody>
</table>

Now above code seems to work - it generates the desired output (like in my jsFiddle). However, I have a few questions:

  1. Is this the correct way of saving a "table-like" layout in a JSON string?
  2. In above code, I have an equal number of rows in all my columns (3 rows in all columns). This may not always be the case. For example, column 1 can have 10 rows and column 2 can have 15 rows. In this case, how can I ensure that the visual layout "expands" to 15 rows? Should this be made on the backend (PHP: So I simply add empty "text":"" values to the string) - or should it be made on the frontend?
Activity icon

Replied to Vue - Parse JSON String

@EMILMOE - @hollyit can either one of you show how the JSON string would then look like? I am a bit puzzled, because in my head, having the columns and then the rows makes sense (that's how you would normally build a table)

Jun
19
4 months ago
Activity icon

Replied to Vue - Parse JSON String

@MAVERICKCHAN - But can't this be achieved, that if there is no row set, it should just be an empty <td></td>?

Activity icon

Replied to Vue - Parse JSON String

@DUNSTI - This gives me an error:

Unexpected token o in JSON at position 1

Laravel already provides the JSON string.

The problem is not getting the JSON string. I already have that in my view. The problem is parsing it in the table format (like I have tried to do in my JSFiddle manually).

Activity icon

Started a new Conversation Vue - Parse JSON String

Hi all

I am trying to parse a JSON string that my Laravel application serves to my Vue view. The JSON string can look like this:

{  
   "1":[  
      {  
         "row":"Some text here on first column."
      },
      {  
         "row":"And more text. Second row."
      },
      {
         "row":"Text!"
      }
    
   ],
   "2":[  
      {  
         "row":"2nd column text."
      },
      {  
         "row":""
      }
   ],
   "3":[  
      {  
         "row":"Even more text. But on the third column."
      }
   ]
}

Things to note here:

  1. The "1", "2", and "3" refers to columns. So in above examples, I have 3 columns.
  2. Each "row" refers to a row within the column.

I am trying to parse the string as a table, like: https://jsfiddle.net/59bz2hqs/1/.

This is what I have now:

<template>
    <div>
      <table>
          <tbody>
              <tr v-for="row in this.content">
                 <td>{{row}}</td>
               </tr>
           </tbody>
      </table>
   <div>
</template>

<script>
    export default {
        data() {
            return {
  
                content: []
            }
        },
        created() {
            Event.$on("document-was-processed", content => {
                this.content = content;          
            });
        }
    }

</script>

Now above simply prints out the actual JSON string. Can anyone help me out on how to actually parse the content?

Thanks!

Activity icon

Replied to Controller/Route Design For "frontend Updating"

Thanks both of you!! :)

I've tried the above approach and it actually makes sense and makes it look a lot cleaner.

Activity icon

Started a new Conversation Controller/Route Design For "frontend Updating"

Hi all

So I have a Vue component called "EditorView.vue". This is a frontend editor, where my users can edit images (crop, resize, add effects etc.)

My editor has two steps:

  1. The image is loaded and the user can do some preprocessing (optimize the image, change DPI etc.)
  2. The "preprocessed" image is loaded, and in this step, the user can do the resizing, cropping etc.

Now when going from step 1 to step 2, the image will need to hit the backend, in order for my server to do the actual preprocessing of the image. The processed image is then returned back to the Vue view and served in step 2.

I've just watched the Cruddy By Design by Adam Wathan, where he talks about implementing the CRUD setup for controllers and keep the number of actions within controllers to a minimal.

I am currently stuck on how to solve this, and how to call the backend.

Let's say I have below controller:

Api\Editor\ImagesController.php

and inside this controller, I have the basic CRUD actions.

I have below route defined:

Route::apiResource('editor/image', 'Editor\ImagesController');

I would then need to have methods such as optimizeImage(), changeDPI() in my step 1, and in step 2, I would need methods such as cropImage(), 'resizeImage()`

However, this has nothing to do with CRUD - it's custom actions to manipulate the image, that I have in my controller.

So what is the best approach to solving this? Should I treat the controllers for my editor differently than the rest?

Jun
18
4 months ago
Activity icon

Started a new Conversation Vue - Async Events Using Axios

Hi all

I am a bit confused on how to use the queue/async event feature within Laravel + Vue.

Let's say I have a Vue component as below:

AddReply.Vue:

<template>
   <div>
      <input value="" name="text" placeholder="Enter text..">
      <button @click='addReply'>Add Reply</button>
   </div>
</template>
<script>
export default {
        data() {
           text: "",
           output: [],
        },
        methods: {
           addReply(){
       
               axios.post("/api/reply", {
                          text: this.text
               }).then(response => this.output = response.data);
   
           }
        }
}
</script>

OK so above is very simplified, but it basically just sends a request to api/reply endpoint.

Now imagine that in my RepliesController.php I fire off an event: SendReplyNotification

This event is queued like below:

class SendReplyNotification implements ShouldQueue
{
    //Do something
}

Now all of this is happening asynchronous. Now, my question is: **how can I, on the frontend, wait for the event/queue to be finished, and then return data back to the Vue view? (AddReply.vue)

For example, I may want to redirect to a new page, after the reply was actually added.

Activity icon

Started a new Conversation Vue - Preloading JSON String From Database

I am trying to do, so my users can dynamically create table columns on top of an image.

I have below function, which works fine (I have minified the code a bit):

 data() {
     return {
           columns: [],
           xAxis: 0,
     }
},
addColumn: function () {

   this.columns.push({
           id: this.nextColumnId++,
           position: (this.xAxis * 100).toFixed(2),
           xAxis: this.xAxis
    });
},

I can successfully create new columns dynamically:

<a v-on:click="addColumn">Add Column</a>

This will just push a new "column" to the columns array. This will look like:

columns:Array[2]
   0:Object
      position:"30"
      xAxis:72
   1:Object
       position:"60"
       xAxis:578

Now my problem is when I am trying to load an image, that already has columns defined. This is stored in my database like so:

{"1": {"position": "30"}, "2": {"position": "60"}} 

(Above is two columns, at 30% on the page and 60% on the page)

I pass above, to below Vue prop (an object):

current:Object
   columns:"{"1": {"position": "30"}, "2": {"position": "60"}}"
   name:"test"
   created_at:"2019-05-13 17:23:32"

In my child file (DocumentViewer.vue), I try to add these columns:

columns:Object
   1:Object
      position:"30"

   2:Object
      position:"60"

As you can see, the structure in the pre-loaded columns is different from the one created dynamically, thus resulting in my code to break.

My question is, how can I preload the columns as an array, and add each column object, with the correct elements:

position: xx,
xAxis: xx,
Activity icon

Replied to Web Controllers And API Controllers

@NAKOV - Thanks a lot @nakov! That cleared things up for me :)!!

Activity icon

Replied to Web Controllers And API Controllers

@NAKOV - Thanks! Saw some of the "Cruddy By Design", and it makes sense!

Just one question to my API route, that currently looks like this:

Route::group([
   'prefix' => 'api',
   'middleware' => 'auth:api'
], function() {

   Route::get("documents/userDocuments", "[email protected]");    

});

Would it make sense to set the namespace as well - and change the endpoint:

Route::group([
   'prefix' => 'api',
   'namespace' => 'Api',
   'middleware' => 'auth:api'
], function() {

   Route::get("documents", "[email protected]");    

});

Like so?

Activity icon

Replied to Web Controllers And API Controllers

@nakov so in my case, it would be another controller called DocumentsController.php, but placed inside for example Api/ folder - so I will have two DocumentsControllers - one for the web and one for the API?

Activity icon

Started a new Conversation Web Controllers And API Controllers

Hi all!

So I've found myself stuck in my thoughts... Consider below resource controller:

DocumentsController.php

public function index(){}

public function show(){}

public function store(){}

public function destroy(){}

Which is used to serve the views for the frontend.

Now this works fine. I can perform the basic CRUD actions for the Documents.

However in my app, I have created a new Vue file called

DocumentViewer.vue, that will be used to show specific documents, that belongs to specific users/other parameters.

I would like to fetch the documents by using Laravel/Vue and a simple AJAX call to the backend. Something like:

data() {
     return {
         documents: []
     }
},
created() {
   axios.get("/documents/userDocuments")
             .then(response => this.documents = response.data);
}

As you can see, I have specified a URL called /documents/userDocuments, which may be referenced in the routes/api.php file like:

Route::group([
   'prefix' => 'api',
   'middleware' => 'auth:api'
], function() {

   Route::get("documents/userDocuments", [email protected]);    

});

This is my initial thoughts. However, for some reason it feels a bit.. "non-Laravel" like, and I am not sure if it goes against best practices.

My concerns are:

  1. I have my normal controller CRUD resource endpoints defined inside my routes/web.php file. Would it be OK to place the endpoint for the Vue endpoints within the routes/api.php file - or should this be placed within the web.php file?

  2. I'm a bit unsure about naming conventions in above. I'm referring to getUserDocuments, which will be a function within my DocumentsController - but this goes a bit against the clean controller structure. But on the other side, creating a new controller doesn't seem right either?

Jun
14
4 months ago
Activity icon

Replied to Dynamically Add/remove Vue Component

It works perfectly! Thanks!

Activity icon

Started a new Conversation Dynamically Add/remove Vue Component

Hi

I have a Vue component, that can be used to crop an image. I want to be able to allow my users to crop the same images in multiple areas.

Consider below component:

<div id="editor">
     <VueDragResize :w="8" :h="1280" v-on:resizing="resize"></VueDragResize>
</div>

I want to be able to add new <VueDragResize></VueDragResize> components dynamically:

<a @click="addComponent">Add Component</a>

<a @click="removeComponent">Remove Component</a>

So whenever I click Add Component link, a new <VueDragResize></VueDragResize> will be created and inserted into <div id="editor"></div>. Same when I click Remove Component, the specific component will be removed from the div.

I've been searching through SO and Vues forums, but I can't seem to find any examples of how to do this?

Can anyone guide me in the right direction on how to do this?

Jun
13
4 months ago
Activity icon

Started a new Conversation Conditionally Show Blade View

I have below app.blade.php template:

<!-- Sidebar Area -->
@if (\Request::is('*/fields*'))
    @include('streams.nav.editor-menu')
@else
    @include('streams.nav.menu')
@endif

<!-- Content area -->
@yield('content')

As you can see, up until now I have used below condition, to check whether a specific sidebar should be shown:

@if (\Request::is('*/fields/*'))

Above simply checks if the route contains the fields routes, as defined below:

Route::resource('streams/{stream}/fields', 'Stream\FieldsController');

Now, I've reached a point where I need to use this sidebar on another route resource:

Route::resource('streams/{stream}/documents', 'Stream\DocumentsController');

I could just add this to my if statement:

@if (\Request::is('*/fields*') or \Request::is('*/documents*')) 
...
@endif

However, I suppose down the road that I would need to add even more routes to this statement.

What would be the best approach to this? Would it be possible to maybe declare this in the controller or maybe even the model? Something like:

//Fields.php
/**
 * Specifies whether the editor menu should be shown or not.
 *
 * @return bool
 */

$sidebarEditor = true;

However, I am a bit unsure about how to implement this - or if there is a better approach?

Jun
12
5 months ago
Activity icon

Started a new Conversation Use Of Constants In A Model

Hi all

I have a basic model called Document. A document can be two things at the moment:

  1. A PDF file
  2. An image file

Currently, I have a column in my documents table called filetype. This column holds the filetype from the uploaded document, like so:

'filetype' => request()->file->getClientOriginalExtension()

However, I've noticed that for a PDF file, for example, the extension can be pdf or PDF.

This is causing me some annoying "bugs" in my code. Imagine:

if ($this->document->filetype === 'pdf') {
 // Do something
}

Now above will works for all PDF files that have the filetype with lowercase pdf.

A workaround could be to just use strtolower($this->document->filetype) === 'pdf') - or not use strict checking.

However this got me thinking - can this be solved by using CONSTS?

For example in my Documents model:

CONST PDF_FILE = 'pdf';
CONST IMAGE_FILE = 'jpeg,jpg,gif';

I know above is not valid code - but I was thinking if something like this was possible within Laravel?

May
14
5 months ago
Activity icon

Replied to PHP - Designing A Rule Based Parsing Engine

Hi @bobbybouwmann

I've come to the realization that the content now is not necessarily a string ($content = $document->content;).

I have changed my database setup, to store the value of content as JSON. Now, the content can be either just a string of text, or a multiple columns / rows.

Text:

{"text": "Just a regular string.\n Yep!\n\f"}

Columns/rows: (table data)

{"1": [{"1": "The first line of column 1!\n"}, {"2": "The second..\n"}], "2": [{"1": "Second column\f"}]}

So for the text content, I would just serve the content to the parsing rule like: $document->content['text']

However, I am a bit unsure of how I should serve the column data to the parsing rule method?

For table data, a parsing rule could be:

Text Replace $foo with $bar for all columns (loop through all rows)

Or

Text Replace $foo with $bar for column 1 (loop through all rows)

I am unsure how to do so the parsing rule method can accept both string data and table data? I imagine I would have to do a nested loop through the columns and then the rows? Any help or guidance would be highly appreciated!

Activity icon

Started a new Conversation Improving A Rule Engine

I am trying to create a simple parsing rule engine, that can parse text according to some parsing rules the user can define.

The problem I've encountered is that my users can currently save text into to my database in two ways:

documents:

id | path           | content
1  | /mydoc.txt     | {"text":"My document text.\nIs awesome!\n\f"}
2  | /another.txt   | {"column":[{"1":[{"1":"A line in column 1.\n"}],"2":[{"1":"Another line.\n"},{"2":"Yet another in column 2\n"}]}]}

So my users can parse a text string text: and column / table rows column:

I have created a class, that can parse rules:

ApplyParsingRules.php;

public function parseContent(array $content, Field $field)
{
    if ($field->rules->count() > 0) {
        $result['text'] = $this->parse($content, $field->rules);
        $result = json_encode($result);
    }

    return $this->data->fields()->attach($field, ['content' => $result ?? null]);
}

/**
 * Iterate through each rule and parse through the content.
 *
 * @return array
 */
public function parse(array $content, object $rules) : string
{
    $results = [];

    foreach ($rules as $rule) {
        $class = $this->getClass($rule);
        $content = $class->apply($content);
    }

    return $content;
}
public function getClass(FieldRule $FieldRule)
{
    $arguments = unserialize($FieldRule->arguments);
    $class = 'App\StreamParser\Parser\ParsingRules\Text\' . Str::camel($FieldRule->method);
    return new $class($arguments);
}

And it is called like:

$Parser = new ApplyParsingRules();
$result = $Parser->parseContent($content, $field);

An example rule could be textReplace.php:

public function __construct(array $arguments)
{
    $this->search = $arguments['search'];
    $this->replace = $arguments['replace'];
}

public function apply(array $content): string
{
    return str_replace($this->search, $this->replace, $content['text']);
}

Above setup works fine. I can provide the $content['text'] from the database, which is basically:

My document text.\nIs awesome!\n\f

However, I would like to allow for this to also parse the column data (for example, only perform text replacement in column 2, or capitalize everything in column 1, row 1.

Any tips / ideas on how I can improve my rule class to accept both the $content['text'] and $content['column'][$i] ?

May
10
6 months ago
Activity icon

Replied to Laravel - Method With Relationship Query - N+1?

@TRAVISOBREGON - This is exactly what I was looking for! Thanks a lot Travis!

Activity icon

Started a new Conversation Laravel - Method With Relationship Query - N+1?

Hi there

So I have a website where users can upload documents. When a document is uploaded, it will be saved to a specific folder in my storage, like:

stream_token/document_unique_id/mydocument.pdf

In my Document model, I have created a simple method, that can be used to get the path for the specific document:

    /**
     * A Document belongs to a Stream.
     *
     * @return Illuminate\Database\Eloquent\Model
     */
    public function stream()
    {
        return $this->belongsTo(Stream::class);
    }

    /**
     * Get the path to the unique folder for the document
     *
     * @return string
     */
    public function getPath(string $subfolder = '')
    {
        return "{$this->stream->token}/{$this->unique_id}/{$subfolder}";
    }

Since the method uses the $this->stream->token, every time I use it in my application, like:

 Storage::url($document->getPath('original')

It will fire a query to the relationship stream():

select  * from `streams` where `streams`.`id` = 1 limit 1

I use this method a lot of places in my application, but it seems a bit... Weird to use it, as I know it needs to fire of a query to get the stream->token everytime.

Is there any way I can "pre-load" the token or something like that to improve it?