Search code examples
laravel-5dompdf

Is DOMPDF the right tool for complex Reports?


I'm using barryvdh/laravel-dompdf for creating a Report from a Laravel/Jquery Application and this Report is pretty complex - after the startpage there are a couple of pages which are repeated according to the report data. Every page has a header an footer and i wanted to ask if it's possible to restrict the main content in a way so that it does not overlap with footer or header like this enter image description here

i've tried to insert pagenumbers as well but without any success. This is how my Main-Report-Page looks

<body>


    <table width="100%">
        <tr>
             <td>
                <img src="assets/images/track-more.png" width="200px" height="auto">
              </td>
            <td>
                <img class="logofixed" src="assets/images/frauscher1.png" width="200px" height="auto">
            </td>
        </tr>
    </table>


<h1 class="center">report</h1>


</table>
<div class="page-break"></div>

@foreach ($measures as $measure)
    @include("snippets/razor")
    <div class="page-break"></div>
@endforeach

    <footer>
        <hr>
        <script type="text/php">
    if (isset($pdf)) {
       $font = $fontMetrics->getFont("Arial", "bold");
       $pdf->page_text(555, 745, "Page {PAGE_NUM}/{PAGE_COUNT}", $font,    7, array(0, 0, 0));
    }

    </script>

    </footer>
</body>

My snippets/razor page is like this:

 <div class="row">

    <table>
        <tr>
            @if ($measure->pass == 1)
                <td class="ok"><h1>{{$measure->text}}</h1></td><td></td>
            @else
                <td class="fail"><h1>{{$measure->text}}</h1></td><td></td>
            @endif
        </tr>
    </table>
    <table>

        <tr>
            <td>date1:</td><td>{{$measure->date1}}</td>
        </tr>
        <tr>
            <td>date2:</td><td>{{!empty($measure->date2)?$measure->date2:""}}</td>
        </tr>
        <tr>
            <td>date3:</td><td>{{$measure->date3}}</td>
        </tr>
        <tr>
            <td>date4:</td><td></td>
        </tr>

    </table>
@if(!empty($measure->items))
    <table class="measure">
        <tr>
            <th>headerx</th>
            <th>headerx</th>
            <th>headerx</th>
            <th>headerx</th>
            <th>headerx</th>
            <th>headerx</th>
            <th>headerx</th>
            <th>headerx</th>
        </tr>
        @foreach ($measure->items as $i => $item)
            @php  $class = $i % 2 === 0 ? 'even' : 'odd'; @endphp
            <tr class="{{ $class }}" >
                <td>{{ $item->text }}</td>
                <td>{{ $item->data1}}</td>
                <td>{{ $item->data2}}</td>
                <td>{{ $item->data3}}</td>
                <td>{{ $item->data4}}</td>
                <td>{{ $item->data5}}</td>
                @if ($item->data1== 1)
                    <td class="ok">Success</td>
                @else
                    <td class="fail">Failure</td>
                @endif


                <td>{{ $item->data6}}</td>
            </tr>
        @endforeach
    </table>
   @endif
</div>

@edit:

overlapping

this happens when i used "fixed" header and footer

this is my current css

  body {
        font-family: Arial, Helvetica, sans-serif;
        font-size: 14px;
    }

    table.measure, table.measure > tr, table.measure td, table.measure th {
        width: 100%;
        border: 1px solid black;
        padding: 5px;
        border-collapse: collapse;
    }

    .page-break {
        page-break-after: always;
    }

    .center {
        text-align: center
    }


    .logofixed {
        position: fixed;
        right: 0;
    }

    .logofixedleft {
        position: fixed;
        left: 0;
    }



    .bestanden {
        color: white;
        background-color: #95B711;
    }

    .fehler {
        color: white;
        background-color: #e2001a;
    }

    .even {
        background: #FFFFFF;
    }

    .odd {
        background: #a3adb2;
    }

/*   @page {
        margin-top: 2cm;
        margin-bottom: 2cm;
    }*/


    head {
        position: fixed;
        top: 1cm;
    }


    footer {
        position: fixed;
        bottom: 0cm;
    }

    hr {
        border: none;
        height: 1px;
        /* Set the hr color */
        background-color: black; /* Modern Browsers */
    }

    table { overflow: visible !important; }
    thead { display: table-header-group }
    tfoot { display: table-row-group }
    tr { page-break-inside: avoid }

mainpage:

<body>
<head >
    <img class="logofixedleft" src="assets/images/dummy.png" width="200px" height="auto">
    <img class="logofixed" src="assets/images/dummy.png" width="200px" height="auto">

    <hr >
</head>


@foreach ($measures as $measure)
    <div class="page-break"></div>
    @include("snippets/razor")

@endforeach

<footer>
    <hr>
    {{--<div class="pagenum-container">Seite <span class="pagenum"></span></div>--}}
    <script type="text/php">
               $font = $fontMetrics->getFont("Arial", "bold");
               $pdf->page_text(45, 765, "Page {PAGE_NUM}/{PAGE_COUNT}", $font, 8, array(0, 0, 0));

      </script>
</footer>

</body>

this is the page with iterates "snippets/razor"

<div class="row" style="margin-top:1cm">

    <table>
        <tr>
            @if ($measure->pass == 1)
                <td class="ok"><h1>{{$measure->text}}</h1></td><td></td>
            @else
                <td class="fail"><h1>{{$measure->text}}</h1></td><td></td>
            @endif
        </tr>
    </table>

@if(!empty($measure->items))
    <table class="measure" width="100%" >
        <thead>

        <tr>
            <th>column</th>
            <th>column</th>
            <th>column</th>
            <th>column
                </th>
            <th>column</th>
            <th>column</th>
            <th>column</th>
            <th>column</th>
        </tr>
        </thead>
        @foreach ($measure->items as $i => $item)
            @php  $class = $i % 2 === 0 ? 'even' : 'odd'; @endphp
            <tr class="{{ $class }}" >
...
            </tr>
        @endforeach
    </table>

   @endif
</div>

Solution

  • Header / Footer on every page

    In order to show the header / footer on every page you need need to use fixed positioned elements, give the page some margin so the elements don't overlap and then move the header / footer inside the margin with negative top / bottom values.

    Something like this:

    <html>
    <head>
      <style>
        @page { margin: 100px 25px; }
        header { position: fixed; top: -60px; left: 0px; right: 0px; height: 50px; }
        footer { position: fixed; bottom: -60px; left: 0px; right: 0px; height: 50px; }
      </style>
    </head>
    <body>
      <header>header on each page</header>
      <footer>footer on each page</footer>
    </body>
    </html>
    

    Page breaks

    You can create manual page breaks with the following:

    <style>
    .page-break {
        page-break-after: always;
    }
    </style>
    <div class="page-break"></div>
    

    Source:

    page breaks

    header / footer on every page