Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu zend_framework Kanał ATOM (tag: zend_framework)

Autor wpisu: Diabl0, dodany: 20.11.2008 09:46, tagi: php, zend_framework

Ostatnio po raz kolejny w czasie prac nad jednym z projektów stanąłem przed problemem generowania dokumentów do druku. I po raz kolejny automatycznie wybór padł na PDF. I znowu ( ;) ) po raz kolejny stanąłem przed problemem jakiej klasy użyć aby ułatwić sobie zadanie. Tym razem mój wzrok padł na TCPDF i jak na razie spełnia on pokładane w nim nadzieje.

Poniżej natomiast znajdziecie mały wrapper aby korzystanie z TCPDF w Zend Framework było proste, wygodne i zgodne z standardami ZF.

Samą klasę znajdziecie na SF.net: http://sourceforge.net/project/showfiles.php?group_id=128076 - wystarczy ją pobrać i wrzucić do katalogu library/Mao/TCPDF/ (oczywiście Mao zamieniacie na własną nazwę).

Następnie wystarczy utworzyć prostą klasę Mao_TCPDF w library/Mao/TCPDF.php , a w niej:

<?php
/**
 * This is a Zend Framework wrapper for TCPDF class for generating PDF documents without requiring external extensions.
 *
 * {@link http://www.tcpdf.org TCPDF project} has been originally derived in 2002 from the Public Domain {@link http://www.fpdf.org FPDF class} by Olivier Plathey, but now is almost entirely rewritten.
 *  *
 * @category   Mao
 * @package    Mao_TCPDF
 * @author Krzysztof 'Diabl0' Szatanik
 * @copyright Copyright (c) 2008, MAO Group
 * @link http://www.tcpdf.org
 */

Zend_Loader::loadFile( 'tcpdf.php', '../library/Mao/TCPDF/', true );

/**
 * This is a Zend Framework wrapper for TCPDF class for generating PDF documents without requiring external extensions.
 *
 * {@link http://www.tcpdf.org TCPDF project} has been originally derived in 2002 from the Public Domain {@link http://www.fpdf.org FPDF class} by Olivier Plathey, but now is almost entirely rewritten.
 *
 * @category   Mao
 * @package    Mao_TCPDF
 * @author Krzysztof 'Diabl0' Szatanik
 * @copyright Copyright (c) 2008, MAO Group
 * @link http://www.tcpdf.org
 */
class Mao_TCPDF extends TCPDF
{

    /**
     * @var alias for total number of pages
     */
    protected $AliasNbPages = '{nb}';

    /**
     * This is the class constructor.
     *
     * It allows to set up the page format, the orientation and the measure unit used in all the methods (except for the font sizes).
     *
     * @param string $orientation page orientation. Possible values are (case insensitive):<ul><li>P or Portrait (default)</li><li>L or Landscape</li></ul>
     * @param string $unit User measure unit. Possible values are:<ul><li>pt: point</li><li>mm: millimeter (default)</li><li>cm: centimeter</li><li>in: inch</li></ul><br />A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit.
     * @param mixed $format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).<ul><li>4A0</li><li>2A0</li><li>A0</li><li>A1</li><li>A2</li><li>A3</li><li>A4 (default)</li><li>A5</li><li>A6</li><li>A7</li><li>A8</li><li>A9</li><li>A10</li><li>B0</li><li>B1</li><li>B2</li><li>B3</li><li>B4</li><li>B5</li><li>B6</li><li>B7</li><li>B8</li><li>B9</li><li>B10</li><li>C0</li><li>C1</li><li>C2</li><li>C3</li><li>C4</li><li>C5</li><li>C6</li><li>C7</li><li>C8</li><li>C9</li><li>C10</li><li>RA0</li><li>RA1</li><li>RA2</li><li>RA3</li><li>RA4</li><li>SRA0</li><li>SRA1</li><li>SRA2</li><li>SRA3</li><li>SRA4</li><li>LETTER</li><li>LEGAL</li><li>EXECUTIVE</li><li>FOLIO</li></ul>
     * @param boolean $unicode TRUE means that the input text is unicode (default = true)
     * @param String $encoding charset encoding; default is UTF-8
     */
    public function __construct( $orientation = 'P' , $unit = 'mm' , $format = 'A4' , $unicode = true , $encoding = "UTF-8" )
    {
        parent::__construct( $orientation, $unit, $format, $unicode, $encoding );

        // Zawsze o tym zapominam, więc poleciało do konstruktora :)
        $this->AliasNbPages();
    }

