Category
Author

Ahoj, po updatu Nette mám nefunkční Kdyby/Facebook. Lze toto nějak jednoduše opravit? Accessing methods as properties via $obj->begin is deprecated, use PHP callback $obj, ‘begin’ in C:\xampp\htdocs\dejbod\vendor\kdyby\facebook\src\Kdyby\Facebook\Diagnostics\Panel.php:170

Doctrine Beginners
Vojta Mareš at 23.4.2018 10:53

Hello,

I would like to know if it is possible another type for doctrine with namespace instead of fixed name, i mean: Example from Ramyse\Uuid: doctrine:
types:
uuid: Ramsey\Uuid\Doctrine\UuidType

but with consistence Consistence\Doctrine\Enum\Type\StringEnumType::NAME: Consistence\Doctrine\Enum\Type\StringEnumType can I register it like: doctrine:
types:
Consistence\Doctrine\Enum\Type\StringEnumType::NAME: Consistence\Doctrine\Enum\Type\StringEnumType

is this possible or not ?

Doctrine Beginners
kocopo at 16.4.2018 1:11

Zdravím, začínám s nette a doctrine a když se snažím získat jeden článek z databáze tak mi stále vyhazuje chybu Metadata of class Posts was not found, because the class is missing or cannot be autoloaded

v config.local mám doctrine:
user: root
password:
dbname: quickstart
host: 127.0.0.1:3306
metadata:
App: %appDir% a pak v namespace App\Model ve složce app/model mám soubor Posts.php který začíná :

namespace App\Model;

use Doctrine\ORM\Mapping as ORM; use Kdyby\Doctrine\Entities\Attributes\Identifier;

/**
*
* @ORM\Entity()
*/ class Posts {

A pak třídu PostService:

class PostService {

/**
* @var EntityManager
*/
private $EM;

public function __construct(EntityManager $entityManager)
{
$this->EM = $entityManager;
}

/**
* @return Posts
*/
public function findArticle($id){
return $this->EM->find(‘Posts’, $id);
}

}

Mohl by mi někdo objasnit co dělám špatně ?

Doctrine Beginners
Vojta Mareš at 3.1.2018 23:38

Zdravím,

po dlouhém rozmýšlení jaké ORM pro netté použít (kdyby/doctrine, nextras/orm a nettrine/orm) jsem se rozhodl pro kdyby/doctrine.

Avšak mám problém/tápu ve stránkováním. Když chci vypsat N článků, jak toho docílím, četl jsem dokumentaci, ale vůbec z toho nejsem moudrý
- Mám si napsat vlastní třídu pro stránkování pro každou entitu zvlášť pomocí DQL nebo je na to něco univerzálního jako má nette database ?

Díky

Dostal jsem od Filipa přístupy takže teď řeším kompatibilitu s PHP 7.2 a Symfony 4.

Pokud jde o pull requesty, nebudu je aktivně procházet, ale pokud mne někdo pingne u pull requestu, který bude rebasnutý na aktuální master a nebude failovat, tak na to mrknu.

iguana007 at 26.10.2017 10:44

Ahoj, rad by jsem se zeptal, jak to vypada do budoucna s Kdyby? Podle Githubu mi to pripada, ze je vetsina repozitaru mrtva, tj. ceka tam mraky pull requestu a az na par vyjimek se to neresi. Pouzivat tedy u novych projektu Kdyby knihovny nebo radsi zvolit alternativy? Dekuji za info.

Kdyby to ještě náhodou někdo řešil… Mi nefungovala ani notace “if_else”, zkusil jsem ale pouze “if” a tohle prošlo :o)

Tak si nakonec odpovím sám. Nainstaloval jsem modul redisu pro PHP ve verzi 3.1.3 a už to běhá bez chyby.

Na Windows 10 mám aplikaci. V ní mám aktivní redis. Viz. config: extensions:
redis: Kdyby\Redis\DI\RedisExtension

redis:
journal:
database: 0

storage:
database: 0

session:
database: 1

host: 127.0.0.1
connectionAttempts: 3

Celé mi to havaruje stále chybovou hláškou session_regenerate_id(): Failed to create(read) session ID: redis (path: tcp://127.0.0.1:6379?weight=1&timeout=10&database=1&prefix=Nette.Session%3A)

Nedovedl by jste prosím poradit co vyzkoušet ? PHP je ve verzi 7.0.13, redis support se mi v phpinfo zobrazuje jako aktivní ve verzi 3.1.0. Redis server mám nainstalován. Když zkouším redis jhednoduše přímo v php skriptu mimo nette, tak tohle normálně funguje: $redis = new Redis(); $redis->connect( ‘127.0.0.1’ ); // sets message to contian “Hello world” //$redis->set(‘message’, ‘Hello world’);

// gets the value of message $value = $redis->get(‘message’);

// Hello world print($value);

echo ($redis->exists(‘message’)) ? “Oui” : “please populate the message key”;

Doctrine Beginners
Raketoplan2005 at 7.7.2017 2:10

Ahoj,

používám v PHP rozšíření pro enumy a teď bych ho chtěl navázat na doctrine s kdyby/doctrine ale nevím jak správně udělat krok 3 z https://github.com/…nce-doctrine – tedy Register postLoad listener v kombinaci s kdyby/doctrine, jak správně zapsat registraci listeneru do configu, prosím?

Zatím jsem to vyřešil v bootstrapu:

$em = $container->getByType(“\Doctrine\ORM\EntityManager”);
$reader = $container->getByType(“\Doctrine\Common\Annotations\Reader”); $em->getEventManager()->addEventListener(
Events::postLoad,
new EnumPostLoadEntityListener($reader) );

Díky

You shouldn't change entities in postflush. It's too late and requires a second flush call to actually work. Some people are calling flush in the subsriber but that can end very badly in some cases because the first flush is not yet finished.

Personally I'm using “double flush” with my own event:

$this->em->transactional(
    function () {
        // some logic
        $this->em->flush();
        // use symfony/event-dispatcher to call subsribers with more logic
        $this->eventDispatcher->dispatch(...);
        // transactional will call a second flush
    }
)

Caute, Neviete mi poradit mam listener na onFlush a v nom sa snazim editovat dalsie entity. podla tochto navodu som si chcel odregistrovat lisener urobit zmenu ktoru potrebujem a znovu ho zaregistrovat. Problem je v tom ze mi to nadava: Undefined index: Doctrine\ORM\Event::onFlush tu

Ja mam asi takyto listener, neviete mi poradit co robim zle?

<?php
namespace Nas\CmsModule\Listeners;

use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
use Doctrine\ORM\Query;
use Kdyby\Events\Subscriber;
use Nas\CmsModule\Model\BasePost;
use Nas\CmsModule\Model\Route;
use Nas\CmsModule\Model\RouteRepository;

class RouterListener implements Subscriber {

    /**
     * Specifies the list of events to listen
     * @return array
     */
    public function getSubscribedEvents() {
        return array(
            Events::onFlush
        );
    }

    /**
     * @param OnFlushEventArgs $args
     */
    public function onFlush(OnFlushEventArgs $args) {
        /** @var \Kdyby\Doctrine\EntityManager $em */
        $em = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        // Remove listener
        $eventManager = $em->getEventManager();
        if ($eventManager) {
            $eventManager->removeEventListener(array(Events::onFlush), $this);
        }

        // Process
        foreach ($uow->getScheduledEntityUpdates() as $key => $entity) {
            if ($entity instanceof Route) {
                $changeSet = $uow->getEntityChangeSet($entity);

                if (array_key_exists('url', $changeSet) || array_key_exists('language', $changeSet)) {
                    $this->replaceChildWhenUpdate($entity, $em);
                }
            }
        }

        // Add listener back again
        if ($eventManager) {
            $eventManager->addEventListener(array(Events::onFlush), $this);
        }
    }

}

Remember that “enum” is not realy supported by Doctrine. Doctrine deals with “string” type and send string values to your database. This is not a problem if your Database is rightly configured with “enum” (SELECT, UPDATE, INSERT will work if your application provide the correct string values).

But for the SchemaUpdaterTool, this field stay a simple “string” type.

Now, if you look at the Doctrine documentation about “columnDefinition”, you will see: “DDL SQL snippet that starts after the column name and specifies the complete (non-portable!) column definition. This attribute allows to make use of advanced RMDBS features. However you should make careful use of this feature and the consequences. SchemaTool will not detect changes on the column correctly anymore if you use “columnDefinition”.”

So everything that you put in “columnDefinition” cannot be compared during “orm:schema-tool:update”. For him, “/** @ORM\Column(type=“enum”, columnDefinition=“ENUM(‘admin’, ‘customer’)”) */” is exactly the same has /** @ORM\Column(type=“string”) */

Ahoj, zkousel to nekdo s kdyby/console? Pres homepagePresenter se mi to povedlo rozchodit, ale kdyz to ted zkousim pres console, tak mi to zase pise: “Please install and enable the redis extension.”

Diky

Translation Questions
Ivo Toman at 10.2.2017 7:14

Lze nějakým způsobem přidat whiteList dynamicky a ne jen přes neon? Jde mi o to, že si přidám v db další jazyk a chtěl bych aby se k tomu začali načítat překlady automaticky, bez zásahu do config.neon

Hello,

I would like to know, how to register directory for entities annotation (metadata) when loading entities from vendor extension. Is there any possibility to get annotation driver from container builder and add metadata directories?

When calling directly:

$builder->getDefinition(
‘doctrine.default.driver.Kdyby_Doctrine.annotationsImpl’ )->addSetup(‘addPaths’, $paths)

, nothing takes affect.

Thanks

Translation Questions
vastlik at 25.1.2017 15:09

Ahoj, používám formát xliff a v tagu source mám název, který obsahuje mezery. Je nějaká možnost jak k tomu přistopovat?
<trans-unit id=“3393”>
<source>Text s mezerami</source>
<target state=“translated”>Nějaký jiný text, který je překlad</target>
</trans-unit>

např. kdyby tam bylo jedno slovo tak použiji strings.slovo Díky

Zdravim mam entitu Genre a Serial medzi nimi je vazba ManyToMany

Vyberiem si Genre pomocou findOneBy(slug ⇒ …) dostanem $genre a potom v template citam serialy ako foreach($genre->serials as $serial) {..}

Zaujima ma a uz sa s tym trapim niekolko dni ako mozem pridat LIMIT (paginator) na obsah v $genre->serials, kedze limit sa mi aplikuje len na vyber Genre ale to nepotrebujem vyberam len jeden..

Dakujem

Tak jsem to ještě upravil tak, že vytvářím pro každý domain nový katalog a ten pak můžu uložit přes TranslationWritter, protože mu dodávám svou vlastní path. Akorát jsem teda ještě nepřišel na to, jestli lze nějak vytáhnout seznam resources s klíčema v podobě domain. Protože takto musím cestu stále hledat tím regulárem.

Mám vytvořeny moduly a přes Extension implements ITranslationProvider dávám translátoru vědět o tom, kde má hledat zdroje (*.neon) pro překlady. Tedy v adresáři toho modulu. To vše mi funguje.

Nicméně vytvořil jsem si také formulář, který umožňuje uživatelům překládat do jiného jazyka. Chci tyto překlady po odeslání uložit vedle těch zdrojových (ve výchozím jazyku). Když ty překlady přidám do katalogu a poté je přes writter chci uložit, tak to chce jen path, kde ale uloží všechny domain překlady do jedné složky (tedy nikoliv do složky modulů).

Zatím jsem to ohakoval tak, že vůbec nepoužiji neon dumper a writter, ale vytvořím .neon (dle domain a jazyka), přidám do resources a pak si ho najdu a uložím překlady nějak takto:

foreach($targetCatalogue->all() as $domain ⇒ $translations) {
$fileName = $domain . “.” . $targetCatalogue->getLocale() . “.neon”;
if($resources = preg_grep(“|$fileName$|i”, $targetCatalogue->getResources())) {
$res = array_shift($resources);
file_put_contents($res, Neon::encode($translations, Neon::BLOCK));
}
}

Není na to nějaké lepší řešení?

Zdravím,

toto by mě také velice zajímalo – sledoval jsem právě onu přednášku na YT a překvapila mě i poznámka, že použití setterů/getterů není ideální. Přemýšlel jsem nad jinými možnostmi, ale v praxi převážně je potřeba se dostat ke všem property, a většinu stějně tak nastavovat.

Použití, které uvedl Vladimír výše také není ideální, co se týče metody “create”, jelikož je nutné, aby bylo z venší znát implementační detaily oněch $params.

Z tohoto důvodu by mě zajímalo, jaké jsou jiné alternativy a jakým způsobem to Filip myslel, ideálně příklad nějaké obsáhlejší entity?

Děkuji

já to pořešil následovně:


$router[] = new Route('//www.[
	.]%sld%.
		', 'Front:Homepage:default');
	
	

a překlad pro češtinu mám: neco.cz_CZ.neon, není to úplně ideální řešení, ale funguje :)

