consil

Experience

9,710

0 Best Reply Awards

  • Member Since 2 Years Ago
  • 96 Lessons Completed
  • 2 Favorites

15th August, 2017

consil left a reply on Which Package Is Best For Roles & Permissions • 4 days ago

@daniel.schreij that looks interesting, and seems to be built on the latest 5.x built-in ACL, unlike most of the other solutions which bring most of the ACL functionality along with them. And the older packages are fine, but it always seems if Laravel is giving a pointer on a direction to go, and any package not going down that route will end up being harder to support as time goes on.

10th August, 2017

consil left a reply on Migrations: Configure A Default String Length? (utf8mb4) • 1 week ago

This SO post gets straight to the one-line solution in the AppServiceProvider boot method:

https://stackoverflow.com/questions/23786359/laravel-migration-unique-key-is-too-long-even-if-specified/23786522#23786522

16th June, 2017

consil left a reply on Setting Table Dynamically • 2 months ago

So, this works for pointing a model at a table.

Next step is using the configuration value in a migration. Is it as simple as accessing the same value from there?

15th June, 2017

consil left a reply on What Can A Package Bring To A Laravel Install? • 2 months ago

@Cronix I feel silly now. My head is still stuck firmly in the 5.1 documentation. All looks great - thanks.

consil started a new conversation What Can A Package Bring To A Laravel Install? • 2 months ago

I'm just curious as to what a package, installed through composer, can bring to an installation of Laravel. Obviously it can bring useful classes that can be used by custom code, but what else?

Config files can be provided by a package, that are installed into the config area. What about other assets? Can they be installed by a package too? If so, would they be like npm dependencies, or assets that go straight into the public area? Or would they need to be manually copied as a procedure to installing the package?

What about views and routes? Can a composer package bring those to a Laravel instance it is installed into? Or again, would manual copying of files be needed? I realise that an artisan command to install these files into the correct place may be needed, and if it is just the artisan command, that's great.

Or am I hoping Laravel does too much at this level, leaving a package as something that you need to glue in with custom code?

consil left a reply on So, Where To Start A New Project With A Baseline? • 2 months ago

Yes, https://github.com/jeremykenedy/laravel-auth seems to be well thought-out and has many things I needed right from the start.

One niggle is that each user can only be assigned one role, which is something I thought died out a decade ago - yes, one user can be a supplier and a customer - it's just the way the real world works. Still, it's better than a poke in the eye with a sharp stick, and is fine for our prototype.

consil left a reply on So, Where To Start A New Project With A Baseline? • 2 months ago

Okay, this is what I am trying now:

https://github.com/jeremykenedy/laravel-auth

Once the server was set up, and I understood how to install node and npm in my account, it all installs nicely and feels to be a great baseline.

consil left a reply on From Zero To Being Able To Being Able To Enter "npm" Commands • 2 months ago

Just found these instructions which got me up and running:

https://hostiso.com/how-to-install-setup-node-js/

This will install node and npm in your local account, so nothing needs to be installed globally on the server. node is a compiled binary, while npm is a JavaScipt script that runs with node as its interpreter.

The latest code is downloaded as an archive from here: https://nodejs.org/en/download/ then expanded to a directory in the account.

The binary node is copied from the extracted archive to the bin directory in the account. Now, I found that the bin directory (even though it did not exist until I created it) was already in my PATH. I guess that is a WHM or cPanel feature.

After copying the node binary, the npm script and a number of its required siblings and support scripts are symbolically linked into the bin directory. This means the extracted node archive must not be moved, so make sure it is in an appropriate page. I extracted it to nodejs/ in the home directory of the domain account.

And that was it. Both node and npm are then available as commands when I log in, and that is what Laravel needs to do its asset management, downloading, compiling, minimising, etc.

I have kept the description to just the concepts above, and left the detailed commands to the page I linked at the top. It's all pretty simple in the end, just four or five commands. Updating the commands will just involve repeating the same steps, which take just a couple of minutes.

consil started a new conversation From Zero To Being Able To Being Able To Enter "npm" Commands • 2 months ago

Got a WHM/cPanel server and am installing Laravel with all the trimmings in an account. Part of the install involves running npm commands. I am trying to understand what needs to be installed and where , in order to do this.