    /**
     * Zwraca szerokość strony
     *
     * @return float
     */
    public function getPageWidth()
    {
        return $this->w - $this->rMargin - $this->x;
    }

    /**
     * Prints a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.<br />
     * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting.
     * @param float $w Cell width. If 0, the cell extends up to the right margin.
     * @param float $h Cell height. Default value: 0.
     * @param string $txt String to print. Default value: empty string.
     * @param mixed $border Indicates if borders must be drawn around the cell. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
     * @param int $ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right (or left for RTL languages)</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>
		Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
     * @param string $align Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li><li>J: justify</li></ul>
     * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
     * @param mixed $link URL or identifier returned by AddLink().
     * @param int $stretch stretch carachter mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if necessary</li><li>2 = forced horizontal scaling</li><li>3 = character spacing only if necessary</li><li>4 = forced character spacing</li></ul>
     * @since 1.0
     * @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), AddLink(), Ln(), MultiCell(), Write(), SetAutoPageBreak()
     */
    public function Cell( $w , $h = 0 , $txt = '' , $border = 0 , $ln = 0 , $align = '' , $fill = 0 , $link = '' , $stretch = 0 )
    {
        //html_entity_decode("€", ENT_COMPAT, "UTF-8");
        if( $txt != '' )
        {
            $txt = str_replace( '€', html_entity_decode( "€", ENT_COMPAT, "UTF-8" ), $txt );
        }

        parent::Cell( $w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch );
    }

}
?>

W zasadzie wszystko powinno być jasne, ale na koniec jeszcze 2 uwagi.

1 - Własnego konstruktora używam z 2 powodów - AliasNbPages o którym zawsze zapominam w samym kodzie, i ładowanie własnego konfiga z Zend_Config (ten fragment dla czytelności pominąłem na powyższym listingu).

2 - metoda Cell - została lekko nadpisana z powodu często używanego przeze mnie znaku €. Po prostu wygodnie jest mi w kodzie używać znaku entity & euro ;.

Related posts

Autor wpisu: Diabl0, dodany: 13.11.2008 13:06, tagi: zend_framework

Przy pracy nad serwisami o dużym obciążeniu bardzo ważną sprawą jest optymalizacja i keszowanie danych. Zend_Cache na szczęście wybitnie nam w tym pomaga, a od wersji 1.7 dodatkowo oferuje kilka ciekawych nowości.

Zacznijmy od Zend_Cache_Backend_TwoLevels - dzięki niemu w prosty sposób można połączyć zalety szybkich mechanizmów cache bazujących na pamięci (Memcache, APC), keszów stałych (pliki, baza danych), oraz pozwala na używanie wygodnego i potężnego mechanizmu tagowania w połączeniu backendami pamięciowymi które natywnie nie mają wsparcia dla tagów.

Poniżej znajduje się przykładowy plik INI konfigurujący TwoLevels dla mechanizmów File i Memcache:

[global]
;; -------------------- CACHE (two level) ------------------
cache.frontend = Core
cache.backend = Two Levels
cache.frontendOptions.automatic_serialization = true

cache.backendOptions.stats_update_factor = 10
cache.backendOptions.auto_refresh_fast_cache = true

cache.backendOptions.slow_backend = File
cache.backendOptions.slow_backend_options.cache_dir = ../temp
cache.backendOptions.slow_backend_custom_naming = false
cache.backendOptions.slow_backend_autoload = false