Zdravím,

začal jsem používat Kdyby\RabbitMQ a mám takový dotaz ohledně inicializace RPC klientů. Při načítání klientů z configu a přidávání do DI kontejneru se provádí inicializace, kde se posílá požadavek na vytvoření fronty, což funguje pěkně. Teoreticky může ale nastat situace, že budu chtít použít RPC klienta pouze v konzolovém příkazu, tzn. aplikace jako taková ho vůbec nepoužívá, ale protože je v DI kontejneru, tak se vlastně při každém ajaxovém požadavku provádí pokus o připojení na rabbit a vytvoření fronty, což je škoda. Chápu to správně? Je to záměr, že to nefunguje lazy? Pokud ano, rád bych se zeptal proč.

Díky za odpověď ;-)

Michal

Ahoj,

přecházím z Nextras\Orm na Doctrinu a hned jsem zabruslil do problému… A nevím jak z něj ven. Omlouvám se předem na názvy sloupečlů, jsem zvyklý ze SAP a ty data v podstatě ze SAP plním.

Mám tři tabulky:

Employee ( werks, pernr, teami, kostl, fname, lname, …; Primární klíče jsou werks, pernr).

Team (werks, teami, name, …; Primární klíče jsou werks, teami)

Center (werks, kostl, name, …; Primární klíče jsou werks, kostl)