Searching for this, there are many mixed instructions on what to do. I have not been able to find any articles that explain just what is needed and how it interacts. For example:

  • What needs to be installed on the operating system globally, perhaps maintain by yum or whatever is used for OS package management?
  • What needs to be built from source, due to their now being any official packages for the OS?
  • What needs to be installed in the account where Laravel is being installed?

I'm not just looking for a series of commands to blindly run. I would like to understand what those commands are doing and where, so I know what needs to be maintained. I'm technically literate, so techy is fine :-)

consil left a reply on So, Where To Start A New Project With A Baseline? • 2 months ago

Aghh! Just typed up a long reply, did not realise this forum had expired tokens in the page, refused to post it, then discarded the post I have typed up. Firefox will remember what you typed on going back a page, unless the site tells it not to. This is an annoying bug that has caught me many times in the past, and really needs to go. Just don't throw my post away!

Anyway, found some stuff, did some stuff, looking good so far, and will come back later to fill in the details again.

13th June, 2017

consil left a reply on It Is Ok To Use LetsEncrypt Free SSL? • 2 months ago

No fret about it. Just use it from the start for all your pages. If a site needs more for any kind of verification reasons, then deal with that when it is needed. For now, just encrypt all connections, and what better way to do that than with a free SSL provider that, TBH, is respected greatly for what it has done for the industry.

consil left a reply on So, Where To Start A New Project With A Baseline? • 2 months ago

I am totally with you @jlrdw and understand what you are saying. I would say the same thing to anyone else starting out, including never underestimating the power of pencil and paper to flesh out an idea. I do that all the time.

I've been down this path a number of times, and have projects written in different versions of Laravel over the years, even going back as far as FuelPHP, which I feel set down some of the structural groundwork that Laravel followed.

Each project is still running today, doing its thing in its own legacy ways. Each followed the lessons of the day, was built on the packages of the moment that seemed popular and did things in a way that felt natural and right. They were all good, and are now all stuck in their own little walled legacy gardens with the occasional updates and bug fixes.

The trouble is, the user stuff - logging in, registering, managing the users at the back end, roles, privileges, ACLs, password recovery - all that stuff is kind of a little footnote in my current project. I just want it done and out the way; "[x] Users". Ticked. Done. Now I can move on to the real guts of the application and flesh it out. That's where the real business end is.

I guess I am looking to hit the ground running a little faster than I would be with a big box of loose LEGO bricks, to mix my metaphors. And I am sure many other people are right there too, and have found the perfect solutions that provide enough out of the box to provide the framework that does things the right way - the Laravel way - and is ready, excited and eager to accept custom modifications so it can shine brighter than it could ever have dreamed.

Sorry, got carried away there. I've looked at Spark. That seems to very much revolve around implementing one particular business model (reseller apps). So I was hoping someone here had hit just the right magical combination of packages, libraries, glue and customisations.

consil started a new conversation So, Where To Start A New Project With A Baseline? • 2 months ago

I bet thousands of people ask this question every day, search the web, find dozens of partial solutions, dozens of tutorials with half a solution, packages and projects that have been abandoned a year ago, or are not clear in what they do or do not do...so what is today's baseline that will give a new project its initial leg up?

I'm looking to start a new project, hopefully L5.4 or thereabouts. I would like user registration, backend user admin, roles, permissions, password reset, maybe social media auth. You know, all the usual stuff that has to be done, just kind of there and working.

I can install Wordpress, and all that is there in five minutes flat. That;s a great start, but then Wordpress is a MONSTER to try to develop in, leaving you banging your head against a brick wall more often than not. Laravel is an absolute pleasure to develop in. But I want to just get on with the application and now have to spend a week messing on with admin pages, password recovery, registration etc. before I can get close to the application functionality. I'm looking for a rapid but fully functioning prototype framework to build in.

So, am I asking too much? Or are there great solutions to this that I have not found? Or is all there already but I just can't see it?

Any recommendations?

22nd March, 2017

consil left a reply on Best Practice For Handling "active" Menu Item In L5 • 4 months ago

@mustard Yes, you can look at the URL path, but you must stay aware of what the implications of that are.