cache.backendOptions.fast_backend = Memcached
cache.backendOptions.fast_backend_options.servers.1.host = 10.0.0.1
cache.backendOptions.fast_backend_options.servers.1.port = 11211
cache.backendOptions.fast_backend_options.servers.1.persistent = true
cache.backendOptions.fast_backend_options.servers.2.host = 10.0.0.2
cache.backendOptions.fast_backend_options.servers.2.port = 11211
cache.backendOptions.fast_backend_options.servers.2.persistent = true
cache.backendOptions.fast_backend_custom_naming = false
cache.backendOptions.fast_backend_autoload = false

Przy okazji widać też sposób konfiguracji wielu serwerów Memcache, z czyn niektórzy mają problemy.

I w PHP:

$config = new Zend_Config_Ini ( '../configs/global.ini', 'global' );
Zend_Registry::set ( 'config', $config );

$cache = Zend_Cache::factory (
    $config->cache->frontend,
    $config->cache->backend,
    $config->cache->frontendOptions->toArray(),
    $config->cache->backendOptions->toArray()
);

Zend_Registry::set ( 'cache', $cache );

A teraz sposób użycia w przykładowym modelu, przy okazji z użyciem innej nowości 1.7 (notabene, mojej propozycji ;)):

/**
 * Rekord tabeli maternity_models_Maternity
 *
 * @category   App
 * @package    App_Maternity
 * @subpackage Models
 */

class maternity_models_Maternity_Row extends Mao_Db_Table_Row
{

    /**
     * Przechowuje koszt odbytych wizyt
     *
     * @var integer
     */
    private $_visitsCost = false;

    /**
     * Zwraca koszt odbytych wizyt
     *
     * @return integer
     */
    public function getVisitsCost()
    {

        if ( $this->_visitCost != false ) {
            return $this->_visitCost;
        }      

        /* @var $cache Zend_Cache_Core */
        $cache = Zend_Registry::get( 'cache' );
        $cache_id = 'maternity_models_Maternity_Row_visitsCost_' . $this->_data['maternity_id'];

        if(  ! $this->_visitsCost = $cache->load( $cache_id ) )
        {
            $visits = $this->getVisits();
            $ret = 0;

            foreach( $visits as $row )
            {
                $ret = $ret + $row->visit_cost;
            }
            $this->_visitsCost = $ret;

            $cache->save( $this->_visitsCost, $cache_id,
                array(
                    'maternity',
                    'maternity_models_Maternity' ,
                    'maternity_models_Maternity_Row_' . $this->_data['maternity_id']
                ),
                604800
            );
        }
        return $this->_visitsCost;
    }

    /**
     * Allows post-update logic to be applied to row.
     * Subclasses may override this method.
     *
     * @return void
     */
    protected function _postUpdate()
    {
        // Czyścimy cache updatowanego rekordu
        /* @var $cache Zend_Cache_Core */
        $cache = Zend_Registry::get( 'cache' );

        if ( isset( $this->_data['maternity_id'] ) ) {
            $cache->clean(
                Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG,
                'maternity_models_Maternity_Row_' . $this->_data['maternity_id']
            );
        }
        return parent::_postUpdate();
    }

}

W powyższym przykładzie tryb Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG usuwa z cache wszystkie rekordy zawierające podany tag.

Przy okazji wpadł mi jeszcze jeden pomysł na kolejny “tryb” czyszczenia - czyszczący rekordy zawierające wszystkie podane tagi, ale nad tym pomyślę już później.

Related posts

Autor wpisu: widmogrod, dodany: 12.11.2008 22:09, tagi: zend_framework, php

