tiny ‘n’ smart
database layer

Odkazy: dibi | API reference

Oznámení

Omlouváme se, provoz fóra byl ukončen

Lean Mapper – výchozí řazení v proměnné typu m:belongsToMany

před 6 lety

svezij
Člen | 69

Ahojte, nerad přidávám příspěvky do vlákna Lean Mapper – tenké ORM nad dibi, protože mi přijde, že se tam řeší důležité věci ohledně Lean Mapperu a nechci tam obtěžovat takovými maličkostmi. Proto se omlouvám, měl-li bych tento dotaz vložit právě tam.
Mám entitu výrobku, která obsahuje obrázky výrobku:

/**
 * @property int $id
 * ...
 * @property ProductImage[] $images m:belongsToMany(:product_images)
 * ...
 */
class Product extends \LeanMapper\Entity
{
}

Všechno funguje tak, jak má, ale tabulka product_images obsahuje sloupec sequence, který je typu „integer“ a udává řazení obrázků. Jak Lean Mapper „donutit“, aby mi obrázky z tabulky product_images stahoval do proměnné $images v pořadí ORDER BY sequence ASC? Tzn.:
Tabulka:

id | product | filename | sequence
----------------------------------
1  | 1       | obr1.jpg | 1
2  | 1       | obr2.jpg | 3
3  | 1       | obr3.jpg | 2

Kód:

$repository = getProductRepository();
$product = $repository->find(1);

foreach ($product->images as $image) {
  echo $image->file . '<br />';
}

Chtěl bych, aby vypsalo:

obr1.jpg
obr3.jpg
obr2.jpg

ale samozřejmě vypíše:

obr1.jpg
obr2.jpg
obr3.jpg

Jak to mám vyřešit? Děkuji :-).

před 6 lety

svezij
Člen | 69

Tak zatím jsem to „zvládl“ přes vlastní getter.

/**
 * Getter of images
 *
 * @return ProductImage[]
 */
public function getImages()
{
  $value = array();
  foreach ($this->row->referencing('product_images', 'product_id') as $row) {
    $value[] = new ProductImage($row->referenced('product_images', 'id'));
  }

  usort($value, function($a, $b) {
    return (($a->sequence == $b->sequence) ? 0 : (($a->sequence < $b->sequence) ? -1 : 1));
  });

  return $value;
}

Je to správné řešení, nebo existuje jiné, lepší?

před 6 lety

Casper
Člen | 253

Použij filtr.

Entita:

/**
 * @property ProductImage[] $images m:belongsToMany(:product_images) m:filter(sortImages)
 */
class Product extends \LeanMapper\Entity{}

config.neon

services:
    myFilter: Model\Filter\MyFilter

    connection:
        class: LeanMapper\Connection(%database%)
        setup:
            - registerFilter('sortImages', [@myFilter, 'sortImages'])

Filtr:

class MyFilter {
    public function sortImages(\LeanMapper\Fluent $statement){
        $statement->orderBy("sequence ASC");
    }
}

před 6 lety

Tharos
Člen | 1042

Použití filtru je best practice.

Ke Casperovo odpovědi jenom dodám, že filtr může být i obecnější (a univerzálnější) s „natvrdo“ vepsaným parametrem v anotaci, což bych zde asi volil:

/**
 * @property ProductImage[] $images m:belongsToMany(:product_images) m:filter(sort#sequence)
 */
class Product extends \LeanMapper\Entity
{
}
$connection->registerFilter('sort', function(Fluent $statement, $column) {
    $statement->orderBy($column);
});

před 6 lety

svezij
Člen | 69

Ahojte, mockrát děkuji za odpověď, chtěl jsem to takto provést, ale nevím, kde registrovat ten filter. Zkoušel jsem ho registrovat v konstruktoru repozitáře, ale laděnka píše:

Filter with name 'sort' was already registered.

Systém s LeanMapperem spojuji v bootstrap.php:

// LeanMapper connection registration
$configurator->onCompile[] = function($configurator, Nette\Config\Compiler $compiler) {
  $compiler->addExtension('dibi', new LeanMapperConnectionExtension());
};

a třída LeanMapperConnectionExtension se liší od DibiNette20Extension tím, že volám:

$connection = $container->addDefinition($this->prefix('connection'))
                        ->setClass('LeanMapper\Connection', array($config));

místo:

$connection = $container->addDefinition($this->prefix('connection'))
                        ->setClass('DibiConnection', array($config));

Kde mám tedy zavolat

$connection->registerFilter('sort', function(Fluent $statement, $column) {
    $statement->orderBy($column);
});

?

Ještě jednou moc děkuji.

před 5 lety

medhi
Bronze Partner | 189

Také bych se přimlouval za odpověď. Jak v Nette registrovat takový filtr, pokud mám Lean Mapper v configu jako extension?

Díky

Editoval medhi (29. 8. 2014 16:22)

před 5 lety

Tharos
Člen | 1042

Ahoj,

já poslední dobou registruji filtry následovně:

<?php

namespace SomeProject\LeanMapper\DI;

use LeanMapper\Connection;
use Nette\DI\CompilerExtension;
use Nette\PhpGenerator\ClassType;
use SomeProject\LeanMapper\IFiltersConfigurator;

/**
 * @author Vojtěch Kohout
 */
class LeanMapperExtension extends CompilerExtension
{

    public function loadConfiguration()
    {
        $container = $this->getContainerBuilder();
        $config = $this->getConfig();

        $useProfiler = isset($config['profiler'])
            ? $config['profiler']
            : class_exists('Tracy\Debugger') && $container->parameters['debugMode'];

        unset($config['profiler']);

        if (isset($config['flags'])) {
            $flags = 0;
            foreach ((array) $config['flags'] as $flag) {
                $flags |= constant($flag);
            }
            $config['flags'] = $flags;
        }

        $connection = $container->addDefinition($this->prefix('connection'))
            ->setClass('LeanMapper\Connection', [$config]);

        if ($useProfiler) {
            $panel = $container->addDefinition($this->prefix('panel'))
                ->setClass('Dibi\Bridges\Tracy\Panel');
            $connection->addSetup([$panel, 'register'], [$connection]);
        }
    }


    /**
     * @param ClassType $class
     */
    public function afterCompile(ClassType $class)
    {
        $initialize = $class->methods['initialize'];
        $initialize->addBody('$this->getByType("' . IFiltersConfigurator::class . '")->setUpFilters($this->getByType("' . Connection::class . '"));');
    }

}
<?php

namespace SomeProject\LeanMapper;

use LeanMapper\Connection;

/**
 * @author Vojtěch Kohout
 */
interface IFiltersConfigurator
{

    function setUpFilters(Connection $connection);

}
<?php

namespace SomeProject\LeanMapper;

use SomeProject\LeanMapper\Query\IQuery;
use SomeProject\LeanMapper\Query\QueryUsingEntityReflection;
use LeanMapper\Connection;
use LeanMapper\Exception\InvalidArgumentException;
use LeanMapper\Fluent;
use LeanMapper\IMapper;
use LeanMapper\Reflection\Property;

/**
 * @author Vojtěch Kohout
 */
class FiltersConfigurator implements IFiltersConfigurator
{

    /**
     * @param Connection $connection
     */
    public function setUpFilters(Connection $connection)
    {
        $connection->registerFilter(...);
    }

}

Možností je vážně celá řada. Mně se líbí, když existuje nějaký konfigurátor (FiltersConfigurator) a v extenzi, která Lean Mapper integruje do projektu, se dá velmi pohodlně využít.

Editoval Tharos (2. 9. 2014 23:31)