简体   繁体   中英

How do I prevent repetition in my Laravel app?

I am currently working on a new large app and I am trying to ensure I implement best practices from the start. I am new to Laravel so one question I have is how can I limit repetition throughout my app.

As an example I currently have a resource controller for an admin section that makes a view like so:

public function index()
{

    // $data will be passed to the view
    $data = array(
        'pageTitle'      => 'Manage Products',
        'btn'            => array(
            'title'      => 'Add product',
            'url'        => 'admin.catalog.product.create',
        )
    );

    return View::make('catalog::product.index', $data)->with('products', Product::all());

}

My view file looks likes so:

<table class="table table-striped">
<thead>
    <tr>
        <th>ID</th>
        <th>Name</th>
        <th>SKU</th>
        <th>Price</th>
        <th>Qty</th>
        <th>Created</th>
        <th><i class="icon-cog"></i></th>
    </tr>
</thead>
<tbody>
@foreach ($products as $product)
<tr>
    <td>{{ $product->pid }}</td>
    <td><a href="{{ URL::route('admin.catalog.product.edit', $product->pid) }}">{{ $product->name }}</a></td>
    <td>{{ $product->sku }}</td>
    <td>{{ Currency::display($product->price) }}</td>
    <td>{{ $product->quantity }}</td>
    <td>{{ Dates::showTimeAgo($product->created_at) }}</td>
    <td>
        <a href="{{ URL::route('admin.catalog.product.edit', $product->pid) }}" class="btn btn-success btn-mini pull-left">Edit</a>

        {{ Form::open(array('route' => array('admin.catalog.product.destroy', $product->pid), 'method' => 'delete', 'data-confirm' => 'Are you sure?')) }}
        <button type="submit" href="{{ URL::route('admin.catalog.product.destroy', $product->pid) }}" class="btn btn-danger btn-mini">Delete</button>
        {{ Form::close() }}
    </td>
</tr>
@endforeach
</tbody>

Is there a way that I can just use the one view file for all admin tables and pass what columns I want for the header and body through the controller instead of hard coding this in the view like above?

I know I can pass the $data array but not sure how to go about passing the columns I want through this. Any ideas or suggestions would be much appreciated.

I don't think this really is a question regarding Laravel, but hey, here we go.

You could add functions to your models to map column names to your values.

public function getColumns()
{
    return array(
        'ID' => 'pid',
        'Name' => 'name',
        ....
    );
}

public function getColumnData()
{
    $columns = $this->getColumns();

    $records = [];
    foreach ($columns as $column) {
        if ('name' == $column) {
            $data = '<a href="' . URL::route('admin.catalog.product.edit', $this->pid) . '">' . $product->name . '</a>';
        } if else (..) {
            ...
        } else {
            $data = $this->{$column};
        }
    }

    return $records;
}

And your view would become something like this:

<thead>
    <tr>
        @foreach ($records->first()->getColumns() as $column)
        <th>{{ $column->name }}</th>
        @endforeach
    </tr>
</thead>
<tbody>
    @foreach ($records->all() as $record)
    <tr>
        @foreach ($record->getColumnData() as $data)
        <td>{{ $data }}</td>
        @endforeach
    </tr>
    @endforeach
</tbody>

I would like this

View:

<table>
    <thead>
        <tr>
            @foreach ($records[0] as $k => $v)
                <th>{{ ucwords(str_replace('_', ' ', $k)) }}</th>
            @endforeach
        </tr>
    </thead>
    <tbody>
        @foreach ($records as $record)
            <tr>
                @foreach ($record as $col)
                    <td>{{ $col }}</td>
                @endforeach
            </tr>
        @endforeach
    </tbody>
</table>

Controller: (Using getColumns helper function)

$users = User::all();
// In the first array, just pass the fields
// you want to get, second one is data array
$data['records'] = getColumns(array('id', 'username', 'email'), $users->toArray());
return View::make('user.users', $data);

Or, you may use it like this

$users = User::all()->toArray();
// In this  example, I want to show only
// username, first_name and last_name
$records = getColumns(array('username', 'first_name', 'last_name'), $users);
return View::make('user.users')->with('records', $records);

This is a helper function, it's possible to use this from any model/controller

function getColumns($keys, $result)
{
    $records = array();
    foreach ($result as $row) {
       $record = array();
       foreach ($row as $k => $v) {
           if(in_array($k, $keys)) $record[$k] = $v;
       }
       $records[] = $record;
    }
    return $records;
}

I'm using helper function because, I can use it with any model and it's in my filters.php file, you can put it anywhere. Actually, I have a file custom_helpers.php file in app folder where filters.php and at the end of my filters.php file, I've this

include "custom_helpers.php";

In this custom_helpers.php I've this helper function with other functions. Here is an example with screenshot

$users = User::take(5)->get()->toArray();
$records = getColumns(array('username', 'first_name', 'last_name'), $users);
return View::make('user.users')->with('records', $records);

Screen Shot: 在此输入图像描述

Thanks for all the responses. I actually ended up using a package created by Rob Gordijn. Works great for me and prevents a lot of repetition. You can get this package at the URl below:

https://github.com/RobGordijn/Bamboo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM