Alle Beiträge von Christian Sonntag

Ubuntu 14.10 auf Mac mini late 2012

Dies ist ein kurzer Erfahrungsbericht zu Ubuntu 14.10 auf einem Mac mini late 2012 mit einem 2,5 GHz i5 Prozessor, 8 GB Speicher und einer 128 GB SSD.

Gleich vorweg muss ich betonen dass die Installation super einfach und unkompliziert war. Ein externes optisches USB Laufwerk wird hierfür benötigt. Ubuntu Live CD/DVD einlegen, beim starten die C Taste drücken und schon kann die Installation losgehen.

Die komplette Hardware wird ohne murren erkannt. Wlan und Bluetooth funktionierten auf Anhieb. Auch das Keyboardlayout ist bei einer Apple Mini Tastatur größtenteils richtig, die Mediatasten sind richtig belegt.

Die zweite HDD die über ein Dual Harddrive Kit verbaut ist ging nicht automatisch in den Ruhezustand um Strom zu sparen. Dies war aber nur ein kleineres Problem. Hierfür sind ein paar manuelle Anpassungen übers Terminal nötig. Den entsprechenden Link dazu habe ich leider nicht mehr parat. Aber im Internet findet man genügend Infos dazu.

Ubuntu 14.10 auf Mac mini late 2012

Abschließend muss ich mich leider wiederholen ;-) Die installation ist einfach, die komplette Hardware wurde erkannt. Ubuntu auf dem Mac mini läuft flott und stabil!

ZF2: Custom ZfcTwig Extension unter Zend 2

Notizen zu einer exemplarischen Twig Extension unter ZF2 &ZfcTwig:

Klasse anlegen z.B. unter Application/src/Application/View/CustomTwigExtension.php

<?php

// http://stackoverflow.com/questions/28254666/twig-add-filter

namespace Application\View;

use Twig_Extension;
use Twig_SimpleFilter;
use Twig_SimpleFunction;

class CustomTwigExtension extends Twig_Extension
{
    public function getFilters() {
        return [new Twig_SimpleFilter('ucfirst', 'ucfirst') ];
    }
    public function getName() {
        return "CustomTwigExtension";
    }
    public function getFunctions() {
        return [new Twig_SimpleFunction('renderimg', function ($picture, $width = 100, $height = 100) {
            $filename = basename($picture);
            
            return '<img src="' . $filename . '" width="' . $width . '" height="' . $height . '" />';
        }
        , array(
            'is_safe' => array(
                'html'
            )
        )) ];
    }
}

Custom Extension in config/autoload/global.php registieren:

<?php
/**
 * Global Configuration Override
 *
 * You can use this file for overriding configuration values from modules, etc.
 * You would place values in here that are agnostic to the environment and not
 * sensitive to security.
 *
 * @NOTE: In practice, this file will typically be INCLUDED in your source
 * control, so do not include passwords or other sensitive information in this
 * file.
 */

return array(
	'zfctwig' => [
	      'extensions' => [
	            'Twig_Extension_Debug',

	            // Custom Twig Extension registrieren
	            \Application\View\CustomTwigExtension::class,
	      ],
	      'environment_options' => array(
	            'debug'         => false
	      )
	],
);

Verwendung im Twig Template

{{ renderimg('test.jpg', 100, 100) }}

 

 

ZF2: Custom View Helper in Zend Framework 2 mit ZfcTwig

Notizen zum erstellen eines Custom View Helpers in Zend 2.

View Helper PHP Datei z.B. unter ../Application/src/Application/View/Helper/TestHelper.php anlegen:

<?php
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
 
class TestHelper extends AbstractHelper
{
    public function __invoke($str, $find)
    {
        if (! is_string($str)){
            return '<!--must be string-->';
        }
 
        if (strpos($str, $find) === false){
            return '<!--not found-->';
        }
 
        return '<!--found-->';
    }
}

Diesen Helper dann im Config-Array im Modul registrieren unter ../module/Application/config/module.config.php. Dieses entweder erweitern/ergänzen bzw. erstellen.