V tabulce employee používám vztah ManyToOne na teami a kostl, a protože jsou vždy dva primární klíče, dávám to pomocí JoinColumns (werks a teami, werks a kostl).

Když chci uložit/upravit nového zaměstnance a jeho tým (Teami) a středisko (kostl) existuje, tak je vše v pořádku. Pokud ale neexistuje v tabulce Team nebo Center záznam, na který odkazuji, hodí mi to automaticky závod (Werks) na hodnotu NULL a příkaz neprojde (werks = primární klíč). To je ale problém, protože tam potřebujeme mít i staré zaměstnance, kteří už u nás nepracují a proto nemají přiřazený tým ani nákl. středisko.

Při vytváření zaměstnance pro vložení týmu a střediska používám getPartialReference.

Our customer has problem with application developed in Nette. Sometimes there is RedisException. This happen only sometimes Kdyby\Redis\RedisClientException: Redis server went away vendor/kdyby/redis/src/Kdyby/Redis/RedisClient.php:291 caused by RedisException RedisException: Connection closed vendor/nette/utils/src/Utils/Callback.php:98 caused by RedisException RedisException: Connection closed vendor/nette/http/src/Http/Session.php:107 caused by RedisException

Enviroment deswcription: 1 virtual server LoadBalancer 1 virutal server Application server
PHP 5.5.19–1+deb.sury.org~trusty+1
nginx/1.7.8
Tracy 2.3.0
Nette Framework 2.3.0 (released on 2015–02–25)