Paths are generally (and should always IMO) be defined in the routes.php map. Outside of that script, I don't believe views or controllers should be aware of what those paths are. Paths can easily change as an application develops and grows. The names of the paths however, can remain fixed since they define a business function.

But horses for courses - it's not wrong, just understand what its advantages and limitations are.

30th October, 2016

consil left a reply on Best Practice For Handling "active" Menu Item In L5 • 9 months ago

@awks If you specifically check for equality to zero, then you can make sure the route starts with the relevant string:

{{ strpos(Route::currentRouteName(), 'admin.dashboard') === 0 ? 'active' : '' }

That will match admin.dashboard.bar but not foo.admin.dashboard.bar. That may or may not be what you want, but it's something you can do.

I would also return and empty string instead of null, then there is no type-casting needed, since {{ ... }} will be expecting a string to be returned, or will need to cast whatever is returned to a string. Just start with a string and get it over with.

24th September, 2016

consil left a reply on Recommendations For Drag-and-drop Reordering • 10 months ago

Hi @mr415

When I first started this I had the assumption that Vue would have its own data model mapped to the structure and would be used to draw the initial tree. That proved very difficult to implement, and TBH did not offer any benefits. So instead I just drawn up the structure using standard nested loops in blade, giving elements appropriate IDs, classes and other attributes, then use some pretty standard jQuery to point sortable at the dragable elements in the tree. That proved pretty simple in the end.

If there were a draggable tree plugin to Vue, that sat on top of Vue, then it may be a completely different matter. So, tried that route, then threw it away and went for simple jQuery and sortable.

18th September, 2016

consil left a reply on Recommendations For Drag-and-drop Reordering • 11 months ago

The AJAX URL just identifies the node (in the path of the URL) and its new position (in GET parameters). Whether it is absolute or relative should make no difference - it is just what the route() function spits out.

Alternatively you could have one path that all the nodes share, with the node IDs being passed in also a GET parameters. Whatever is easiest for you really. The key things are:

  • It is a PUT action and not GET, so things don't get accidentally moved around by visiting URLs in the browser.
  • You are getting the data you need to implement the move in the database to a controller method. Whether that method has parameters mapped to the route path, or simply looks at POST parameters, makes no difference. You are just getting the new position data to the server so it can manipulate the database to reflect the drag-and-drop you did on the front end.

It's about keeping the front end and the database in sync. The sortable library lets you drag nodes around the tree structure, and that's great. Then each time a node moves, the server needs to be told what has just moved, and that is the AJAX call.

Of course, things can still get out of step, or out of order, because there is no guarantee the AJAX call will work. A node may have been deleted or moved by someone else, or an AJAX call may have failed, or was slow. A large, fancy JS framework may be able to handle what then happens reliably and consistently, but vue.js and jQuery with some simple AJAX is not going to cope with all eventualities. But just programme defensively, and if the user gets errors, they can just refresh the page and everything should be back in sync.

consil left a reply on Recommendations For Drag-and-drop Reordering • 11 months ago

Using console.log(whatever) in your JS, and inspecting the console using Firebug or whatever equivalent your browser has, can give you a lot of information about what is happening. I tend not to look through the code too much - I find JS very difficult to get my head around being a mostly back-end developer, with it all being kind of mystery layers of dynamic context and scopes - but just inspecting what data it throws around is often all you need to know (i.e. what it does rather than how it does it).

consil left a reply on Recommendations For Drag-and-drop Reordering • 11 months ago

Rather than littering the tree with JS fragments, I use jQuery to scan the DOM for draggable lists and apply the Sortable events to it. This is at the bottom of my tree page:

@push('ready-scripts')
    jQuery("#show-map .groups, #show-map .judges, #show-map .classes").each(function(i, el){
        Sortable.create(el, {
            handle: '.drag-handle',
            animation: 150,
            forceFallback: false,
            onUpdate: function (evt) {
                var url = evt.item.getAttribute('url');
                if (url) {
                    $.ajax({
                        method: "PUT",
                        url: url,
                        data: {position: evt.newIndex}
                    });
                }
            }
        });
    });
@endpush

The selector (#show-map .groups, #show-map .judges, #show-map .classes) selects each <ul> that has sortable child elements. The onUpdate event reads the URL on a <li> that has been dragged and PUTs it to the server along with its new position.

This at the bottom of our outermost page template, just before the closing </body>, renders this @push() section in the right place:

        <script>
            jQuery(document).ready(function() {
                @stack('ready-scripts')
            });
        </script>

consil left a reply on Recommendations For Drag-and-drop Reordering • 11 months ago

Completely aside, instead of this:

<ul class="list-group" id= <?= '"section' . $section->id .'"'; ?>>

You can do this:

<ul class="list-group" id="section{{ $section->id }}">

That will keep much of the raw PHP out of the blade view.

consil left a reply on Recommendations For Drag-and-drop Reordering • 11 months ago

The url included with each element is the route that you use to update the list?

Essentially yes:

<ul class="classes list-unstyled list-group in">
    <li class="class" url="http://example.com/admin/shows/14/groupjudges/43/position/newposition">
        <a title="A show class" href="http://example.com/admin/shows/14/groupjudges/336" title="Edit judge">Judge Dredd</a>
    </li>
    <li class="class" url="http://example.com/admin/shows/14/groupjudges/43/position/newposition">
    <li class="class" url="http://example.com/admin/shows/14/groupjudges/43/position/newposition">
    <li class="class" url="http://example.com/admin/shows/14/groupjudges/43/position/newposition">
</ul>

There are more levels than that, but it gives you an idea. Each of these would need additional data to identify just their ID, so when dragging to a new parent, you can identify that parent to notify the server.

This is all generated as plain HTML using loops in blade templates. I'm sure the tree could be generated on the client side through pure data bound to the HTML using vue.js. But that's a whole new ball-game for another day :-)

consil left a reply on Recommendations For Drag-and-drop Reordering • 11 months ago

@mniblett just in the last few days, the client has asked us if they could move the sessions between judges. Oh well :-)