<?php
return array(

    //...
    //...

    'view_helpers' => array(
        'invokables' => array(
            'foo' => 'Application\View\Helper\TestHelper'
        ),
    ),

    //...
    //...

);

Im Twig Template mit installiertem ZfcTwig kann dieser dann wie folgt aufgerufen werden.

{{ foo('meee', 'e') }}

Beziehungsweise innerhalb des Standardtemplate mit:

<?php echo $this->foo('meee', 'e'); ?>

 

ZF2: Twig Templateengine installieren und aktivieren

Notizen zur Installation von Twig unter Zend 2.

Composer Beispielkonfiguration:

{
    "name": "zendframework/skeleton-application",
    "description": "Skeleton Application for ZF2",
    "license": "BSD-3-Clause",
    "keywords": [
        "framework",
        "zf2"
    ],
    "homepage": "http://framework.zend.com/",
    "require": {
        "php": ">=5.3.3",
        "zendframework/zendframework": "2.3.*",
        "zendframework/zftool": "dev-master",
        "zf-commons/zfc-twig": "dev-master",
        "zendframework/zend-modulemanager": "2.3.*@dev"
    }
}

Mit Composer  installieren:

composer require zf-commons/zfc-twig:dev-master

Twig Modul in application.config.php aktivieren:

<?php
/**
 * Configuration file generated by ZFTool
 * The previous configuration file is stored in application.config.old
 *
 * @see https://github.com/zendframework/ZFTool
 */
return array(
    'modules' => array(
        'Application',
		'ZfcTwig'
    ),
    'module_listener_options' => array(
        'module_paths' => array(
            './module',
            './vendor'
        ),
        'config_glob_paths' => array(
            'config/autoload/{,*.}{global,local}.php'
        )
    )
);

Die Twig Example Templates ersetzen dann die Templates der ZF2 Skeleton Application.

Zu finden sind diese unter:

vendor/zf-commons/zfc-twig/examples

und ersetzen die Templates in diesem Ordner:

module/Application/view

 

ZF2: Zend Form in Twig Templates ausgeben

Einige Notizen zur Umsetzung einer Zend Form mit Ausgabe in einem Twig Template.

Form Klasse:

<?php

namespace Application\Form;

use Zend\Captcha;
use Zend\Form\Element;
use Zend\Form\Form;

class ContactForm extends Form
{
    public function __construct($name = null)
    {
        parent::__construct('contact');

        $this->setAttribute('method', 'post');
        $this->setAttribute('class', 'zf2');


        $this->add(array(
            'name' => 'name',
            'type' => 'Zend\Form\Element\Text',
            'attributes' => array(
                'required' => 'required',
            ),
            'options' => array(
                'label' => 'Name',
                'label_attributes' => array(
                    'class' => 'required',
                ),
            ),
        ));

        $this->add(array(
            'name' => 'email',
            'type' => 'Zend\Form\Element\Email',
            'attributes' => array(
                'required' => 'required',
            ),
            'options' => array(
                'label' => 'Email',
                'label_attributes' => array(
                    'class' => 'required',
                ),
            ),
        ));

        $this->add(array(
            'name' => 'comment',
            'type' => 'Zend\Form\Element\Textarea',
            'attributes' => array(
                'required' => 'required',
            ),
            'options' => array(
                'label' => 'Kommentar',
                'label_attributes' => array(
                    'class' => 'required',
                ),
            ),
        ));

        $this->add(array(
            'name' => 'submit',
            'type' => 'Submit',
            'attributes' => array(
                'class' => 'gradient-button',
                'value' => 'Abschicken',
                'id' => 'submit',
            ),
        ));


        $this->add(array(
            'name' => 'csrf',
            'type' => 'Zend\Form\Element\Csrf',
            'options' => array(
                'csrf_options' => array(
                    'timeout' => 600
                )
            )
        ));
    }
}

Form Validieren:

<?php
namespace Application\Model\Form;

use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;

class Contact implements InputFilterAwareInterface
{
    protected $inputFilter;