1 virutal server Redis: Redis server v=3.0.7 sha=00000000:0 malloc=jemalloc-3.6.0 bits=64 build=6929afb666badedb 1 virutal server DB server MySql

I have changed loglevel on Redis server to debug, but in log there is no error, fail. Could you help me to resolve this issue? What to check? What you recommend?

Is possible that this issue relates to https://github.com/…is/issues/14

Nikdo? :-(

  • Jak s tím pracovat v případě replicatoru?
  • Jak zajistit automatické mazání, když přes replicator odstraním řádek?
  • Jak zajistit updatování, aniž by se tvořili duplicity?

Provizorně všechny záznamy před zpracováním smažu, ale asi to není cool řešení:

$this->em->getConnection()->delete('catalog_item_attributes', ['catalog_item_id' => $this->entity->id])

Chyba byla v ukládání, tj persist:

foreach ($values["attributes"] as $key => $attribute)
{
    $a = new CatalogItemAttribute();
    $a->value = $attribute->value;
    $a->attribute = $this->attributeModel->findAttribute($attribute->id);
    $this->entity->addAttribute($a);

    $this->em->persist($a);
}

$this->em->flush($entity);

Ahoj, mám entitu produkt a ten by měl mít možnost vlastnit více attributů. Mám to navržené tedy přes spojovací tabulku. Pro přidávání attributů používám replicator. Jak pěkně uložit nové attributy?

Udělal jsem tam něco takového:

foreach ($values["attributes"] as $key => $attribute)
{
    $a = new CatalogItemAttribute();
    $a->value = $attribute->value;
    $a->attribute = $this->attributeModel->findAttribute($attribute->id);
    $this->entity->addAttribute($a);

    $this->em->persist($this->entity);
}

$this->em->flush($entity);

ale křičí:

A new entity was found through the relationship 'App\Entity\CatalogItem#attributes' that was not configured to cascade persist operations for entity: App\Entity\CatalogItemAttribute@00000000154b019f000000000e5b71bb. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'App\Entity\CatalogItemAttribute#__toString()' to get a clue.

Jednotlivé entity:

CatalogItem:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="catalog_item")
 */
class CatalogItem extends BaseEntity
{
    use \Kdyby\Doctrine\Entities\MagicAccessors;

    /**
     * @ORM\Id
     * @ORM\Column
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column
     * @InputType(label="Název", type="text", required=true)
     */
    protected $name;

    /**
     * @ORM\Column
     * @InputType(label="Model", type="text", required=true)
     */
    protected $model;

    /**
     * @ORM\Column
     * @InputType(label="URL", type="text", required=true)
     */
    protected $url;

    /**
     * @ORM\Column
     * @InputType(label="Vlastní H1", type="text")
     */
    protected $titleH1;

    /**
     * @ORM\Column
     * @InputType(label="Meta title", type="text")
     */
    protected $metaTitle;

    /**
     * @ORM\Column
     * @InputType(label="Meta description", type="textArea")
     */
    protected $metaDescription;

    /**
     * @ORM\Column(type="decimal")
     * @InputType(label="Cena bez DPH", type="text")
     */
    protected $price;

    /**
     * @ORM\Column(type="decimal")
     * @InputType(label="Cena s DPH", type="text")
     */
    protected $priceWithoutVat;

    /**
     * @ORM\Column
     * @InputType(label="DPH v %", type="text")
     */
    protected $vat;