The general approach I took, is that each draggable <li> element is given a URL attribute. When it is dragged, that URL is used to tell the server that this element has moved (using PUT). The URL contains enough for the server to identify which element in the list you are moving, and it also identifies that it is a movement taking place.

So for example, a judge in a show may have a "moving URL":

<li url="http://example.com/show/123/judge/456/position">Judge Dredd</li>

So that is the URL we PUT to in order to tell the server this node has been dragged. What we then need is additional data to tell the server where we have dragged it to. That is sent as GET parameters. The draggable front-end library I used has draggable events to tap in. In my case I was not worried about changes to parents, but simply the new position in the current branch the judge is in - so I send position=N in the PUT request. The server then works out what needs to be changed in the database to implement that (changing siblings in the nested set left/right values - but that really depends on how your data is managed).

You (and maybe me next week) will probably also need to send the parent ID with the drag-and-drop action. So adding another custom data attribute to the draggable elements will be needed - the ID of that node on the server, because the front end will need to know the parent of the node you have dragged the element onto, so it can tell the server.

I'm sure there are frameworks and libraries to kind of do all this stuff without having to worry about the details, but I'm not into big JS frameworks and so am putting together much smaller building blocks, so have to understand a little more about what is happening at a lower level.

24th August, 2016

consil left a reply on Laravel 5.1 - Same Form For Create And Edit Page • 11 months ago

Just to add to this, I see a lot of recommendations to use Form::open() for creating a new resource and Form::model() for modifying an existing resource. In my experience, it is more beneficial to use Form::model() in both cases, i.e. when creating and modifying.

When creating a resource, the controller can provide a blank model:

$model = new Model();
return view('model.create')
    ->with('model' => $model);

Why would you do that? For defaults. Default values can be set in the model, and those will feed through to the create form:

class Model extends LaravelModel {
    protected $attributes [
        'some_field' => 'my default',
    ];
    ...
}

Depending on the context, those defaults can also be set or overridden in the controller (create method):

$model = new Model(['some_field' => 'a different default']);

8th August, 2016

consil left a reply on Getting A Tree Of Models In The Correct Order • 1 year ago

Finally did it, but what a pain! I'll post the details later, but in summary the approach was to do a single select first to get all the IDs of A, B and C in the correct order (the order will change from one context to another, so it is arbitrary). Then I do a nested eager load of A, B and C, which generates three queries for the three-level tree. Each level is given the appropriate IDs from the first query for its own ordering using the MySQL FIELDS() function.