    public function setInputFilter(InputFilterInterface $inputFilter)
    {
        throw new \Exception("Not used");
    }

    public function getInputFilter()
    {
        if (!$this->inputFilter)
        {
            $inputFilter = new InputFilter();
            $factory = new InputFactory();


            $inputFilter->add($factory->createInput([
                'name' => 'name',
                'required' => true,
                'filters' => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim'),
                ),
                'validators' => array(
                    array (
                        'name' => 'NotEmpty',
                        'options' => array(
                            'messages' => array(
                                'isEmpty' => 'Bitte geben Sie Ihren Namen ein.',
                            )
                        ),
                        'break_chain_on_failure' => true,
                    ),
                ),
            ]));

            $inputFilter->add($factory->createInput([
                'name' => 'email',
                'filters' => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim'),
                ),
                'validators' => array(
                    array (
                        'name' => 'Regex',
                        'options' => array (
                            'pattern' => '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/',
                            'message' => array (
                                'regexNotMatch' => 'Bitte geben Sie eine gültige E-Mailadresse ein.',
                            )
                        ),
                        'break_chain_on_failure' => true,
                    ),
                    array (
                        'name' => 'EmailAddress',
                        'options' => array(
                            'messages' => array(
                                'emailAddressInvalidFormat' => 'Bitte geben Sie eine gültige E-Mailadresse ein.',
                            )
                        ),
                        'break_chain_on_failure' => true,
                    ),
                    array (
                        'name' => 'NotEmpty',
                        'options' => array(
                            'messages' => array(
                                'isEmpty' => 'Bitte geben Sie eine E-Mailadresse ein.',
                            )
                        ),
                        'break_chain_on_failure' => true,
                    ),
                ),
            ]));

            $inputFilter->add($factory->createInput([
                'name' => 'comment',
                'required' => true,
                'filters' => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim'),
                ),
                'validators' => array(
                    array (
                        'name' => 'NotEmpty',
                        'options' => array(
                            'messages' => array(
                                'isEmpty' => 'Bitte geben Sie einen Kommentar ein.',
                            )
                        ),
                        'break_chain_on_failure' => true,
                    ),
                ),
            ]));

            $this->inputFilter = $inputFilter;
        }

        return $this->inputFilter;
    }
}

From in Controller an View übergeben:

        $formValidator = new Contact();
        $form = new ContactForm();
        $form->setInputFilter($formValidator->getInputFilter());
        $form->setAttribute('action', $this->url()->fromRoute('kontakt'));


        $view->setVariables(
            array(
                'form' => $form,
            )
        );

Form in Controller verarbeiten:

        $request = $this->getRequest();

        if ($request->isPost()) {

                $form->setData($request->getPost());


            if ($form->isValid()) {
                {

                    $view->setVariables(
                        array(
                            'formValid' => TRUE,
                            'formData' => $form->getData()
                        )
                    );

                    // send mail
                    $this->sendMail($form->getData());

                    return $view;
                }
            }
        }

Form in Twig Template ausgeben.

        {{ form().prepare() }}
        {{ form().openTag(form)|raw }}
        {{ formRow().setInputErrorClass('error').render(form.get('name'))|raw }}
        {{ formRow().setInputErrorClass('error').render(form.get('email'))|raw }}
        {{ formRow().setInputErrorClass('error').render(form.get('comment'))|raw }}
        {{ formRow(form.get('submit'))|raw }}
        {{ formRow(form.get('csrf'))|raw }}
        {{ form().closeTag(form)|raw }}

 

TYPO3: BodyTag mit CSS Klassen für Page Id und Page Template

Folgend ein kleiner TypoScript Snippet um den BodyTag mit zusätzlichen Klassen zu rendern.

Eine ist mehr informativ und gibt die Page ID aus z.B. „pid-123“. Die andere gibt das aktuell ausgewählte bzw. „vererbte“ Seitentemplate von fluidpages aus und kann für Stylingzwecke gut gebraucht werden.

