PHP code example of milanmadar / coolio-orm

1. Go to this page and download the library: Download milanmadar/coolio-orm library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

milanmadar / coolio-orm example snippets


use Milanmadar\CoolioORM\ORM;
use Milanmadar\CoolioORM\Geo\Shape2D;
use Milanmadar\CoolioORM\Geo\GeoFunctions;
use App\Model\GeometryTest;

$orm = ORM::instance(); // In Symfony, you can autowire `\Milanmadar\CoolioORM\ORM`

$geotestManager = $orm->entityManager( GeometryTest\Manager::class );

//
// Create a new entity (representing a table row), and fill it with data
//
$geotest = $geotestManager
    ->createEntity()
    ->setTitle("My first Geometry enabled Entity")
    ->setDifficulty( 1 )
    ->setPointGeom( new Shape2D\Point(1, 2) )
    ->setLinestringGeom( new LineString([ new Point(1, 1), new Point(2, 2), new Point(3, 3), new Point(4, 4) ], 4326) );

// Save it to the database
$geotestManager->save($geotest);

// Now our Entity has an ID
$geotest->getId(); // 1

//
// Read entities (rows) from the database
//

// Get an entity from the database
$geotest = $geotestManager->findById( 1 );
$geotest->getTitle(); // "My first Geometry enabled Entity"
$geotest->getPointGeom()->getX(); // 1

// Get many entities from the database
$geotests = $geotestManager->findManyWhere("difficult = :Safe_Difficulty_Param", ['Safe_Difficulty_Param'=>1]);
foreach($geotests as $geotest) {
    echo $geotest->getTitle()."\n";
}

//
// QueryBuilder: SELECT
//
$geotests = $geotestManager
    ->createQueryBuilder()
    ->select('title', 'difficulty', 'linestring_geom') // if you want select(*) then you can omit this line
    ->andWhereColumn('difficulty', '=', 1)
    ->andWhereColumn('linestring_geom', '!=', null)
    ->orderBy('difficulty', 'asc')
    ->limit(0, 10)
    ->groupBy('difficulty')
    ->fetchManyEntity() // fetches many entities
;
/* 
There are many fetches, like:
     ->fetchAllAssociative() // fetches all rows as associative array
     ->fetchOneEntity() // fetches 1 entity
You will find them all in the below documentation
*/

//
// Use PostGIS ST_* functions
//
$ST_Distance_expression = GeoFunctions::ST_DWithin(
    'point_geom',
    new LineString([new Point(1, 1, 1), new Point(2, 1, 1), new Point(2, 2, 1), new Point(1, 1, 1)]),
    5
);

$isThatRowWithinDistance = $mgr->createQueryBuilder()
    ->select($ST_Distance_expression)
    ->andWhereColumn('id', '=', 1)
    ->fetchOne();
// $isThatRowWithinDistance is TRUE or FALSE here        

$entitiesWithinDistance = $mgr->createQueryBuilder()
    ->andWhere($ST_Distance_expression)
    ->fetchManyEntity();
foreach($entitiesWithinDistance as $geotestEntity) {
    echo $geotestEntity->getTitle()."\n";
}

//
// Delete the entity
//
$geotestManager->delete($geotest);

use Milanmadar\CoolioORM\ORM;
use App\Model\Shop;
use App\Model\Products;

$orm = ORM::instance(); // In Symfony, you can autowire `\Milanmadar\CoolioORM\ORM`

$shopManager = $orm->entityManager( Shop\Manager::class );
$productManager = $orm->entityManager( Product\Manager::class );

//
// Create a Shop with some Products
//

// Create a new Shop (representing a table row), and fill it with data
$shop = $shopManager
    ->createEntity()
    ->setName('Coolio Shop');
// Save it to the database
$shopManager->save($shop);
    
// Create some products
$products = [];
// One product
$products[] = $productManager
    ->createEntity()
    ->setTitle('Coolio T-shirt')
    ->setShop( $shop ); // Set the shop for the product
// Another product
$products[] = $productManager
    ->createEntity()
    ->setTitle('Coolio Mug')
    ->setShop( $shop ); // Set the shop for the product

// Save each product
foreach($products as $product) {
   $productManager->save($product);
}

// Now all our entity has an IDs
$shop->getId(); // 1
$products[0]->getId(); // 1
$products[1]->getId(); // 2

//
// Read all the products from the shop
// Imagine there are 10.000 products in the shop
//

$shop = $shopManager->findById( 1 );

// Read all Products with the "paging" method, with chunks of 200s
// (Paging means we will increase the LIMIT offset by 200 each time)
$lastOffset = 0;
do {
    $products = $productManager
        ->createQueryBuilder()
        ->andWhereColumn('shop_id', '=', $shop->getId())
        ->orderBy('id', 'asc')
        ->limit($lastOffset, 200) // chunks of 200
        ->fetchManyEntity(); // this gives us an array of Product\Entity objects
    foreach($products as $product) {
        echo $product->getTitle()."\n";
    }
    $lastOffset += 200;
} 
while( !empty($products) );

// Read all Products with the "cursor" method, with chunks of 200s
// (Cursoring means we will read the Products ordered by their ID, always remembering the last ID we read)
// The cursoring is better for large datasets (the database needs to work less)
$lastProductId = 0;
do {
    $products = $productManager
        ->createQueryBuilder()
        ->andWhereColumn('shop_id', '=', $shop->getId())
        ->andWhereColumn('id', '>', $lastProductId)  // from the last ID we already read
        ->orderBy('id', 'asc')
        ->limit(0, 200) // chunks of 200
        ->fetchManyEntity(); // this gives us an array of Product\Entity objects
    foreach($products as $product) {
        $lastProductId = $product->getId(); // remember the last ID we read
        echo $product->getTitle()."\n";
    }
} 
while( !empty($products) );


//
// Delete the shop
//
$shopManager->delete($shop);
// The deletion of the Products happens in the database because of the FOREIGN KEY...ON DELETE CASCADE

#
# EXAMPLE 1: Get the thumbnail picture of a Product
#
namespace App\Model\Product;

use App\Model\Picture;
use Milanmadar\CoolioORM;

class Entity extends CoolioORM\Entity
{
    public function getThumbnail(): Picture\Entity
    {
        return $this->orm->entityManager( Picture\Manager::class )
            ->createQueryBuilder()
            ->andWhereColumn('product_id', '=', $this->getId())
            ->andWhereColumn('type', '=', 'thumbnail')
            ->orderBy('position', 'asc')
            ->limit(0, 1)
            ->fetchOneEntity();
    }
}

#
# EXAMPLE 1: Get the certain special Products of a Shop
#
namespace App\Model\Shop;

use App\Model\Product;
use Milanmadar\CoolioORM;

class Entity extends CoolioORM\Entity
{
    public function getCheapestProduct(): Product\Entity 
    {
        return $this->orm->entityManager( Product\Manager::class )
            // in real life you would probably use the QueryBuilder
            ->findOneWhere("shop_id=? ORDER BY price ASC LIMIT 1", [$this->getId()]);
    }
    
    public function getAllProducts(: array
    {
        return $this->orm->entityManager( Product\Manager::class )
            // in real life you would probably use the QueryBuilder
            ->findManyWhere("shop_id=? ORDER BY position ASC", [$this->getId()]);
    }
}

# catalogs table:
catalogs.id
catalogs.title

# items table:
items.id
items.description
items.catalog_id # Foreign Key to catalogs.id (ON DELETE SET NULL, ON UPDATE CASCADE)

class Catalog
{
  public function getId(): int {...}
  public function setId( int $id ) {...}
  
  public function getTitle(): string {...}
  public function SetTitle( string $title ) {...}
}

class Item
{
  public function getId(): int {...}
  public function setId( $id ) {...}
  
  public function getDescription(): string {...}
  public function setDescription( string $description ) {...}
  
  public function getCatalogId(): int {...}
  public function setCatalogId( int $id ) {...}
  
  // Here is the important part
  public function getCatalog(): Catalog {...}
  public function setCatalog( Catalog $catalogEntity ) {...}
}

// New Catalog, so it doesn't have an ID yet
$catalog = $catalogManager->createEntity();
$catalog->setTitle("Nice catalog");
$catalog->getId(); // catalogs.id=null

// New Item, so it doesn't have a Catalog yet
$item = $itemManager->createEntity();
$item->getCatalog(); // null
$item->getCatalogId(); // items.catalog_id=null

// Let's give to the Item its Catalog
$item->setCatalog( $catalog );

// Well, the Catalog exists, but it wasn't saved yet, so still doesn't have ID
$item->getCatalog(); // Catalog entity
$item->getCatalogId(); // items.catalog_id=null

// Let's save the Catalog now
$catalogManager->save($catalog);
$catalog->getId(); // catalogs.id=123

// And magically, the Item's foreign key has been updated too
$item->getCatalogId(); // items.catalog_id=123

// Let's delete the Catalog
$catalogManager->delete( $catalog );

// And magically, the Item's foreign key has been set to null too
$item->getCatalogId(); // items.catalog_id=null

// Let's change the catalog_id field of the Item
$item->setCatalogId( 5 );

// When we get the Catalog Entity from the Item now, 
// it will fetch that Catalog(id=5) from the db
$anotherCatalog = $item->getCatalog();
$anotherCatalog->getId(); // catalogs.id=5

class Item\Manager { /* ... */ }
class Item\Entity { /* ... */ }

class Catalog\Manager { /* ... */ }
class Catalog\Entity {
    public function getCheapestItem(): ?Item\Entity {
        return $this->orm->entityManager( Item\Manager::class, $this->db )
            // in real life you would probably use the QueryBuilder
            ->findOneWhere("catalog_id=? ORDER BY price ASC LIMIT 1", [$this->getId()]);
    }
    public function getAllItems(int $itemId): array {
        return $this->orm->entityManager( Item\Manager::class, $this->db )
            // in real life you would probably use the QueryBuilder
            ->findManyWhere("catalog_id=? ORDER BY number ASC", [$this->getId()]);
    }
}

public function someFuncInSymfony(CoolioORM\ORM $orm) {
  $userManager = $orm->entityManager( \App\Model\User\Manager::class );
}

$userManager = $orm->entityManager( 
    \App\Model\User\Manager::class,
    $orm->getDbByUrl( 'mysql://user:password@localhost/other_database_name' )  
);

$manager->setDb( 
    $orm->getDbByUrl( 'mysql://user:password@localhost/other_database_name' )
);

$orm = CoolioORM\ORM::instance();
$userManager = $orm->entityManager( \App\Model\User\Manager::class );

use App\Model\OtherModel;
class Manager extends CoolioORM\Manager
{
    public function manipulateOtherModel()
    {
        $otherManager = $this->orm->entityManager(OtherModel\Manager::class);
        $otherEntity = $otherManager->findById(123);
        // ... do something with $otherEntity ...
    }
    
    public function someOtherModel_fromArchives()
    {
        $dbArchive = \Milanmadar\CoolioORM\Utils::getDbByUrl( $_ENV['DB_ARCHIVE'] ) // DB_ARCHIVE is an environmental variable (like in .env)
        $otherManager = $this->orm->entityManager(OtherModel\Manager::class, $dbArchive);
        $otherEntity = $otherManager->findById(123);
        // ... do something with $otherEntity ...
    }
    
    public function someOtherModel_fromTheSameDatabaseAsThis()
    {
        $thisDb = $this->db; // the database of this manager
        $otherManager = $this->orm->entityManager(OtherModel\Manager::class, $thisDb);
        $otherEntity = $otherManager->findById(123);
        // ... do something with $otherEntity ...
    }
}

$entity_1 = $manager->findById( 1 );
$entity_2 = $manager->findById( 1 ); // no db communication, we just get it from the Repo
($entity_1 === $entity_2); // true

$entity_3 = $manager->findOneWhere("id=1"); // no db comm
($entity_1 === $entity_3); // true

$sql = "something='xyz'"; // this also returns 'id'=1 row from the db  
$entity_4 = $manager->findOneWhere($sql); // YES db comm happens because the Entity Repo only skips db when we use the primary `id` field
($entity_1 === $entity_4); // true, because the ORM knows its the same entity (with id=1)

$entity_1 = $manager->findById( 123 );

$entityArr = $manager->findMany("SELECT * FROM tbl"); // select all (including 123 too)
foreach($entityArr as $ent) {
  if($ent->getId() == 123) // this is row with id=123 from the "select all" query
  {
    ($ent === $entity_1) // true 
  }
}

// First, fetch all the items in the catalog (among these there is also Item with id=123)
$itemsFromCatalog = $itemManager->findManyWhere("catalog_id=1");

// Then, unrelated to the previous fetch (somewhere else in the code, e.g. inside some deeply hidden method)
// we change the title of Item with id=123 
$itemToFix = $itemManager->findById( 123 ); // ORM gives us the same Item object it alrady has from the "catalog_id=1" result
$itemToFix->setTitle("I change it!");

// Now, list those we got from the catalog (in the first line)
foreach($itemFromCatalog as $item) {
  echo $item->getTitle()."\n"; // For Item 123 it will echo "I change it!"
}

// In the code you are writing
$itemArr = $itemManager->findManyWhere("catalog_id=100");
foreach($itemArr as $item)
{
  // This next line will only fetch from the db the first time it's called.
  // Every other time it will NOT talk to the db at all,
  // it will just give you the same $shop Entity from the Repo (much faster).
  $shop = $shopManager->findById( $item->getShopId() );
}

$entA = $manager->findById( 1 );
$entB = $manager->findById( 1, true );
($entA === $entB) /// false, because its a different PHP object

// Process all the items (millions) 
$lastId = 0;
do {
  // We fetch 4000 items in each loop
  $sql = "id > :lastId ORDER BY id ASC LIMIT 4000";
  $itemsArr = $itemManager->findManyWhere($sql, ['LastId'=>$lastId]);
  foreach($itemsArr as $item) {
  $lastId = $item->getId();
    // ... process item ...
  }
  
  // Clear the Items cache right now (just because i want to)
  $manager->clearRepository(false);
}
while(count($itemsArr));

# src/Model/Catalog/Manager.php
namespace Model/Catalog;
class Manager extends CoolioORM\Manager
{
    /**
     * @inheritDoc
     * @param Entity $ent
     */
    public function delete(CoolioORM\Entity $ent): void
    {
        if( ! $ent instanceof Entity) {
            throw new \InvalidArgumentException(get_class($this)."::delete() can't delete ".get_class($ent));
        }
        
        // The Catalog has an ID which means it was saved already earlier,
        // so it may have items, so let's delete those items
        if( $ent->getId() ) {
            $itemManager = $this->orm->entityManager( \App\Model\Item\Manager::class );
            $items = $itemManager->findManyWhere('catalog_id = :CatId', ['CatId'=>$ent->getId()]);
            foreach($items as $item) {
                // Delete the Item
                $itemManager->delete( $item );
                
                // Another case could be to set their catalog_id to NULL
                //$item->setCatalog( Null );
                //$itemManager->save( $item );
            }
        }
        
        // Delete the Catalog from the db
        parent::delete($ent);
    }
}

$sqlBldr
    ->select('name, age')
    ->from('persons')
    ->where('age > :Age AND height < :Height')->setParameter('Age', 18)->setParameter('Height', 175)
    ->orWhere('something IN (:ArrayVal)')->setParameter('ArrayVal', ['a','b','c'])
    ->andWhere('name LIKE :Part')->setParameter('Part', '%tom%')
    ->groupBy('category')->addGroupBy('subcategory')
    ->having('children > :ChildNum')->setParameter('ChildNum', 1)
    ->orHaving('married = 1')
    ->andHaving('iq > 115')
    ->orderBy('popularity', 'desc')->addOrderBy('age', 'asc')
    ->limit(0, 100);

->setParameters([
    'Age'=>18,
    'ArrayVal'=>['a','b','c'],
    ... 
]);

$intOrNullValue = $someEntity->getSomething();
$sqlBldr
    // inside the '=' will be changed to 'IS NULL' if $intOrNull value is NULL
    ->whereColumn('field_name_a', '=', $intOrNull)
    // inside the '!=' will be changed to 'IS NOT NULL' if $intOrNull value is NULL
    ->andWhereColumn('field_name_b', '!=', $intOrNull)
    ->orWhereColumn('field_name_c', '=', $intOrNull)
    ->orWhereColumn('field_name_d', '!=', [1,2,3,]); // '!=' converts to 'NOT IN'