5th August, 2016

consil left a reply on Getting A Tree Of Models In The Correct Order • 1 year ago

Just had a thought while watching the Olympics opening ceremony.

I could let Laravel eager load the nested collections. That would be fairly efficient, with it getting all the models in three queries (one for each level).

Then I can do a single database query on the same data, but with my own custom ordering, whatever it may be. The results of that plain query can be used to order the IDs of all the models in the nested collections. That should be fairly simple to do, since all the ordering data will be in once result set.

consil left a reply on Getting A Tree Of Models In The Correct Order • 1 year ago

Good question. Yes, we can just take the first D under each C to determine the order of the Cs.

consil started a new conversation Getting A Tree Of Models In The Correct Order • 1 year ago

I am going to have to explain this one as it is a bit tricky. I have a tree of different models, four layers deep. We can call then A, B, C and D. Each A has many B, each B has many C, and each C has many D. Simple enough so far. Given a single A, I want to display the tree as nested lists. So for A I show a list of B. For each B I should a nested list of C etc. So far, so good - just do n eager load and off we go: A::with('B.C.D')->get().

Now the tricky part. The property to order this tree with is an attribute of D. So the the ordering happens at the leaf nodes of the nested collections that make up the tree. How can I do that? How can I make sure B and C are ordered so that the D leaf nodes are in the correct order?

I can work around this by putting an ordering property on every level (B, C and D) in the database, but I would like to avoid that if possible. Perhaps there is some kind of reordering I can do to the nested collections once I have them back, using recursive callbacks for ordering? Not sure - I have a hunch this will be the way to do it.

Any thoughts?

20th July, 2016

consil left a reply on [L5] Disable CSRF Middleware On Certain Routes • 1 year ago

@mdeclaire That is certainly the easiest technique. But do be aware, that App\Http\Middleware\VerifyCsrfToken lists the URLs that are excluded, not the routes. It uses the $request->is() method internally, so includes whatever wildcards that supports.

Personally, I don't like mixing route names and URL fragments all over the place. The controllers should not have to know what the URL formats are (laravel out of the box puts url paths in several places, which all need to be found and replaced with route names). Anyway, sorry to rant :-)

29th June, 2016

consil left a reply on Constraining/Ordering Multi-level Eager Loaded Models • 1 year ago

Yes, that is one way to do it. Eloquent collections have some great sorting methods built in.

I've just tried this out of curiosity, and it seems to work. The crazy thing is, the number of queries that are performed by eloquent do not increase - it does one SELECT for the orderlines, putting them in order, then one select for the products, making use of the orderlines it has already selected and cached. I have this working four levels deep, and it does exactly what I need.

Orders::where('id', 1)->with([
    'orderlines' => function($query) {
        $query->orderBy('line_number');
    },
    'orderlines.products' => function($query) {
        $query->orderBy('product_number');
    },
])->first();

(Ignore the fact that I have multiple products on each orderline!)

I will go for this technique for now, and if it every stops working (because I am not sure if it works by design, or some fluke) I have the fallback of being able to order the collections after the full nested tree is fetched from the database.

consil left a reply on Constraining/Ordering Multi-level Eager Loaded Models • 1 year ago

The callback that is passed $query seems to be called just once, against the last model in the chain. So in this case against the product. I need to be able to tap into both the product and the orderlines relationship query.

consil started a new conversation Constraining/Ordering Multi-level Eager Loaded Models • 1 year ago

So I can eager-load the orderlines for an order:

Orders::find(1)->with('orderlines');

I can order the eager-loaded child records:

Orders::find(1)->with(['orderlines' => function($query) {
    $query->orderBy('line_number');
}]);

I can eager-load multiple levels of children:

Orders::find(1)->with('orderlines.product');

But how do I set ordering constraints for that? Separate queries will be run for both orderlines and the product, so the same query cannot be used for both models.

28th June, 2016

consil left a reply on Handling AJAX DELETE • 1 year ago

Got it working now in a very generic way, and will document it later (hopefully today). Some of the features of the solution are:

  • Each model looks after its own pre-delete checks, and raises an exception if any fail (e.g. trying to delete a product that has already been ordered). The exception message text ends up on the front end.
  • The backend destroy() does not care if it has been called by AJAX or a form. It returns the appropriate result in both cases.
  • There is minimum to add and do in both the controllers and the front end.
  • It uses rails.js for convenience. With a bit more custom code this could be avoided and some lines of JS avoided.