Der TypoScript Kenner kann dies leicht z.B. für FLUIDTEMPLATE umschreiben.

page {
    bodyTag >
    bodyTagCObject = COA
    bodyTagCObject {
        10 = TEXT
        10 {
            data = page:uid
            stdWrap.noTrimWrap = |pid-| |
        }

        20 = TEXT
        20 {
            if.isTrue.data = page:tx_fed_page_controller_action
            data = page:tx_fed_page_controller_action
            split {
                token = >
                returnKey = 1
            }
            case = lower
        }
        20.wrap = tmpl-|

        30 = TEXT
        30 {
            if.isFalse.data = page:tx_fed_page_controller_action
            data = levelfield:-2, tx_fed_page_controller_action, slide
            split {
                token = >
                returnKey = 1
            }
            case = lower
        }
        30.wrap = tmpl-|
    }
    bodyTagCObject {
        wrap = <body class="|">
    }
}

 

TYPO3: Fluid Powered TYPO3 – Custom Flux Controller

FluidTYPO3 alleine ist schon eine geniale Lösung. Damit ist es ein leichtes Seitentemplates und Contentelemente anzulegen.

Im Hintergrund arbeitet Flux und übergibt automatisch die wichtigsten Daten für das Frontendrendering.

Bei Seiten sind dies alle benötigten Daten zu Seiteneigenschaften, bei Contentelementen alle benötigten Daten aus den gepflegten Feldern der Flexform des Contentelements und noch einiges mehr.

Für den Fall dass dies nicht ausreichen sollte gibt es die Möglichkeit in der Providerextension einen „Custom Flux Controller“ anzulegen.

In diesem ist es möglich zusätzliche Daten an die View zu übergeben, die nicht durch Flux geliefert werden.

Wie dies genutzt werden kann will ich folgend kurz beschreiben.

Zunächst müssen im Ordner „Classes/Controller“ zwei Controller Dateien angelegt werden:

  • ContentController.php
  • PageController.php

Beispielcode zum ContentController:

<?php
namespace Yourvendorname\Yourextensionkey\Controller;

use FluidTYPO3\Flux\Controller\AbstractFluxController;

/**
 * Additional ContentController
 *
 * As default Flux generates internally a ContentController an assigns most common objects to the view.
 * If a custom ContentController with a known action is found. Flux will execute the action additionally (performSubRendering).
 *
 * @package Yourextensionkey
 * @subpackage Controller
 */
class ContentController extends AbstractFluxController
{


//    public function fooAction()
//    {
//        $this->view->assign('foo', 'bar');
//    }

}

Beispielcode zum PageController:

<?php
namespace Yourvendorname\Yourextensionkey\Controller;

use FluidTYPO3\Fluidpages\Controller\AbstractPageController;

/**
 * Additional PageController
 *
 * As default Flux generates internally a PageController an assigns most common objects to the view.
 * If a custom PageController with a known action is found. Flux will execute the action additionally (performSubRendering).
 *
 * @package Yourextensionkey
 * @subpackage Controller
 */
class PageController extends AbstractPageController {

//    public function fooAction()
//    {
//        $this->view->assign('foo', 'bar');
//    }

}

Dies allein sollte schon ausreichen um einen Custom Flux Controller für Page und Content anzulegen.

Für den Fall dass dies nicht ausreichen sollte muss wie hier beschrieben im Ordner „Migrations/Code“ die Datei ClassAliasMap.php angelegt werden.

<?php

return array(
	'Tx_Yourextensionkey_Controller_ContentController' => 'Yourvendorname\\Yourextensionkey\\Controller\\ContentController',
	'Tx_Yourextensionkey_Controller_PageController' => 'Yourvendorname\\Yourextensionkey\\Controller\\PageController',
);

 

Fluid Powered TYPO3 auf Github.

TYPO3: Fluid Powered TYPO3

Ich möchte hier kurz Fluid Powered TYPO3 vorstellen. Dieses war mir schön länger bekannt, nur leider habe ich die Genialität dahinter nicht verstanden. Mit dem Gedanken „wer braucht den bitte Flux“ habe ich dieses Thema immer schnell abgehakt.

