0

Trying to get my head around the logic for the following.

I have 3 images and two static functions. I believe it's possible to make one function but lack the knowledge of how to achieve this and putting the issue into words is hard, so google is of no help currently.

1 of the 3 images is outside of the foreach loop in the view, so in the model I created two public static functions. This is my issue, is there a better way to do this then use 2 functions?

Table in the database is "images" and consists of following:

  • id
  • image
  • page
  • list

Currently the Model looks like this:

class Images extends Eloquent {

public static function indexPageTL() 
  {
    $images = DB::table('images')
        ->where('page', 'index')
        ->whereBetween('list', array(0,1))
        ->orderBy('list', 'asc')
    ->get();

    return $images;
  }

  public static function indexPageMR() 
  {
    $images = DB::table('images')
        ->where('page', 'index')
        ->whereBetween('list', array(2,4))
        ->orderBy('list', 'asc')
    ->get();

    return $images;
  }
}

As you can see in the model I am using an array to select the items I need, so as to separate them (hence the two functions). I pass this to my services to better combine the data:

namespace Services;

use Images;

class IndexService
{
  public function indexData() 
  {
    $data = array(
      'images'  => Images::indexPageMR(),
      'imagesTL'  => Images::indexPageTL()
    );
    return $data;
  }
}

Then in my controller:

use Services\IndexService;

class IndexController extends BaseController
{

public function index() {
   return View::make('index', with(new IndexService())->indexData());
    }
}   

Finally in the view:

@foreach($imagesTL as $fetch)
 <img src="{{ $fetch->image }}" class="img-responsive">
 @endforeach 

//then further down the page I call the indexPageMR()

@foreach($imagesMR as $fetch)
 <img src="{{ $fetch->image }}" class="img-responsive">
 @endforeach 

Question is essentially, do I need 2 separate public static functions for this or can I combine them, if i can combine them how do I do it?

Apologies if this is unclear, as I said it's hard to put into words.

SethCodes
  • 283
  • 1
  • 5
  • 14
  • 2
    This question is a *perfect* demonstration that before you start doing "oop" and using frameworks - you need to learn basics. – zerkms Sep 28 '14 at 00:25
  • Also on that note it's perfect example that even when I think I am getting somewhere I am essentially getting no-where. I thought I was on the right track, I guess not. Sorry to waste your time. Can you direct me somewhere when I can get some documentation, I have read a lot about OOP and it's practices, however making it work in a framework and in practice is much more difficult. – SethCodes Sep 28 '14 at 00:32
  • @zerkms, I'm not sure the snark is helpful or necessary. We're all here on SO trying to learn something. – damiani Sep 28 '14 at 03:42
  • @damiani: I don't find learning quantum physics prior to arithmetics efficient or even possible. – zerkms Sep 28 '14 at 03:47
  • Certainly, but if you think the questioner needs to learn better arithmetic, then help guide him or her to a good, solid arithmetic text that would put them on the right path...or take a few minutes to teach them some of the arithmetic they are lacking...or, perhaps, say nothing at all. – damiani Sep 28 '14 at 04:12

1 Answers1

1

There are two separate issues at play here: one is your question, can you combine your two image-gathering functions into one (i.e. simplifying the logic in your model); the other issue is the correct implementation of OOP principles, in order to make your code testable and flexible.

(Disclaimer: I'm new to all this, too, so hopefully more experienced folks will chime in and correct any of my errors in the comments.)

Before you delve into the OO way to deal with this, let's get your business logic itself to be a little simpler, more flexible, and more "Laravel-like".

First, the model (which will ultimately change when you implement full OO principles):

class Image extends Eloquent {

    public function scopeOnPage($query, $index)
    {
        return $query->wherePage($index);
    }

    public function scopeLocationBetween($query, $location)
    {
        return $query->whereBetween('list', $location);
    }

    public function getIndexPageImages($index, $location)
    {
        return $this->onPage($index)->locationBetween($location)->orderBy('list')->get();
    }

}

The changes here include:

  • Avoiding static functions; instead, the functions will act upon the Image object that we create elsewhere.
  • Making our primary method, getIndexPageImages, more flexible and reusable, rather than hardcoding in the values for location. Our model doesn't need to know about TL, MR, or what list values constitute those.
  • Taking advantage of Eloquent to make queries simpler and readable. I've used query scopes here, which will allow you to reuse that logic elsewhere in your model if needed.

Now, from our controller, we can ask our Image model to give us exactly what we want (again, as with the model, this will change once you go full-OOP...but this is the starting point):

class IndexController extends BaseController {
    public function showIndex($index)
    {
        $images = new Image;
        $data['images_TL'] = $images->getIndexPageImages($index, [0,1]);
        $data['images_MR'] = $images->getIndexPageImages($index, [2,4]); 
        return View::make('showIndex', with($data));
    }
}

...and our route:

Route::get('images/{index}', 'IndexController@showIndex');

Our route passes along the index parameter to the controller. In the controller, we instantiate a new Image object, then ask it for the specific images we want, divided by TL and MR. (Since this logic is no longer hardcoded into our model, we have the flexibility to ask it for other groupings of images, if we wanted to, without having to go in and change our model.) We then pass that data to the view, where you would loop over $images_TL and $images_MR in foreach loops, as you are doing now.

So now we have a 'thinner' model, a 'fat' controller (i.e. it contains logic that is best kept elsewhere), and while we are taking better advantage of the Eloquent object, we're still not fully-OO.

Which leads to the second issue: how do you implement OOP correctly in a case like this, and, more generally, how to you learn how to do it?

Our controller shouldn't have to gather data for the view, it should be given it (through dependency injection). And we need a layer of abstraction between our model and our controller, so that we're not so tightly coupled with the Eloquent ORM. The repository pattern would solve this, and take you to full-OOP nirvana.

  • The repository implements an interface, which sets out (as a 'contract') what methods the repository must have.
  • The repository communicates with the model to collect the data based on our 'business logic.'
  • Then, a service provider binds the interface and the repository together, so that we can inject the interface and Laravel will resolve the binding and serve up our repository.
  • Finally, inject the interface into the __construct method of the controller (or, in Laravel 5, you can inject it directly into a method, if the whole controller doesn't need it.)

How you set these up depend in part on details of your application that aren't mentioned in your question. But here are a couple great, practical resources to help:

Both of these books are well worth their price, for gaining a solid understanding of OOP and SOLID principles, and—more importantly—seeing them in action, applied to Laravel apps.

Finally, subscribe to Laracasts and let Jeffrey Way teach you all of this like only he can.

Good luck.

Community
  • 1
  • 1
damiani
  • 7,071
  • 2
  • 23
  • 24
  • Thankyou so much for taking the time to explain this to me! Honestly, you were such a great help. Thankyou 100x over. – SethCodes Sep 28 '14 at 09:18