consil left a reply on Laravel 5.1 404 Response To JSON • 1 year ago

As an alternative, is there any way to return a 404 and an array of data, leaving Laravel to decide how it gets encoded? The client may have requested JSON, or it may have requested something else (e.g. XML). Laravel knows what to return if the controller just returns an array. But how do you do that with a non-200 return code?

27th June, 2016

consil left a reply on Handling AJAX DELETE • 1 year ago

This is what I have tried first:

Include this JS in the page (after jQuery, with no need to initialise it): https://github.com/rails/jquery-ujs/blob/master/src/rails.js

In the page head add these two meta elements:

<meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="csrf-param" content="_token">

The delete link then looks like this:

<a href="{{ route('my_resource.destroy', [$my_model_instance]) }}" data-method="delete" data-confirm="Confirm delete?" class="btn btn-danger">Delete</a>

That gives me a big red delete button, that asks if I'm sure, then posts a DELETE to the resource. It does a full POST rather than AJAX, but I suspect I can fix that with some settings. It's 500 lines of JS, which is certainly overkill, but it's just for admins, and I guess once it's loaded, it's loaded. I'll explore this a little more after tea.

consil left a reply on Handling AJAX DELETE • 1 year ago

@tomschlick Thanks. I've seen that one around, which dynamically turns the anchor into a DELETE form. That keeps the source markup much neater, which is certainly one of the things I was looking for. However, it does then involve a full POST to the server, rather than using AJAX. That is okay for resource show pages where the user will always (assuming there was no problem deleting) be redirected after deleting, but if the user is deleting from inside the resource index page, then a redirect gets messy - you need to get the user back to the page they were on, rather than just removing the table row that contained the resource.

consil left a reply on Handling AJAX DELETE • 1 year ago

@martinbean I understand what you are saying about the links, but I'm not talking about using GET to modify anything. The request would still be a DELETE, which no anchor can deliver directly. The route for the resource delete is identical to the resource show, but with a different verb, so even accidentally going to that route (e.g. if the JS isn't working) would not do any harm.

From my POV, I just want to keep the markup simple, as I have a lot of it to maintain.

I've got the CSRF token in the header already, so your sample bit of JS should pick that up for the AJAX calls:

<meta name="csrf-token" content="{{ csrf_token() }}">

One downside with using the form, is that if the JS does not pick it up to catch it, then a single click will delete the resource without ANY confirmation message. I think this is why I have seen some libraries that will turn an anchor into a form dynamically on the page, so there is no DELETE form at all if JS has not recognised the delete link. A link could by AJAX and converted into a DELETE request may also have some issues that I've miss too...?

Anyway - your code looks like it handles the main functionality nicely :-) I'll try it out wrapping it around and anchor and see how that goes.

consil left a reply on Handling AJAX DELETE • 1 year ago

I'm looking into this at the moment:

https://github.com/rails/jquery-ujs/wiki/Unobtrusive-scripting-support-for-jQuery

Seems like it does a lot of stuff I don't need, so may be overkill, but if it handles DELETE in a commonly-handled and accepted way, then I'll probably end up using it.

consil started a new conversation Handling AJAX DELETE • 1 year ago

Not sure if this is the best channel, but I'll ask here. I'm use resource controllers, and they include a destroy route using a DELETE method. I would like to support the DELETE function using AJAX. The main requirements are:

  • I would it to be unobtrusive - the delete links should just be anchor elements, not forms.
  • I would like to be able to handle errors on the server side, with the ability to pass a message back to the user if the model fails to delete.
  • I would like the user to confirm they do want to delete before the DELETE is sent.
  • Redirect on success should - I guess - happen on the client, with the appropriate success data sent back.

On that last point, the success return should be a data structure that includes a success message, the ID of the item deleted, and the URL for the index page to go to. The page on which the delete button is used can decide whether it needs to redirect the user to the index page, or simply remove a row (by ID) from a table of models on the page (assuming the user is deleted from the index page).