FluidTYPO3 besteht aus einer Kombination diverser Extensions für TYPO3 CMS. flux, fluidcontent, fluidcontent_core, fluidpages und vhs bilden zusammen ein sehr geniales gespannt.

Diese müssen natürlich nicht allesamt genutzt werden. flux und fluidcontent alleine reichen schon aus um schnell flexible Contentelemente anzulegen. fluidpages weitet das ganze auf Seitentemplateebene aus. fluidcontent_core ersetzt css_styled_content. vhs selbst ist eine Sammlung von oft benötigten ViewHelpern.

Wie auf der Homepage von FluidTYPO3 zu lesen ist steht „convention-over-configuration“ im Vordergrund. Und das ist auch sehr genial umgesetzt.

Doch wie findet man einen einfachen Einstieg um dies zu nutzen? Fast ein wenig versteckt ist in der sehr umfangreichen Dokumentation die Extension „builder“ erwähnt. Ich persönlich hätte den builder mehr in einem QuickStart Tutorial hervor gehoben.

fluidtypo3-builder

Mit dieser ist es möglich wie zu den alten Extension Kickstarter Zeiten eine FluidTYPO3 „provider extension“ zu erstellen. Dies ist über ein Backend Modul möglich oder man nutzt dazu den CLI Dispatcher auf der Kommandozeile. Deren Grundgerüst sieht dann wie folgt aus:

provider-extension

Dies ist auf den ersten Blick eine ganz normale Extbase Ordnerstruktur, in der Datei ext_tables.php wird diese Extension als „Provider Extension“ bei Flux registriert und die Magie beginnt.

Als Beispiel sind über den Builder dort schon zwei Templates angelegt worden, diese sind zum einen ein Seiten-Template und zum anderen ein Contentelement-Template. Jedes weitere Template das im Ordner „Page“ oder „Content“ angelegt wird, wird automatisch im TYPO3 Backend als Seitentemplate oder als Contentelement zur Verfügung gestellt.

Hinzu kommt dass in diesen Template Dateien die komplette Konfiguration enthalten ist. Configuration (BE Eingabe), Preview (BE) und Main (FE rendering) sind dort zentral in einer Datei enthalten. Und das alles ohne eine einzige Zeile TypoScript!

Beispiel Konfigurationsdatei für ein Seitentemplate:

<div xmlns="http://www.w3.org/1999/xhtml" lang="en"
	xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers"
	f:schemaLocation="https://fluidtypo3.org/schemas/fluid-master.xsd"
	xmlns:flux="http://typo3.org/ns/FluidTYPO3/Flux/ViewHelpers"
	flux:schemaLocation="https://fluidtypo3.org/schemas/flux-master.xsd"
	xmlns:v="http://typo3.org/ns/FluidTYPO3/Vhs/ViewHelpers"
	v:schemaLocation="https://fluidtypo3.org/schemas/vhs-master.xsd">
	<f:layout name="Page" />

	<f:section name="Configuration">
		<flux:form id="fluidpage" options="{icon: 'Icons/Page/Standard.gif'}">
			<!-- Insert fields, sheets, grid, form section objects etc. here, in this flux:form tag -->
		</flux:form>
		<flux:grid>
			<!-- Edit this grid to change the "backend layout" structure -->
			<flux:grid.row>
				<flux:grid.column colPos="0" colspan="3" name="main" />
				<flux:grid.column colPos="1" name="right" />
			</flux:grid.row>
		</flux:grid>
	</f:section>

	<f:section name="Main">
		<h1>I am a page template!</h1>
		<p>
			My template file is EXT:myprovider/Resources/Private/Page/Standard.html.
		</p>
		<div style="float: left; width: 75%;">
			<h2>Content main</h2>
			<v:content.render column="0" />
		</div>
		<div style="float: left; width: 25%;">
			<h2>Content right</h2>
			<v:content.render column="1" />
		</div>
	</f:section>
</div>

Beispiel einer Konfigurationsdatei für ein Contentelement:

<div xmlns="http://www.w3.org/1999/xhtml" lang="en"
	xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers"
	f:schemaLocation="https://fluidtypo3.org/schemas/fluid-master.xsd"
	xmlns:flux="http://typo3.org/ns/FluidTYPO3/Flux/ViewHelpers"
	flux:schemaLocation="https://fluidtypo3.org/schemas/flux-master.xsd">
	<f:layout name="Content" />

	<f:section name="Configuration">
		<flux:form id="fluidcontent" options="{icon: 'Icons/Content/Example.gif', group: 'FCE'}">
			<!-- Insert fields, sheets, grid, form section objects etc. here, in this flux:flexform tag -->
		</flux:form>
	</f:section>

	<f:section name="Preview">
		<!-- uncomment this to use a grid for nested content elements -->
		<!-- <flux:widget.grid /> -->
	</f:section>

	<f:section name="Main">
		<h3>I am a content element!</h3>
		<p>
			My template file is EXT:myprovider/Resources/Private/Content/Example.html.
		</p>
	</f:section>
</div>

Im Hintergrund kümmert sich flux um alles und übergibt automatisch an die Templates (Views) alle benötigten Objekte für das Rendering im Frontend.

Wie schon erwähnt ein in meinen Augen ziemlich geniales Gespann mit dem man einfach, schnell und flexibel Seitentemplates und Contentelemente (FCE’s) anlegen kann.

Fluid Powered TYPO3 auf Github

OS X: gimli unter Mavericks installieren – markdown2pdf

Nach längerem Suchen nach einer Lösung um Markdown Files nach PDF zu konvertieren bin ich auf Gimli gestoßen. Unter Ubuntu war dies leicht zu installieren und man konnte schnell Ergebnisse damit erzielen.

Unter OS X Mavericks 10.10 war dies nicht ohne weiteres möglich. Beim Aufruf von „gem install gimli“ kam es immer zu einer Fehlermeldung. Die erste Suche führte in die falsche Richtung und Grund waren immer die fehlenden Xcode Commandline Tools aufgeführt mit fehlendem gcc Compiler.

Bei mir hat ein Update auf den aktuellen Ruby Version Manager sowie eine aktuelle Ruby Version Abhilfe geschaffen.

# update rum und ruby
\curl -L https://get.rvm.io | bash -s stable --ruby

# Versionen nach update
localhost:markdown csg$ rvm -v
rvm 1.26.4 (latest) by Wayne E. Seguin <wayneeseguin@gmail.com>, Michal Papis <mpapis@gmail.com> [https://rvm.io/]
localhost:markdown csg$ ruby -v
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]

# gimli installieren
gem install gimli

gimli ist erfolgreich installiert. Nun ist es ein leichtes aus mehreren Markdown Dateien automatisiert ein PDF erstellen zu lassen.

# Beispiel
gimli -merge -outputfilename "documentation" -w '--toc --footer-center "[page]/[toPage]"'

 

Games: Riamond Rush

Nach einer kleinen anfänglichen JavaScript Spielerei hat es Riamond Rush nun endlich in den ersten Store geschafft. Google play macht den Anfang und auch der Einzug in den iTunes App Store ist schon in Planung. Dank Ludei ist es ein leichtes sein HTML5 Spiel/App auf verschiedene Plattformen zu „portieren“.

Wer kein Smartphone besitzt kann Riamond Rush auch im Browser (bevorzugt Chrome ;-) am Rechner spielen.

Je nach Endgerät unterscheidet sich etwas die Steuerung. Im Browser wird Riamond mit den Cursortasten gesteuert, mit D kann man Ihn zum graben bewegen falls es das Level erlaubt. Falls man sich in einem Level in eine ausweglose Situation gebracht hat wird dieses mit R neu gestartet.

Auf Smartphones/Tablets gehorcht Riamond dem Finger auf dem Touchdisplay. Gegraben wird mit dem Button unten rechts, Levelneustart mit Button oben rechts.

Viel Spaß beim spielen!