    /**
     * @ORM\OneToMany(targetEntity="CatalogCategoryItem", mappedBy="item")
     */
    protected $categories;

    /**
     * @ORM\ManyToOne(targetEntity="CatalogCategory")
     */
    protected $category;

    /**
     * @ORM\Column
     * @InputType(label="Popis", type="textArea")
     * @InputStyle(class="editor")
     */
    protected $description;

    /**
     * @ORM\Column
     */
    protected $image;

    /**
     * @ORM\Column
     */
    protected $photo = null;

    /**
     * @ORM\Column
     */
    protected $variant;

    /**
     * @ORM\OneToMany(targetEntity="CatalogItemVariant", mappedBy="item")
     */
    protected $variants = null;


    /**
     * @ORM\OneToOne(targetEntity="CatalogItemVariant", mappedBy="variant")
     */
    protected $variantsOf = null;


    /**
     * @ORM\Column
     * @InputType(label="Počet kusů", type="text")
     */
    protected $quantity;


    /**
     * @param $item
     * @return mixed
     */
    private static function getVariant($item) {
        return $item->variant;
    }

    /**
     * Get price of Vat
     * @return mixed
     */
    public function getVatPrice()
    {
        return $this->price - $this->priceWithoutVat;
    }

    /**
     * @ORM\OneToMany(targetEntity="CatalogItemAttribute", mappedBy="item")
     */
    protected $attributes = null;


    public function addAttribute(CatalogItemAttribute $attribute)
    {
        $attribute->item = $this;
        $this->attributes[] = $attribute;
    }

    /**
     * Get array of product variants
     * @return array
     */
    public function getVariants() {

        if($this->variant == 0)
        {
            $result = array();

            foreach($this->variants as $variant) {
                $result[] = $variant->variant;
            }

            return $result;
        }

        $variants = isset($this->variantsOf) ? $this->variantsOf->item->getVariants() : array();
        $result = array();

        foreach($variants as $var) {
            if($var->id != $this->id)
               $result[] = $var;
        }

        if(isset($this->variantsOf))
        $result[] = $this->variantsOf->item;
        return $result;
    }

    /**
     * Return array of product attributes, todo !!!!
     * @return array
     */
    public function getAttributes()
    {
        $results = [];

        return $results;
    }

    /**
     * Return array of product attachments, todo !!!!
     * @return array
     */
    public function getAttachments()
    {
        $results = [];

        return $results;
    }

}

CatalogAttribute:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="catalog_attribute")
 */
class CatalogAttribute extends BaseEntity
{
    use \Kdyby\Doctrine\Entities\MagicAccessors;

    /**
     * @ORM\Id
     * @ORM\Column
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column
     */
    protected $type;

    /**
     * @ORM\Column
     */
    protected $title;

    /**
     * @ORM\Column
     */
    protected $value;

    /**
     * @ORM\Column
     */
    protected $unit;

    /**
     * @ORM\OneToMany(targetEntity="CatalogItemAttribute", mappedBy="attribute")
     */
    protected $items;
}

CatalogItemAttribute:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="catalog_item_attributes")
 */
class CatalogItemAttribute
{
    use \Kdyby\Doctrine\Entities\MagicAccessors;

    /**
     * @ORM\Id
     * @ORM\Column
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="CatalogItem", cascade={"persist"})
     * @ORM\JoinColumn(name="id_item", referencedColumnName="id")
     */
    protected $item;

    /**
     * @ORM\OneToOne(targetEntity="CatalogAttribute", inversedBy="items")
     * @ORM\JoinColumn(name="id_attribute", referencedColumnName="id")
     */
    protected $attribute;

    /**
     * @ORM\Column
     */
    protected $value;
}

Nakopnete mě správným směrem prosím?

Proletěl jsem si dokumentaci a už mně to trklo. stačilo do configu přidat cestu k vendoru v doctrine.metadata