I have not been able to find a standard way to do this in Laravel. It makes sense for it to use jQuery and vue.js, I expect. All examples I have seen lack one of the above requirements - they force a redirect, or don't return error messages, or don't do a confirm, or build a form in the background so a browser POST is issued. So, is there an off-the-shelf way to handle all this, perhaps using a jQuery package, or just a simple block of code, because I feel like I'm going to have to reinvent something here that must have been implemented a thousand times before. Thanks!

26th June, 2016

consil left a reply on Shopping Cart With (super-)flexible Products? • 1 year ago

Yeah, got the t-shirt (literally). I know the Moltin lads - right from their launch on a Super Mondays talk - must be four/five years ago. I was always interested in the fact they used PHP, since they had OmniPay linking to the payment gateways, which I use a lot. Whether that is still true given their latest funding, I'm not sure - haven't asked them about the platform.

Anyway, I suspect my complex structure of "products" is probably too much for Moltin to be of any help here. I probably could squeeze the products into the API, but would need an awful lot of logic built into the front-end cart - which is what I need to have anyway. So the Moltin API would just end up being storage and not much more, and eloquent is handling that side nicely.

consil left a reply on Shopping Cart With (super-)flexible Products? • 1 year ago

Thanks, I'm studying a number of carts to see what problems they have had to solve. None of them fit my requirements entirely, but the basic underlying structures and methods will still apply.

23rd June, 2016

consil left a reply on Handling Date Attributes After Submitting A Form • 1 year ago

Maybe there is some other level where the conversion from a submitted "dob" string to a Carbon object happens? Probably not middleware, since it is too specific to a model.

consil started a new conversation Handling Date Attibutes With Forms • 1 year ago

An eloquent model can be given a list of attributes that are dates:

// Model
protected $dates = ['dob', 'start_date', 'date_for_foo'];

When model instances are fetched from the database, these dates are automatically converted to Carbon objects, which is handy. No getter is required to do that conversion. Those Carbon objects can then easily be formatted for use in display and in forms.

Now the problem comes when binding a model to a form. When the form containing say dog is submitted, it will contain the dob as a string. This may be YYYY-MM-DD or DD-MM-YYYY or some other format, all depending on the requirements of the system. Passing that to the model to save gives errors:

$my_model->update(Input::only(['dob'])); // Does not work - it expects Carbon to be passed in.

I work around this with a mutator:

public function setDobAttribute($value)
{
    if (! $value instanceof Carbon) {
        $value = Carbon::parse($value); // Parse according to what formats we expect from the user.
    }
    $this->attributes['dob'] = $value;
}

That works, but I have the hunch that it is unnecessary. Do I need to do this, or should using the $dates property do this for me automatically, meaning that I am possibly doing something else wrong? Or is this always needed, with the $dates property feature not really designed for forms in the first place?

consil left a reply on Create A Custom Relationship Method • 1 year ago

I can actually get almost there:

// Dog
public function orders()
{
    $relation = $this->belongsToMany('App\OrderLine');

    $relation->getQuery()
        ->join('orders', 'order_lines.order_id', '=', 'orders.id')
        ->select('orders.*')
        ->groupBy('orders.id');

    return $relation;
}

The query in a relation can be adjusted, and in this case I slip in another table, and select from that table, making sure I bring back unique orders only. The downside is that the retrieved data populates OrderLine models and not Order models. So if I wanted to make this a generic solution, I could extend the model to have a relatedToMany() method for example, with a callback to adjust the query (just in case the query becomes a value object in the future, which is probably unlikely).

// MyModel
public function someDistantModels()
{
    return $this->relatedToMany('app\ModelToReturn', function($query) {
        $query -> ... // create the query to go find the model data
    });
}

The default query would start with a simple select to the current model's table, and you can adjust the query to extend out from there in whatever direction you like.

If I get this implemented as a solution, I'll post back here.

consil left a reply on Create A Custom Relationship Method • 1 year ago

Yes, there will be a number of joins, but nothing too complicated. The built-in laravel relationship methods cover some 90% of common queries that you may want. Adding further relationship queries does happen in core eloquent from time-to-time, but the more they add, the more they walk into the law of diminishing returns. But what I have here is just a standard relationship and nothing too special, but something that can be done efficiently in one query, but could involve a very large number of queries and models if not.