Zend Framework umożliwia specjalizację finalnego widoku(layoutu) dla każdej z akcji poprzez tzw. helpery("pomocniki") widoku. Jak to się dzieje odsyłam do podręcznika.Wszystko działało idealnie do dnia gdy nadeszła chwila integracji stronki z Google Maps API.W widoku akcji korzystam z wymiotnego w temacie pomocnika:$this->headScript()->appendFile('http://maps.google.com/maps?file=api&v=2&key='.$this->apiKey);nagłówek strony produkuje mi coś takiego:<script src="http://maps.google.com/maps?file=api&amp;amp;v=2&amp;amp;key=ABQIAAAAnCqO9l1WMOgTCJlg9kVlMRREqxHjot-MVdGv4W7rNtdAWxNh4hS2-gRBnLrWFzhAC8SpBzYmGVYZgA" type="text/javascript"/>a powinien<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAnCqO9l1WMOgTCJlg9kVlMRREqxHjot-MVdGv4W7rNtdAWxNh4hS2-gRBnLrWFzhAC8SpBzYmGVYZgA" type="text/javascript"></script>jak łatwo zauważyć problem leży w &amp; -> &.Inicjowanie map googla tej zmiany nie lubi. Problem tkwi w funkcji htmlspecialchars, użytej w Zend_View_Helper_HeadScript::append() itd.Żeby nie ingerować w kod w/w klasy można zastosować funkcję htmlspecialchars_decode w szablonie w następujący sposób...// &amp; -> & becouse gmaps crash!print htmlspecialchars_decode($this->headScript());.. i wszystko działa, tak jak powinno od samego początku.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: widmogrod, dodany: 19.09.2008 15:26, tagi: zend_framework, php

Wykorzystując Zend_View_Helper_Action w layout-cie (jako aplet w layout)$this->action('list','index','calendar', array('rowCount' => 5));dostałem wyjątek
Zend_Controller_Router_Exception: module is not specified in ..
O co chodzi?Na początku anializy myślałem że jest błąd w tym helperze i dispachowaniu akcji ale naszczęście się myliłem. Rozwiązanie problemu okazało się dużo bardziej trywialne jak i zaskakujące!Wykorzystując pomocnik widoku Zend_View_Helper_Url w pliku widoku dla wywoływanej akcji (czyli list.phtml) nie można korzystać z "skróconej" wersji generowani url!tj. zamiast$this->url(array('action' => 'display','id' => $row->id),'frontend')należy stosować pełny zapis$this->url(array('module' => 'calendar','controller' => 'index','action' => 'display','id' => $row->id),'frontend')EDIT:

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: WojciechNaruniec, dodany: 22.07.2008 23:59, tagi: zend_framework

Dziś w serwisie Zend Developer Zone ukazała się informacja, że dostępny jest już Zend Framework 1.6 RC1. Oto lista głównych zmian i nowości.

Autor wpisu: WojciechNaruniec, dodany: 01.06.2008 17:32, tagi: zend_framework

Ostatnio instalowałem aplikację opartą o Zend Framework na serwerze używającym oprogramowania IdeaWebServer i okazało się, że nie działają przekierowania: każda próba przekierowania za pomocą klasy Zend_Controller_Action_Helper_Redirector kończyła się błędem Internal Server Error 500. W pierwszej chwili pomysłałem że to wina serwera, ale błąd okazał się mieć źródło w samym ZF.

Autor wpisu: widmogrod, dodany: 30.05.2008 09:23, tagi: zend_framework, jquery

Form generator demoWykorzystane biblioteki: Zend_Form od Zend Framework i jQueryv0.3 - pierwsze publiczne wydanie (prezentacja)Jest to nowy projekt, który wykonuję w ramach zlecenia.Podstawową cechą tej aplikacji ma być (i mam nadzieje że jest ;)) intuicyjna możliwości tworzenia ankiet/formularzy, oczywiście bez wymaganej znajomości HTML przez użytkownika. Tak stworzony formularz ma być oddany w ręce potencjalnego klienta w celu wypełnienia i wysłania go na zdefiniowany adres e-mail.Po raz kolejny w wykonaniu projektu posłużyłem się biblioteką jQuery. Pierwszą opublikowaną na tym blogu aplikacją, w której również została użyta w/w biblioteka jest jQuery ankieter.Generowaniem formularzy zajmuje się świetny komponent od zend'a Zend_Form.Kolejnym zastosowaniem tego skryptu, które nota bene wynika z jego charakteru jest przyśpieszenie tworzenia projektu z ZF.
Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.