neueste Beiträge http://www.espend.de/feed.xml de YouTube Data API (v3) Device Authentifikation in Python http://www.espend.de/artikel/youtube-data-api-v3-device-authentifikation-python.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="/sites/default/files/youtube_data_api_v3_device_authentification.png" class="lightbox colorbox-inline" rel="lightbox" title=" youtube_data_api_v3_device_authentification"><img class="right" src="/sites/default/files/resize/youtube_data_api_v3_device_authentification-180x164.png" width="180" alt=" youtube_data_api_v3_device_authentification" title=" youtube_data_api_v3_device_authentification" height="164" /></a>War es der YouTube API v2 noch möglich mittels <a href="https://developers.google.com/youtube/v3/guides/moving_to_oauth">ClientLogin Verfahren</a> einen User Access-Token mit Name und Password zu erhalten, geht dieses in OAuth 2.0 nicht mehr. Jede Benutzeranmeldung muss zwingend in irgendeiner Form per Browser stattfinden z.B. über einen Redirect-Callback. Die Implementierung von <a href="/artikel/mytube-youtube-auf-der-dreambox-mit-enigma2.html">MyTube: Youtube auf der Dreambox mit Enigma2</a> funktioniert somit nach der Abschaltung der alten API nicht mehr. Youtube bietet für Geräte ab API v3, also wo kein Browser bereitsteht, den sogenannte <a href="https://developers.google.com/youtube/2.0/developers_guide_protocol_oauth2#OAuth2_Devices_Flow">OAuth2 Devices Flow</a> an. Es wird einfach ein Gerät mit einer simple Code Eingabe mit einem Benutzer verknüpft.</p> <h2>Code: Authentifikation in Python</h2> <p>Hier wird ein Device Code erzeugt. Als YouTube Account Daten muss man sich einen "Installed Applikation - Client-ID für native Anwendung" Code erzeugen bzw. exportieren aus der <a href="https://console.developers.google.com/">Google Developer Console</a>. Alternative gibt hier noch ein <a href="https://elliotnoma.wordpress.com/2015/03/11/python-code-to-summarize-data-collected-in-the-google-fit-data-store/">Beispiel für curl</a>.</p> <p><div class="geshifilter"><pre class="python geshifilter-python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> httplib2 <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span> <span style="color: #ff7700;font-weight:bold;">from</span> apiclient <span style="color: #ff7700;font-weight:bold;">import</span> discovery <span style="color: #ff7700;font-weight:bold;">from</span> oauth2client <span style="color: #ff7700;font-weight:bold;">import</span> client <span style="color: #ff7700;font-weight:bold;">import</span> json &nbsp; <span style="color: #ff7700;font-weight:bold;">import</span> httplib2 <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">time</span> &nbsp; YOUTUBE_API_CLIENT_DEVICE_URL <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;https://accounts.google.com/o/oauth2/device/code&quot;</span> YOUTUBE_API_CLIENT_DEVICE_TOKEN <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;https://accounts.google.com/o/oauth2/device/code&quot;</span> &nbsp; YOUTUBE_API_CLIENT_ID <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;xxxx.apps.googleusercontent.com&quot;</span> YOUTUBE_API_CLIENT_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;xxxxx&quot;</span> YOUTUBE_API_SCOPE <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;https://www.googleapis.com/auth/youtube&quot;</span> &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> getUserCode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>: &nbsp; params <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span> <span style="color: #483d8b;">'client_id'</span>: YOUTUBE_API_CLIENT_ID<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'scope'</span>: YOUTUBE_API_SCOPE<span style="color: #66cc66;">,</span> <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span> &nbsp; response<span style="color: #66cc66;">,</span> content <span style="color: #66cc66;">=</span> httplib2.<span style="color: black;">Http</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">request</span><span style="color: black;">&#40;</span>YOUTUBE_API_CLIENT_DEVICE_URL<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'POST'</span><span style="color: #66cc66;">,</span> params<span style="color: #66cc66;">,</span> headers<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'Content-type'</span>: <span style="color: #483d8b;">'application/x-www-form-urlencoded'</span><span style="color: black;">&#125;</span> <span style="color: black;">&#41;</span> &nbsp; jsonResponse <span style="color: #66cc66;">=</span> json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>content<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;device_code&quot;</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> jsonResponse <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #483d8b;">&quot;user_code&quot;</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> jsonResponse: <span style="color: #ff7700;font-weight:bold;">return</span> Null &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> jsonResponse &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> getRefreshedToken<span style="color: black;">&#40;</span><span style="color: #dc143c;">token</span><span style="color: black;">&#41;</span>: &nbsp; params <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span> <span style="color: #483d8b;">'client_id'</span>: YOUTUBE_API_CLIENT_ID<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'client_secret'</span>: YOUTUBE_API_CLIENT_SECRET<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'refresh_token'</span>: <span style="color: #dc143c;">token</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'grant_type'</span>: <span style="color: #483d8b;">'refresh_token'</span> <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span> &nbsp; response<span style="color: #66cc66;">,</span> content <span style="color: #66cc66;">=</span> httplib2.<span style="color: black;">Http</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">request</span><span style="color: black;">&#40;</span>YOUTUBE_API_CLIENT_DEVICE_TOKEN_REFRESH<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'POST'</span><span style="color: #66cc66;">,</span> params<span style="color: #66cc66;">,</span> headers<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'Content-type'</span>: <span style="color: #483d8b;">'application/x-www-form-urlencoded'</span><span style="color: black;">&#125;</span> <span style="color: black;">&#41;</span> &nbsp; jsonResponse <span style="color: #66cc66;">=</span> json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>content<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">print</span> jsonResponse &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;access_token&quot;</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> jsonResponse: <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span> &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> jsonResponse &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> getToken<span style="color: black;">&#40;</span><span style="color: #dc143c;">code</span><span style="color: black;">&#41;</span>: &nbsp; <span style="color: #808080; font-style: italic;">#credentials_from_code</span> url <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'https://accounts.google.com/o/oauth2/token'</span> &nbsp; params <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span> <span style="color: #483d8b;">'client_id'</span>: YOUTUBE_API_CLIENT_ID<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'client_secret'</span>: YOUTUBE_API_CLIENT_SECRET<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'code'</span>: <span style="color: #dc143c;">code</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'grant_type'</span>: <span style="color: #483d8b;">'http://oauth.net/grant_type/device/1.0'</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span> &nbsp; response<span style="color: #66cc66;">,</span> content <span style="color: #66cc66;">=</span> httplib2.<span style="color: black;">Http</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">request</span><span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'POST'</span><span style="color: #66cc66;">,</span> params<span style="color: #66cc66;">,</span> headers<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'Content-type'</span>: <span style="color: #483d8b;">'application/x-www-form-urlencoded'</span><span style="color: black;">&#125;</span> <span style="color: black;">&#41;</span> &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>content<span style="color: black;">&#41;</span> &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> getCredentials<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>: &nbsp; <span style="color: #808080; font-style: italic;"># last access token</span> access_token <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;foo&quot;</span> refresh_token <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;foo&quot;</span> &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> OAuth2Credentials<span style="color: black;">&#40;</span> access_token<span style="color: #66cc66;">=</span>access_token<span style="color: #66cc66;">,</span> client_id<span style="color: #66cc66;">=</span>YOUTUBE_API_CLIENT_ID<span style="color: #66cc66;">,</span> client_secret<span style="color: #66cc66;">=</span>YOUTUBE_API_CLIENT_SECRET<span style="color: #66cc66;">,</span> refresh_token<span style="color: #66cc66;">=</span>refresh_token<span style="color: #66cc66;">,</span> token_expiry<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> token_uri<span style="color: #66cc66;">=</span>YOUTUBE_API_CLIENT_DEVICE_TOKEN_REFRESH<span style="color: #66cc66;">,</span> user_agent<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span> <span style="color: black;">&#41;</span> &nbsp; device <span style="color: #66cc66;">=</span> getUserCode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Got device request with '%s' and '%s'&quot;</span> % <span style="color: black;">&#40;</span>device<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;verification_url&quot;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> device<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;user_code&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> &nbsp; interval <span style="color: #66cc66;">=</span> device.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;interval&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span> &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">60</span> / <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>interval<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>: <span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span>interval<span style="color: black;">&#41;</span> <span style="color: #dc143c;">token</span> <span style="color: #66cc66;">=</span> getToken<span style="color: black;">&#40;</span>device<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;device_code&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;error&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">token</span>: <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Got request error '%s'&quot;</span> % <span style="color: #dc143c;">token</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;error&quot;</span><span style="color: black;">&#93;</span> &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;access_token&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">token</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #483d8b;">&quot;refresh_token&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">token</span>: <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #dc143c;">token</span> <span style="color: #ff7700;font-weight:bold;">break</span></pre></div></p> <h2>Status Abfragen</h2> <p><a href="/sites/default/files/youtube_data_api_v3_device_python.png" class="lightbox colorbox-inline" rel="lightbox" title="youtube_data_api_v3_device_python"><img class="right" src="/sites/default/files/resize/youtube_data_api_v3_device_python-150x59.png" width="150" alt="youtube_data_api_v3_device_python" title="youtube_data_api_v3_device_python" height="59" /></a> Ein "Device -> Benutzer Verknüpfung" Status muss kontinuierlich abgefragt werden bis der Benutzer den Code eingegeben hat. Solang hier nichts passiert ist wird ein <i>pending</i> Status zurückgegeben. Wenn der Benutzer den Vorgang im externen Browser durchgeführt hat, gibt es Tokens zum Weiterarbeiten.</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">root@device:/media/net# python foo.py Got device request with 'https://www.google.com/device' and 'BXJC-QTVP' Got request error 'authorization_pending' Got request error 'authorization_pending' Got request error 'authorization_pending' Got request error 'authorization_pending' Got request error 'authorization_pending' Got request error 'authorization_pending' Got request error 'authorization_pending' Got request error 'authorization_pending' Got request error 'authorization_pending' Got request error 'authorization_pending' {u'access_token': u'ya29.ZwFuC-ySd3ALraod7KcZzdnSqqKzldD7BGGQJneoG8Vhge-xxxx', u'token_type': u'Bearer', u'expires_in': 3600, u'refresh_token': u'1/_zQPkMfQrhonGssOhiOdxxx'}</pre></div></p> <h2>Meine Uploads</h2> <p><div class="geshifilter"><pre class="python geshifilter-python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> httplib2 &nbsp; <span style="color: #ff7700;font-weight:bold;">from</span> apiclient.<span style="color: black;">discovery</span> <span style="color: #ff7700;font-weight:bold;">import</span> build &nbsp; <span style="color: #808080; font-style: italic;"># This OAuth 2.0 access scope allows for read-only access to the authenticated</span> <span style="color: #808080; font-style: italic;"># user's account, but not other types of account access.</span> YOUTUBE_READONLY_SCOPE <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;https://www.googleapis.com/auth/youtube.readonly&quot;</span> YOUTUBE_API_SERVICE_NAME <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;youtube&quot;</span> YOUTUBE_API_VERSION <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;v3&quot;</span> &nbsp; youtube <span style="color: #66cc66;">=</span> build<span style="color: black;">&#40;</span>YOUTUBE_API_SERVICE_NAME<span style="color: #66cc66;">,</span> YOUTUBE_API_VERSION<span style="color: #66cc66;">,</span> http<span style="color: #66cc66;">=</span>getCredentials<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">authorize</span><span style="color: black;">&#40;</span>httplib2.<span style="color: black;">Http</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> &nbsp; <span style="color: #808080; font-style: italic;"># Retrieve the contentDetails part of the channel resource for the</span> <span style="color: #808080; font-style: italic;"># authenticated user's channel.</span> channels_response <span style="color: #66cc66;">=</span> youtube.<span style="color: black;">channels</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: #008000;">list</span><span style="color: black;">&#40;</span> mine<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: #66cc66;">,</span> part<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;contentDetails&quot;</span> <span style="color: black;">&#41;</span>.<span style="color: black;">execute</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> channels_response <span style="color: #66cc66;">&lt;</span>python<span style="color: #66cc66;">&gt;</span></pre></div></p> </div></div></div> Sat, 02 May 2015 08:40:21 +0000 Daniel Espendiller 323 at http://www.espend.de Interne Paketverwaltung mit Composer und Satis per Jenkins Skript http://www.espend.de/artikel/interne-paketverwaltung-mit-composer-und-satis-jenkins-skript.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>Über den <a href="https://getcomposer.org/">Composer</a> und der <a href="https://packagist.org/">Paketverwaltung Packagist</a> lassen sich bekanntlich externe PHP Libraries mit deren Abhängigkeiten in Projekten einbinden. Will man hier nicht öffentlichen Quelltext ausrollen, so muss eine interne Infrastruktur her. Mit <a href="https://getcomposer.org/doc/articles/handling-private-packages-with-satis.md#satis">Satis</a> kann man hier recht einfach private Repositories in seinen Entwicklungsprozess einbinden. Zwar kann man auch über einen Zweig <i>repositories</i> ein gleichen Effekt erreichen, dies ist aber recht langsam, da in jedem Branch nach möglichen <i>composer.json</i> Datei gesucht wird. Die Arbeit kann man besser Satis regelmäßig durchführen lassen.</p> <h2>Jenkins Job für Satis</h2> <p>Satis durchsucht sämtliche <i>repositories</i> und erzeugt einen entsprechende statische <i>.json</i> und paar HTML Ausgaben, welche dann auf einen Webserver hochgeladen werden müssen. Somit sind alle Pakete und Versionen zentral über eine Adresse erreichbar und nicht jeder Composer Client muss sich selber um deren Aufbau kümmern. Als Beispiel simples Jenkins:</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">#initial jenkins job #curl -sS https://getcomposer.org/installer | php #php composer.phar create-project composer/satis --stability=dev --keep-vcs &nbsp; statis=$(cat &lt;&lt;EOF { &quot;name&quot;: &quot;Satis&quot;, &quot;homepage&quot;: &quot;http://satis.example.org&quot;, &quot;repositories&quot;: [ { &quot;type&quot;: &quot;vcs&quot;, &quot;url&quot;: &quot;git@foo.de:user/bar.git&quot; }, { &quot;type&quot;: &quot;vcs&quot;, &quot;url&quot;: &quot;git@foo.de:user/bar2.git&quot; } ], &quot;require-all&quot;: true } EOF ) &nbsp; echo &quot;$statis&quot; &gt; satis.json &nbsp; php satis/bin/satis --skip-errors build satis.json build &nbsp; rsync --delete --chmod=ug=rwX -axv build/ user@myserver:/var/www/satis/htdocs/</pre></div></p> <h2>Branch-Alias</h2> <p>Normal wird der Version-String eines Paketes über den Branch-Namen erzeugt. So wird aus <i>master</i> <i>dev-master</i>. Mittels <i>branch-alias</i> können wir dieses aber per <i>composer.json</i> im <a href="https://getcomposer.org/doc/articles/aliases.md#branch-alias">Repository überschreiben</a>.</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">{ &quot;extra&quot;: { &quot;branch-alias&quot;: { &quot;dev-master&quot;: &quot;1.0.x-dev&quot; } } }</pre></div></p> <h2>Satis in composer.json einbinden</h2> <p>Am Ende noch eine Zeile mit der HTTP-Adresse in die <i>composer.json</i> und per <i>require</i> kann jetzt jedes interne Paket eingebunden werden.</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">{ &quot;repositories&quot;:[ { &quot;type&quot;:&quot;composer&quot;, &quot;url&quot;:&quot;http://satis.example.org/&quot; } ] }</pre></div></p> </div></div></div> Tue, 28 Apr 2015 12:19:51 +0000 Daniel Espendiller 322 at http://www.espend.de psr-0 ClassLoader in Shopware Plugin http://www.espend.de/artikel/psr-0-classloader-shopware-plugin.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="/sites/default/files/shopware_psr-0_plugin_0.png" class="lightbox colorbox-inline" rel="lightbox" title=" shopware psr-0 php"><img class="right" src="/sites/default/files/resize/shopware_psr-0_plugin_0-120x121.png" width="120" alt=" shopware psr-0 php" title=" shopware psr-0 php" height="121" /></a>Mit Einführung der Namespaces in PHP 5.3 und dem <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md">psr-0 Standards</a>, hat sich das gesamte Autoloading von PHP Klassen standardisiert (Eine Klasse pro Datei und Verzeichnisstruktur = Namepace). Auch wenn dies mittlerweile durch den <a href="http://www.php-fig.org/psr/psr-4/">psr-4 Standard</a> abgelöst worden ist, so hilft dieses doch immer noch bei der <strong>Entwicklung wiederverwendbarer Klassen</strong>.<br/>Auch PhpStorm unterstützt das ganze <a href="http://blog.jetbrains.com/phpstorm/2014/04/psr-0-psr-4-and-sourcetest-root-support-in-phpstorm-8-eap/">psr-x Thema</a>, so dass Klassen Templates automatisch erzeugt werden. Shopware bietet nur ein Standard ClassLoader ohne psr-0 Support an. Zwar kann man psr-0 recht einfach über einen <i>Spl-Autoloader</i> und ein <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md#example-implementation">paar Zeilen Code einbinden</a> einbinden, jedoch sollte man ein <i>require_once</i> nicht nutzen, sonst könnte es sein, dass ein eingereichtes Plugin nicht im Commmunity Store angenommen wird.</p> <p>Als alternative kann man jedoch den ClassLoader vom Doctrine Projekt einbinden <i>\Doctrine\Common\ClassLoader</i>, dieser Unterstützt psr-0 und ist in Shopware als <i>vendor Library</i> eingebunden. Dazu reicht es dann in der Boostrap Datei über die <i>init Funktion</i> einen Loader zu definieren. Hier nehmen wir einfach mal einen Order "PluginName/src" diesem geben wir dann dem Namespace "espend". Dazu die Datei Beispiele:</p> <h2>ClassLoader einbinden</h2> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Shopware_Plugins_Frontend_EspendTest_Bootstrap <span style="color: #000000; font-weight: bold;">extends</span> Shopware_Components_Plugin_Bootstrap <span style="color: #009900;">&#123;</span> &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> afterInit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$loader</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> \Doctrine\Common\ClassLoader<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'espend'</span><span style="color: #339933;">,</span> __DIR__ <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/src'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$loader</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">register</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #009900;">&#125;</span></pre></div></p> <h2>psr-0 Namespace ClassLoader</h2> <p>Der Doctrine ClassLoader sucht anhand des Verzeichnis <i>src</i> nun entsprechende Dateien anhand der Namensräume und Klassennamen.</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># EspendTest/src/espend/MyClass.php </span><span style="color: #000000; font-weight: bold;">namespace</span> espend<span style="color: #339933;">;</span> &nbsp; <span style="color: #000000; font-weight: bold;">class</span> MyClass <span style="color: #009900;">&#123;</span> &nbsp; <span style="color: #009900;">&#125;</span></pre></div></p> <h2>Shopware ClassLoader</h2> <p>Wer will kann auch den Standard Loader von Shopware nutzen. Dazu werden die Klassennamen aber bei mehreren Unterverzeichnissen schnell recht lang.</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># EspendTest/Classes/FooClass.php </span><span style="color: #000000; font-weight: bold;">class</span> Shopware_Plugins_Frontend_EspendTest_Classes_FooClass <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#125;</span></pre></div></p> </div></div></div> Sun, 07 Dec 2014 17:22:35 +0000 Daniel Espendiller 321 at http://www.espend.de SensioLabsInsight Plugin für PhpStorm http://www.espend.de/artikel/sensiolabsinsight-plugin-fuer-phpstorm.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="/sites/default/files/sensionlabsinsight_phpstorm_shopware.png" class="lightbox colorbox-inline" rel="lightbox" title="SensioLabsInsight PhpStorm"><img class="right" src="/sites/default/files/resize/sensionlabsinsight_phpstorm_shopware-150x165.png" width="150" alt="sensiolabsinsight phpstorm shopware" title="SensioLabsInsight PhpStorm" height="165" /></a>Im Zuge der Zusammenarbeiten zwischen <a href="http://blog.jetbrains.com/phpstorm/2014/05/sensiolabs-partners-with-phpstorm-for-the-bright-future-of-symfony-community-tooling/">JetBrains</a> und <a href="http://blog.sensiolabs.com/2014/05/21/sensiolabs-partners-with-phpstorm-for-the-bright-future-of-symfony-community-toolin/">SensioLabs</a> wurde von mir ein Plugin für <a href="https://insight.sensiolabs.com/">SensioLabsInsight</a> entwickelt, welches mittlerweile im PhpStorm <a href="https://plugins.jetbrains.com/plugin/7589">Plugin Repository</a> zu finden ist.<br/>Das Plugin nutzt die <a href="https://insight.sensiolabs.com/">SensioLabsInsight</a> API und bereitet die Code-Analyse Reports für PhpStorm auf, so dass sie direkt in der IDE zur Verfügung stehen.</p> <p>So werden potenzielle Fehler im Quellcode direkt in der IDE markiert und es können die <a href="https://www.jetbrains.com/phpstorm/webhelp/code-inspection.html">Code-Inspections</a> von PhpStorm genutzt werden. Auch ein direktes Aufrufen des SensioLabsInsight Projekts ist möglich, genau so wie die Anzeige der Statistiken über die Toolbar.</p> <h2>Features</h2> <ul> <li>Get inspection results right into the editor</li> <li>Synchronize the inspection to the latest SensioLabsInsight analysis</li> <li>Get access to the code quality violations messages</li> <li>Use the new SensioLabsInsight panel to perform the most common analysis tasks</li> <li>Easily track the evolution of your technical debt in the new SensioLabsInsight panel</li> </ul> <h2>Bildergalerie</h2> <div class="view view-gallery-include view-id-gallery_include view-display-id-default view-dom-id-1"> <div class="view-content"> <div class="views-row views-row-1 views-row-odd views-row-first views-row-last"> <div class="views-field views-field-title"> <span class="field-content"><a href="/gallerynode/sensiolabsinsight-plugin-fuer-phpstorm.html">SensioLabsInsight Plugin für PhpStorm</a></span> </div> <div class="views-field views-field-field-image"> <div class="field-content"> <div class="item-list"> <ul> <li class="first"><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_shopware.png?itok=N690rBYT" title="SensioLabsInsight Plugin für PhpStorm" class="colorbox" rel="gallery-318"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_shopware.png?itok=mo6uYHXf" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_1.png?itok=vHF9i3Dr" title="SensioLabsInsight Plugin für PhpStorm" class="colorbox" rel="gallery-318"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_1.png?itok=XSJ4D3Vk" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_2.png?itok=jofumD1Q" title="SensioLabsInsight Plugin für PhpStorm" class="colorbox" rel="gallery-318"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_2.png?itok=Ul9FbeYG" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_3.png?itok=BKIMaahj" title="SensioLabsInsight Plugin für PhpStorm" class="colorbox" rel="gallery-318"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_3.png?itok=nmxOUbOb" width="100" height="80" alt="" title="" /></a></li> <li class="last"><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_4.png?itok=PS59nWyS" title="SensioLabsInsight Plugin für PhpStorm" class="colorbox" rel="gallery-318"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/sensionlabsinsight_phpstorm_4.png?itok=wOlOF4uj" width="100" height="80" alt="" title="" /></a></li> </ul> </div> </div> </div> </div> </div> </div> <h2>Youtube</h2> <iframe width="100%" height="315" src="//www.youtube.com/embed/OyFcJGRwM3M" frameborder="0" allowfullscreen></iframe></div></div></div> Sun, 23 Nov 2014 11:10:13 +0000 Daniel Espendiller 317 at http://www.espend.de Laravel Plugin für PhpStorm http://www.espend.de/artikel/laravel-plugin-fuer-phpstorm.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="/sites/default/files/laravel_blade_section_phpstorm_2.png" class="lightbox colorbox-inline" rel="lightbox" title="Laravel Blade Section in PhpStorm"><img class="right" src="/sites/default/files/resize/laravel_blade_section_phpstorm_2-130x59.png" width="130" alt="laravel blade section phpstorm" title="Laravel Blade Section in PhpStorm" height="59" /></a>Mit PhpStorm8 wurde Support für die <a href="http://blog.jetbrains.com/phpstorm/2014/08/blade-template-engine-support-in-phpstorm-8-eap/">Blade Template Enigne</a> vom <a href="http://laravel.com/">Laravel Framework</a> eingebunden. Eines der am meisten gewünschten Features der PhpStorm Community, anhand des Issue System.<br/> Dieser Support bietet allerdings reine Language Syntax Unterstützung. Framework spezifische Features enthält dieses Implementierung nicht. Bei der Nutzung <a href="http://phpmagazin.de/artikel/php-framework-umfrage-2014-176990">Populärstes Framework 2014 | PHP Magazin</a>, sollte es jedoch eine gewissen Beachtung verdient. Mittlerweile stelle ich dafür ein entsprechendes Plugin im <a href="https://plugins.jetbrains.com/plugin/7532">PhpStorm Repository</a> bereit. Laravel basiert zu großen Teilen auf den Symfony2 Komponenten, somit finden sich hier auch viele Features vom <a href="/projekte/phpstorm-symfony2-plugin.html">Symfony2 Plugin</a> wieder.</p> <h2>Features und Komponenten</h2> <ul> <li>Erweiterter Blade Template Support: linemarker, navigation</li> <li>Routing und Controller</li> <li>Translations</li> <li>Config</li> </ul> <h2>Installation</h2> <ul> <li>To install, go to Settings > Plugins and search for "Laravel Plugin"</li> <li>Once installed, you must activate per-project by going to Settings > Laravel Plugin and clicking "Enable for this project"</li> <li>Note Currently, you must install and use the <a href="https://github.com/barryvdh/laravel-ide-helper">Laravel IDE Helper</a> in order for PHPStorm to know how to find the Laravel classes.</li> <ul> <h2>Galerie</h2> <div class="view view-gallery-include view-id-gallery_include view-display-id-default view-dom-id-2"> <div class="view-content"> <div class="views-row views-row-1 views-row-odd views-row-first views-row-last"> <div class="views-field views-field-title"> <span class="field-content"><a href="/gallerynode/laravel-fuer-phpstorm-galerie.html">Laravel für PhpStorm Galerie</a></span> </div> <div class="views-field views-field-field-image"> <div class="field-content"> <div class="item-list"> <ul> <li class="first"><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/laravel_phpstorm_1.png?itok=nGxwYeMc" title="Laravel für PhpStorm Galerie" class="colorbox" rel="gallery-319"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/laravel_phpstorm_1.png?itok=a-GdFZ_W" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/laravel_phpstorm_2.png?itok=jBUQ5mcr" title="Laravel für PhpStorm Galerie" class="colorbox" rel="gallery-319"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/laravel_phpstorm_2.png?itok=EWvpCGf5" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/laravel_phpstorm_3.png?itok=RYHrPEu6" title="Laravel für PhpStorm Galerie" class="colorbox" rel="gallery-319"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/laravel_phpstorm_3.png?itok=NXxQcXhW" width="100" height="80" alt="" title="" /></a></li> <li class="last"><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/laravel_phpstorm_4.png?itok=-Hr0d9UG" title="Laravel für PhpStorm Galerie" class="colorbox" rel="gallery-319"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/laravel_phpstorm_4.png?itok=BIYPm_L7" width="100" height="80" alt="" title="" /></a></li> </ul> </div> </div> </div> </div> </div> </div> </div></div></div> Sun, 23 Nov 2014 12:08:35 +0000 Daniel Espendiller 320 at http://www.espend.de Shopware: Symfony2 Dependency Injection im Plugin nutzen http://www.espend.de/artikel/shopware-symfony2-dependency-injection-im-plugin-nutzen.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="/sites/default/files/shopware_symfony2_dependency_injection.png" class="lightbox colorbox-inline" rel="lightbox" title="Shopware: Symfony2 Dependency Injection"><img class="right" src="/sites/default/files/resize/shopware_symfony2_dependency_injection-200x63.png" width="200" alt="shopware symfony2 dependency injection" title="Shopware: Symfony2 Dependency Injection" height="63" /></a>In Shopware wird die <a href="http://symfony.com/doc/current/book/service_container.html">Symfony2 Service Container Komponente</a> genutzt. Die Core Services lassen sich allerdings nur bedingt beeinflussen, wie man in <a href="https://github.com/ShopwareAG/shopware-4/blob/master/engine/Shopware/Kernel.php">Kernel::buildContainer</a> sehen kann.<br/> So kann man eine eigene Container Datei in <i>/Components/DependencyInjection/services_local.xml</i> anlegen. Dies ist nicht unbedingt praktisch für Plugins. Auch aktuell (4.3.x) gibt es keine richtige Möglichkeit dies irgendwie zu umgeben. Somit muss man sich in <strong>Plugins einen eigenen Container</strong> zusammensetzen und die Shopware Core Services bei Bedarf übergeben.</p> <h2>Eigener Symfony2 Service Container</h2> <p>Wir setzen uns also zu erst einen eigenen <i>ContainerBuilder</i> zusammen. Hier geben wir beispielhaft ein paar Shopware Services mit. Zusätzlich setzen wir auch gleich ein Event, somit kann unser Container zumindest von anderen Plugins erweitert werden. Das ganze lassen wir über eine Singleton Instanz laufen.</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// engine/Shopware/Plugins/Local/Frontend/FooPlugin/Container.php</span> &nbsp; <span style="color: #000000; font-weight: bold;">class</span> Shopware_Plugins_Frontend_FooPlugin_Container <span style="color: #009900;">&#123;</span> &nbsp; <span style="color: #009933; font-style: italic;">/** * @var \Symfony\Component\DependencyInjection\ContainerInterface */</span> <span style="color: #000000; font-weight: bold;">protected</span> static <span style="color: #000088;">$instance</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #009933; font-style: italic;">/** * Get container singleton * * @return \Symfony\Component\DependencyInjection\ContainerBuilder */</span> <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> Instance<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> static <span style="color: #000088;">$instance</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$instance</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$instance</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> \Symfony\Component\DependencyInjection\ContainerBuilder<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$loader</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> \Symfony\Component\DependencyInjection\Loader\XmlFileLoader<span style="color: #009900;">&#40;</span><span style="color: #000088;">$instance</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> \Symfony\Component\Config\FileLocator<span style="color: #009900;">&#40;</span>__DIR__<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$loader</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'container.xml'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$instance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'models'</span><span style="color: #339933;">,</span> Shopware<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Container</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'models'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$instance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'config'</span><span style="color: #339933;">,</span> Shopware<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Container</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'config'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; Shopware<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Container</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'events'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">notify</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Plugin_Container_Init'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> Enlight_Event_EventArgs<span style="color: #009900;">&#40;</span><a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'containerBuilder'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$instance</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$instance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">compile</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$instance</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #009933; font-style: italic;">/** * empty class on for secure singletone */</span> <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #009933; font-style: italic;">/** * empty class on for secure singletone */</span> <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> __clone<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #009900;">&#125;</span></pre></div></p> <h2>Container als XML</h2> <p>Der ContainerBuilder nutzt also die <i>container.xml</i> und setzt die Services zusammen. Shopware Core Services lassen sich nutzen soweit übergeben.</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">// engine/Shopware/Plugins/Local/Frontend/FooPlugin/container.xml &nbsp; &lt;?xml version=&quot;1.0&quot; ?&gt; &nbsp; &lt;container xmlns=&quot;http://symfony.com/schema/dic/services&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd&quot;&gt; &nbsp; &lt;parameters&gt; &lt;parameter key=&quot;cache_lifetime&quot;&gt;10&lt;/parameter&gt; &lt;/parameters&gt; &nbsp; &lt;services&gt; &lt;service id=&quot;models&quot; synthetic=&quot;true&quot;/&gt; &nbsp; &lt;service id=&quot;foo_class&quot; class=&quot;\Shopware_Plugins_Frontend_FooPlugin_Classes_BarClass&quot;&gt; &lt;argument type=&quot;service&quot; id=&quot;models&quot;/&gt; &lt;argument&gt;%cache_lifetime%&lt;/argument&gt; &lt;/service&gt; &nbsp; &lt;/services&gt; &nbsp; &lt;/container&gt;</pre></div></p> <h2>CompilerPass: ContainerBuilder Event nutzen</h2> <p>Im Symfony2 full-stack gibt es Bundles und einen <a href="http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html">CompilerPass</a> damit der Container erweitert werden kann. Wir sollen es bei unserer Implementierung nicht übertreiben und übergeben einfach den <i>ContainerBuilder</i>. Wie man sehen kann, ist es hier auch wieder möglich externe XML files nachladen zu lassen.</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">subscribeEvent</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'Plugin_Container_Init'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'onPluginContainerInit'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> onPluginContainerInit<span style="color: #009900;">&#40;</span>Enlight_Event_EventArgs <span style="color: #000088;">$args</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #009933; font-style: italic;">/** @var \Symfony\Component\DependencyInjection\ContainerBuilder $instance */</span> <span style="color: #000088;">$instance</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$args</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'containerBuilder'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$instance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'plugin.dir'</span><span style="color: #339933;">,</span> __DIR__<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$instance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'shopware.api.customer_resource'</span><span style="color: #339933;">,</span> \Shopware\Components\Api\Manager<span style="color: #339933;">::</span><span style="color: #004000;">getResource</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Customer'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000088;">$loader</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> \Symfony\Component\DependencyInjection\Loader\XmlFileLoader<span style="color: #009900;">&#40;</span><span style="color: #000088;">$instance</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> \Symfony\Component\Config\FileLocator<span style="color: #009900;">&#40;</span>__DIR__<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$loader</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'container.xml'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span></pre></div></p> <h2>Singleton in Bootstrap</h2> <p>Zuletzt definieren wir uns noch eine Proxy Methode um den Container über eine Singleton Instanz im Plugin nutzen zu können.</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">use</span> Shopware_Plugins_Frontend_FooPlugin_Container <span style="color: #b1b100;">as</span> Container<span style="color: #339933;">;</span> &nbsp; <span style="color: #000000; font-weight: bold;">class</span> Shopware_Plugins_Frontend_FooPlugin_Bootstrap <span style="color: #000000; font-weight: bold;">extends</span> Shopware_Components_Plugin_Bootstrap <span style="color: #009900;">&#123;</span> <span style="color: #009933; font-style: italic;">/** * Instance helper for dic container * * @return \Symfony\Component\DependencyInjection\ContainerBuilder */</span> <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> Container<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #b1b100;">return</span> Container<span style="color: #339933;">::</span><span style="color: #004000;">Instance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #009900;">&#125;</span></pre></div></p> <p>Somit können wir dann überall im Plugin auf die Services zugreifen</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;">Shopware_Plugins_Frontend_FooPlugin_Bootstrap<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'foo_class'</span><span style="color: #009900;">&#41;</span></pre></div></p> </div></div></div> Sat, 22 Nov 2014 13:00:09 +0000 Daniel Espendiller 315 at http://www.espend.de Shopware: registerCustomModels für Doctrine Entities von fremden Plugins http://www.espend.de/artikel/shopware-registercustommodels-fuer-doctrine-entities-von-fremden-plugins.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>Da Shopware auf Doctrine setzt kann man eigene Entities auch über ein Plugins einbinden <a href="http://forum.shopware.com/programmierung-f56/plugin-neues-model-erstellen-t10506.html">Shopware / Doctrine Plugin - Neues Model erstellen</a>. Diese werden zum Beispiel unter <i>MyPlugin/Models/FooClass.php</i> angelegt. In der Plugin Bootstrap muss das Verzeichnis <i>Models</i> dann manuell registriert werden.</p> <p>Ein Aufruf der <i>registerCustomModels</i> innerhalb von <i>afterInit</i> reicht dazu. Wenn man jedoch auch Entities von externe Plugin / Premium Plugins z.B. als Fremdbeziehung einbinden will, so kann man nicht davon ausgehen, dass das Plugin bereits initialisiert wurde. Will man dieses sicherstellen, so hilft es unten aufgeführtes Code-Snippet. Es ruft einfach die fremde <i>registerCustomModels</i> aus dem Plugin auf.</p> <p><div class="geshifilter"><pre class="php geshifilter-php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Shopware_Plugins_Frontend_MyPlugin_Bootstrap <span style="color: #000000; font-weight: bold;">extends</span> Shopware_Components_Plugin_Bootstrap <span style="color: #009900;">&#123;</span> &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> afterInit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">registerCustomModels</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; try <span style="color: #009900;">&#123;</span> <span style="color: #000088;">$plugin</span> <span style="color: #339933;">=</span> Shopware<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Container</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'shopware.plugin_manager'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPluginBootstrap</span><span style="color: #009900;">&#40;</span> Shopware<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Container</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'shopware.plugin_manager'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPluginByName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ForeignPlugin'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$plugin</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">registerCustomModels</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> catch <span style="color: #009900;">&#40;</span>\Exception <span style="color: #000088;">$e</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#125;</span> &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span></pre></div></p> </div></div></div> Sat, 22 Nov 2014 11:25:08 +0000 Daniel Espendiller 316 at http://www.espend.de Drupal8 PhpStorm Plugin für Symfony2 Support http://www.espend.de/artikel/drupal8-phpstorm-plugin-fuer-symfony2-support.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="/sites/default/files/drupal8_symfony2_phpstorm_7.png" class="lightbox colorbox-inline" rel="lightbox"><img class="right" src="/sites/default/files/resize/drupal8_symfony2_phpstorm_7-200x85.png" width="200" alt="" title="" height="85" /></a>Ab Drupal8 wurde der Core durch viele Symfony2 <a href="http://www.sitepoint.com/symfony-drupal-8/">Komponenten erweitert</a>. Dies vereinfacht nicht nur die Codepflege, sondern auch auch den <b>Support für PhpStorm</b>. Offiziell unterstützt <a href="http://confluence.jetbrains.com/display/PhpStorm/Drupal+Development+using+PhpStorm">JetBrains mit einem entsprechend Drupal Plugin</a> das Framework bereits. Der Umfang lässt dich allerdings drastisch erweitern, wenn man die Symfony2 Komponenten noch mit einbezieht.</p> <p>Deswegen habe ich nun für das <a href="/projekte/phpstorm-symfony2-plugin.html">Symfony2 Plugin für PhpStorm</a> ein entsprechendes Zusatzplugin bereitgestellt. Sofern noch nicht direkt unterstützt stehen nun z.B. Dependency-Injection, Twig, und Routing Komponentent bereit. Das Plugin kann direkt über PhpStorm installiert werden oder über das JetBrains Plugin Repository: <a href="http://plugins.jetbrains.com/plugin/7487">Drupal Symfony2 Bridge</a>. SourceCode gibt es auf <a href="https://github.com/Haehnchen/idea-php-drupal-symfony2-bridge">GitHub</a></p> <h2>Features</h2> <ul> <li>Twig/PHP: Routing</li> <li>Twig/PHP: Gettext support (just throw in a full po file into project)</li> <li>Symfony2: Full dic container support</li> <li>Symfony2: Twig extensions</li> <li>Symfony2: and more...</li> </ul> <div class="view view-gallery-include view-id-gallery_include view-display-id-default view-dom-id-3"> <div class="view-content"> <div class="views-row views-row-1 views-row-odd views-row-first views-row-last"> <div class="views-field views-field-title"> <span class="field-content"><a href="/gallerynode/drupal8-und-symfony2-phpstorm.html">Drupal8 und Symfony2 in PhpStorm</a></span> </div> <div class="views-field views-field-field-image"> <div class="field-content"> <div class="item-list"> <ul> <li class="first"><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_1.png?itok=abY6mJeY" title="Drupal8 und Symfony2 in PhpStorm" class="colorbox" rel="gallery-312"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_1.png?itok=7CohvCRt" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_2.png?itok=GdXyCW_R" title="Drupal8 und Symfony2 in PhpStorm" class="colorbox" rel="gallery-312"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_2.png?itok=m_SEROn9" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_3.png?itok=l6Syx1c5" title="Drupal8 und Symfony2 in PhpStorm" class="colorbox" rel="gallery-312"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_3.png?itok=Gxy2HLfz" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_4.png?itok=zy5rhJvK" title="Drupal8 und Symfony2 in PhpStorm" class="colorbox" rel="gallery-312"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_4.png?itok=ExjJtxqJ" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_5.png?itok=xdBTL03k" title="Drupal8 und Symfony2 in PhpStorm" class="colorbox" rel="gallery-312"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_5.png?itok=zkysl1xm" width="100" height="80" alt="" title="" /></a></li> <li><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_6.png?itok=43H0w_oP" title="Drupal8 und Symfony2 in PhpStorm" class="colorbox" rel="gallery-312"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_6.png?itok=KAb8jF8q" width="100" height="80" alt="" title="" /></a></li> <li class="last"><a href="http://www.espend.de/sites/default/files/styles/gallery_colorbox/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_7.png?itok=ZoHXuwdv" title="Drupal8 und Symfony2 in PhpStorm" class="colorbox" rel="gallery-312"><img typeof="foaf:Image" src="http://www.espend.de/sites/default/files/styles/gallery_include/public/GalleryItem/%5Bnid%5D/drupal8_symfony2_phpstorm_7.png?itok=U156WsJg" width="100" height="80" alt="" title="" /></a></li> </ul> </div> </div> </div> </div> </div> </div> </div></div></div> Sat, 09 Aug 2014 09:20:50 +0000 Daniel Espendiller 313 at http://www.espend.de QrCode Scanner in Android App mit ZXing http://www.espend.de/artikel/qrcode-scanner-android-app-mit-zxing.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p><a href="/sites/default/files/android_zxing_qrcode.jpg" class="lightbox colorbox-inline" rel="lightbox" title="Android ZXing Qrcode"><img src="/sites/default/files/resize/android_zxing_qrcode-200x107.jpg" width="200" alt="android zxing qrcode" title="Android ZXing Qrcode" class="right" height="107" /></a> QrCodes werden meinst im Bereich von Smartphones eingesetzt, um das lästige Tippen zu umgehen. Es gibt viele fertige QrCode Scanner Apps, man kann aber auch ziemlich einfach einen <b>eigenen Scanner in seiner App einbinden</b>. Für Android und JAVA bietet sich die <a href="https://github.com/zxing/zxing">ZXing Bibiothek</a> an. Sie ist recht klein und kann direkt über Gradle eingebunden werden. Somit ist es mit nur ein paar Zeilen Code möglich die App um einen funktionalen QrCode Scanner zu erweitern.</p> <h2>build.gradle erweitern</h2> <p>Da ZXing doch recht mächtig ist und viele unterschiedliche Barcode Format unterstützt, darunter dann auch der QrCode, sollten wir uns auf die Core Komponenten beschränken. Diese enthalten alles um einen QrCode Scanner in der einer App einzubinden. Dank Gradle muss man zur Einbindung nur die <i>dependencies</i> in der <i>build.gradle</i> erweitern:</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">dependencies { compile 'com.google.zxing:core:2.3.0' }</pre></div></p> <h2>QrCode Scanner Activity</h2> <p>Der ZXing Scanner kann in jeder beliebigen Activity einfach als weitere Activity aufgerufen werden. Als Übergabe muss jegliche ein Callback mit <i>onActivityResult</i> übergeben werden:</p> <p><div class="geshifilter"><pre class="java geshifilter-java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.zxing.integration.android.IntentIntegrator</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #666666; font-style: italic;">// [...]</span> &nbsp; @Override <span style="color: #000000; font-weight: bold;">public</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aview+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">View</span></a> onCreateView<span style="color: #009900;">&#40;</span>LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> rootView.<span style="color: #006633;">findViewById</span><span style="color: #009900;">&#40;</span>R.<span style="color: #006633;">id</span>.<span style="color: #006633;">foo</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setOnClickListener</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aview+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">View</span></a>.<span style="color: #006633;">OnClickListener</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> @Override <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> onClick<span style="color: #009900;">&#40;</span><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aview+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">View</span></a> v<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> IntentIntegrator.<span style="color: #006633;">initiateScan</span><span style="color: #009900;">&#40;</span>getActivity<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span></pre></div></p> <h2>QrCode Scan Result / Callback</h2> <p>Wurde ein gültiger QrCode eingescannt, so wird dieser als Activity Callback übergeben. Neben dem <i>resultCode</i>, welche einen möglichen Fehlercode enthält, steht uns in <i>UPCScanned</i> am Ende der Inhalt des QrCode zur Verfügung und kann im weiteren Programmablauf genutzt werden.</p> <p><div class="geshifilter"><pre class="java geshifilter-java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.zxing.integration.android.IntentIntegrator</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.google.zxing.integration.android.IntentResult</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> FooActivity <span style="color: #000000; font-weight: bold;">extends</span> Activity <span style="color: #009900;">&#123;</span> <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000066; font-weight: bold;">void</span> onActivityResult<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> requestCode, <span style="color: #000066; font-weight: bold;">int</span> resultCode, Intent data<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000000; font-weight: bold;">switch</span><span style="color: #009900;">&#40;</span>requestCode<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000000; font-weight: bold;">case</span> IntentIntegrator.<span style="color: #006633;">REQUEST_CODE</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>resultCode <span style="color: #339933;">!=</span> RESULT_CANCELED<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> IntentResult scanResult <span style="color: #339933;">=</span> IntentIntegrator.<span style="color: #006633;">parseActivityResult</span><span style="color: #009900;">&#40;</span>requestCode, resultCode, data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span style="color: #003399;">String</span></a> UPCScanned <span style="color: #339933;">=</span> scanResult.<span style="color: #006633;">getContents</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <span style="color: #666666; font-style: italic;">// QrCode inside; have fun with it</span> &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span> <span style="color: #000000; font-weight: bold;">return</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#125;</span></pre></div></p> </div></div></div> Mon, 23 Jun 2014 17:22:20 +0000 Daniel Espendiller 311 at http://www.espend.de Doctrine und Symfony2 ORM Entities aus Datenbank erzeugen http://www.espend.de/artikel/doctrine-und-symfony2-orm-entities-aus-datenbank-erzeugen.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>Normalweise nutzt man in Symfony2 und Doctrine Projekten Yaml oder Annotations um dann über <b><i>doctrine:schema:update</i></b> die Datenbankstruktur anzulegen bzw. aktualisieren. Wenn man allerdings auf eine fremde Datenbank angewiesen ist funktioniert dieses Vorgehen meist nicht mehr. Mittels <b><i>doctrine:mapping:import</i></b> besteht jedoch auch die Möglichkeit aus einer <a href="http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html">Datenbank die Doctrine Entities</a> samt Konfiguration zu generieren. Alles geht hier allerdings nicht automatischen und einige Dinge gibt es noch zu beachten</p> <h2>Tabelle filtern</h2> <p>Nicht jede Datenbank mit allen Tabellen lassen sich direkt ins ORM Modell übertragen. Es gibt diverse Szenarien, wo kein automatischen umwandeln möglich ist. Doctrine parst alle Tabellen in einer Datenbank, kann hier nur eine Tabelle nicht konvertiert werden, so bricht der Importvorgang komplett ab. Möchte man diese <b>Tabelle einfach ignorieren</b>, kann man sie über <i>schema_filter</i> und eines Regulären Ausdruck überspringen lassen. Doctrine bietet war auch einen Paramater <i>--filter</i>, dieser greift aber erst nach dem Einlesen der Datenbank Struktur, also wenn der Fehler bereits aufgetreten ist.</p> <p>Eine Konfiguration mit Filter für einer zweiter Doctrine EntityManager Instanz lässt dich dann über die Symfony2 Config wie folgt abbilden:</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;"># app/config.yml doctrine: dbal: default_connection: default connections: default: dbname: &quot;%database_name%&quot; [...] charset: UTF8 legacy: dbname: &quot;%database_desk_name%&quot; dbname: &quot;%database_name%&quot; [...] charset: UTF8 &nbsp; schema_filter: ~^(?invalid_table)~</pre></div></p> <h2>Doctrine ORM Whitelist Tabellen</h2> <p>Man kann die Logik auch umdrehen und nur die <b>Tabellen freigeben</b>, die explizit von Doctrine genutzt werden sollen. Unbekannte Tabellen werden somit einfach übersprungen. Dazu dann einfach den Regulären Ausdruck von <i>schema_filter</i> anpassen.</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;"># app/config.yml doctrine: dbal: connections: legacy: schema_filter: ~^(my_table_name_1|my_table_name_1)$~</pre></div></p> <h2>Enum Felder in Doctrine</h2> <p>Da Enum Felder nicht von allen SQL Datenbanken unterstützt wird, ist dieser Feldtyp in <a href="http://symfony.com/doc/2.0/cookbook/doctrine/dbal.html#registering-custom-mapping-types-in-the-schematool">Doctrine erst einmal nicht aktiv</a>. Durch setzen von <i>mapping_types</i> kann man Doctrine allerdings anweisen dieses Feld als String Typ zu nutzen. Man kann somit die Tabelle importieren.</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">Fatal error: Uncaught exception 'Doctrine\DBAL\DBALException' with message 'Unknown database type enum requested, Doctrine\DBAL\Platforms\MySqlPlatform may not support it.'</pre></div></p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;"># app/config.yml doctrine: dbal: connections: legacy: mapping_types: enum: string</pre></div></p> <h2>Tabellen ohne Primary Key</h2> <p>Nicht alle "Strukturelle Fehler" lassen sich übergeben. Tabellen ohne <i>Primary Key</i> werden von Doctrine nicht Unterstützt. Da es sich hierbei (hoffentlich) meist nur um <i>ManyToMany</i> Tabellen handelt, kann man das Mapping manuell anlegen und die Beziehungstabelle über die <i>schema_filter</i> ignorieren</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;"> [Doctrine\ORM\Mapping\MappingException] Table table_name_with_error has no primary key. Doctrine does not support reverse engineering from tables that don't have a primary key.</pre></div></p> <h2>Primär Key in Relation Mappings</h2> <p>Manchmal kann es auch vorkommen, dass "Primäre Schlüssel" einer Tabelle aus mehreren Felder besteht und diese zusätzlich Bestandteil einer ManyToOne oder OneToMany Beziehung sind. Das entsprechende Feld muss dazu einfach als <i>associationKey</i> definiert werden.</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">MyBundle\Entity\Foo: type: entity table: foo_table id: field_1: type: integer field_2: associationKey: true manyToOne: mlmLevel: targetEntity: Bar\ClassName joinColumn: name: field_2 referencedColumnName: foreign_id</pre></div></p> <h2>Doctrine Entity Klassen generieren</h2> <p><i>doctrine:mapping:import</i> erstellt hier die reinen Konfigurationsdateien wenn mal Yaml auf Ausgabe nutzt und legt die entsprechenden Datei in einem definierten Bundle ab <i>MyTargetBundle/Resource/config/doctrine/TableName.orm.yml</i>. Eventuell müssen also noch die Klassen selber mittels Konsolenbefehl erzeugt werden.</p> <p><div class="geshifilter"><pre class="text geshifilter-text" style="font-family:monospace;">php app/console doctrine:mapping:import --em=legacy MyTargetBundle yaml --- php app/console doctrine:generate:entities MyTargetBundle</pre></div></p> </div></div></div> Sat, 21 Jun 2014 09:53:26 +0000 Daniel Espendiller 310 at http://www.espend.de