I suspect I will and up with the approach you suggest, but was just exploring how easy it would be to turn that custom query into a relationship method.

Here is the run-down of the real-world relationships: there is a dog show, and that has a number of show classes - sessions where groups or teams of dogs are judged. A competitor can book dogs onto one or more of these sessions. Most sessions require one dog to the specified when booking. Some sessions require more than one dog to be booked on - so I can make a booking for the "terrier brace" show session and I MUST link TWO of my dogs to that booked session. Those dogs don't form a team or brace in any other context - they are just brought together for that purchased session.

That purchased session is an orderline. I can book multiple sessions for a single show in one order.

Working through this project, I now know FAR more about dogs and dog shows than I every thought I would need to know, but it's interesting stuff.

consil left a reply on Create A Custom Relationship Method • 1 year ago

Okay, I seem to be confusing people by putting real names to models. I'll go more abstract.

We have this relationship:

A >--< B >-- C

which expands to this given the pivot table:

A --< AB >-- B >-- C

Given:

$a = A::find(1)

I would like to find all the C models (cs) that $a is connected to, as a relationship method:

$all_cs = $a->cs;

I actually want to get a little further to D, but we'll stop at C in this example, just accepting that there is an arbitrary query involved here.

22nd June, 2016

consil left a reply on Create A Custom Relationship Method • 1 year ago

Probably not a good example - my orderline does have a single product, but that product purchase is customisable with a multiple number of additional model items. It is actually for a dog show - a product is an entry to a particular class, and that entry can include the user linking up multiple dogs to that orderline to make up a team. So I am starting with the sub-product (a dog) and trying to get a list of shows it is booked onto.

consil left a reply on Create A Custom Relationship Method • 1 year ago

It looks like I would need to provide a concrete instance of Illuminate\Database\Eloquent\Relations\Relation which supports the relationship I would like to implement. And then extend my model with a method long the lines of the built-in relationship methods, such as belongsToMany https://github.com/illuminate/database/blob/master/Eloquent/Model.php#L932

Unless there is a way to chain the relationship methods that return multiple records together? For example, $orderline->order->user works because there is just one result at each stage. But $user->orders->orderlines is not happy at all, because there are multiple results at each stage.

consil left a reply on Create A Custom Relationship Method • 1 year ago

I feel like there should be a way to build up relationship objects, in a sequence, one join at a time.

consil started a new conversation Create A Custom Relationship Method • 1 year ago

This has been driving me mad, because this is a question asked over and over, but the answers all seem to miss the point and provide a different solution than was asked.

What I would like to do, is to create a custom relationship method so that I can get a bunch of related models from a model instance, given an arbitrary relationship between those models.

We are used to this kind of thing out of the box:

// OrderLine
public function order
{
    return $this->belongsTo('App\Order');
}

Then we can get the order model from an orderline like this:

$order = $orderline->order;

Simple. Magic stuff happens in belongsTo() - that method generates a relationship object. The relationship object is quite hard to understand, and I have not got my head around it. So my use case is that I want to do this:

$orders = $product->orders;

A product can be on many orderlines (many-to-many, with pivot table). An orderline is for an order. I would like to do this in one simple query, so the query will include a distinct or group by so I don't get orders multiple times (a product may be on several order lines in a single order).

So, how can I do this? What would the order() method look like? Now, I could create a getMeTheOrders() method that looks up the orderlines, gets the orders for each, throws away any duplicate orders, then returns the result. I don't want to do all those queries when this can be done in one query. Similarly, I want to avoid a sub-select query, as they can be very slow in MySQL since they don't get optimised well at all.

Any examples out there? Is this actually a lot more complex than I am hoping it is (considering that I cannot see this question really cracked yet, often asked wrt being able to find related records via a pivot table.

31st May, 2016

consil left a reply on How To Shorten A Title Post? • 1 year ago

Adding the ellipsis in CSS is certainly the better idea when fitting a title into a limited width and when you want to keep it on just one line. This can be tricky at times, for example to use it in path parts of a bootstrap breadcrumb (not found how to do that yet, without breaking the breadcrumb) so the laravel str_limit() helper is very useful there.

Edit Your Profile
Update

Want to change your profile photo? We pull from gravatar.com.