When I do a simple query, like finding all users, it returns an empty array.
$users = $em->getRepository('MyApp\\Model\\Entity\\User')->findAll();
However, when I connect to my database manually, using PDO, it finds the data. I am using the ArrayCache method, to make sure it has nothing to do with GAE not having a filesystem. The GAE docs say you can use sys_get_temp_dir(), so I don't think it's my proxies. I'm at a loss for why Doctrine is returning nothing and not throwing any errors as well.
Here is my bootstrap file for my app:
<?php
$baseDir = dirname(dirname(__FILE__));
define('TIMEZONE_OFFSET', \MyApp\Library\Date::getMyTimezoneOffset());
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
// globally used cache driver, in production use APC or memcached
$cache = new Doctrine\Common\Cache\ArrayCache;
// standard annotation reader
$annotationReader = new AnnotationReader;
AnnotationReader::addGlobalIgnoredName('dummy');
AnnotationRegistry::registerFile(__DIR__ . "/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php");
AnnotationRegistry::registerFile(__DIR__ . "/Gedmo/Timestampable/Mapping/Driver/Annotation.php");
AnnotationRegistry::registerAutoloadNamespace("\\MyApp\\Model\\Entity", $baseDir);
$cachedAnnotationReader = new Doctrine\Common\Annotations\CachedReader(
$annotationReader, // use reader
$cache, // and a cache driver
$debug = LOCAL
);
// create a driver chain for metadata reading
$driverChain = new Doctrine\ORM\Mapping\Driver\DriverChain();
// load superclass metadata mapping only, into driver chain
// also registers Gedmo annotations.NOTE: you can personalize it
Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM(
$driverChain, // our metadata driver chain, to hook into
$cachedAnnotationReader // our cached annotation reader
);
// now we want to register our application entities,
// for that we need another metadata driver used for Entity namespace
$annotationDriver = new Doctrine\ORM\Mapping\Driver\AnnotationDriver(
$cachedAnnotationReader, // our cached annotation reader
array(ENTITY_PATH) // paths to look in
);
// NOTE: driver for application Entity can be different, Yaml, Xml or whatever
// register annotation driver for our application Entity namespace
$driverChain->addDriver($annotationDriver, 'MyApp\\Model\\Entity');
// general ORM configuration
$config = new Doctrine\ORM\Configuration;
$config->setProxyDir(sys_get_temp_dir());
$config->setProxyNamespace('Proxy');
$config->setAutoGenerateProxyClasses(Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS); // this can be based on production config.
// register metadata driver
$config->setMetadataDriverImpl($driverChain);
// use our already initialized cache driver
$config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);
// create event manager and hook preferred extension listeners
$evm = new Doctrine\Common\EventManager();
// gedmo extension listeners, remove which are not used
// timestampable
$timestampableListener = new Gedmo\Timestampable\TimestampableListener;
$timestampableListener->setAnnotationReader($cachedAnnotationReader);
$evm->addEventSubscriber($timestampableListener);
// mysql set names UTF-8 if required
$evm->addEventSubscriber(new Doctrine\DBAL\Event\Listeners\MysqlSessionInit());
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => DB_USER,
'password' => DB_PASSWORD,
'dbname' => DB_NAME,
'host' => DB_HOST,
'port' => DB_PORT,
'unix_socket' => DB_UNIX_SOCKET
);
// Finally, create entity manager
$em = Doctrine\ORM\EntityManager::create($dbParams, $config, $evm);
Update
Just for clarity:
This returns an empty array:
$users = $em->getRepository('MyApp\\Model\\Entity\\User')->findAll();
\Doctrine\Common\Util\Debug::dump($users);
And this returns an array with users in it. So confused.
$pdo = $em->getConnection();
$users = $pdo->query('SELECT * FROM user');
var_dump($users->fetchAll());
My issue was that I didn't create a Company in my database and my User entity requires a Company, so Doctrine used an INNER JOIN and thus, no users. Ugh.
Update
See this question: Why does Doctrine2 do an INNER JOIN for findAll()?
Related
Given I have a path to Doctrine migration classes. How could I perform the migration programmatically in Doctrine 2?
I assume there should be a clean way to perform the migration over the API as it could have be done with earlier versions of Doctrine as described here:
http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/migrations.html
As I don't see any answers, I'll try to provide my solution for performing migration programmatically (with code) in doctrine.
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\Configuration\Configuration;
use Doctrine\Migrations\Configuration\Connection\ExistingConnection;
use Doctrine\Migrations\Configuration\Migration\ExistingConfiguration;
use Doctrine\Migrations\DependencyFactory;
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
use Doctrine\Migrations\MigratorConfiguration;
use Doctrine\Migrations\Provider\SchemaProvider;
use Doctrine\Migrations\Version\Direction;
// connection
$dbParams = [
'dbname' => 'database-name',
'user' => 'database-username',
'password' => 'database-password',
'host' => 'hostname',
'port' => 'port',
'driver' => 'pdo_mysql',
];
try {
$connection = DriverManager::getConnection($dbParams);
} catch (\Doctrine\DBAL\Exception $e) {
echo 'Problem connecting to DB. '.$e->getMessage();
die();
}
// configuration - Be careful what namespace you use
$configuration = new Configuration($connection);
$configuration->addMigrationsDirectory('MyAppNamespace\Migrations', __DIR__ . '/../migrations');
// we want the execution of the migration to make changes to the table doctrine_migration_versions - so the system is aware that executed the migration
$storageConfiguration = new TableMetadataStorageConfiguration();
$storageConfiguration->setTableName('doctrine_migration_versions');
$configuration->setMetadataStorageConfiguration($storageConfiguration);
$dependencyFactory = DependencyFactory::fromConnection(
new ExistingConfiguration($configuration),
new ExistingConnection($connection))
);
$planCalculator = $dependencyFactory->getMigrationPlanCalculator();
// which migration to execute / I assume latest /
$latestMigrationVersion = $dependencyFactory->getVersionAliasResolver()->resolveVersionAlias('latest');
// check if we have at least one migration version to execute
if(!$latestMigrationVersion->equals(new Version(0))){
try {
// so we will execute only latest ONE migration, if you need more, just find a way to list them in the first parameter of method getPlanForVersions()
$planUp = $planCalculator->getPlanForVersions(
[$latestMigrationVersion],
Direction::UP
);
$dependencyFactory->getMetadataStorage()->ensureInitialized();
// do the migration
$dependencyFactory->getMigrator()->migrate($planUp, (new MigratorConfiguration())->setAllOrNothing(false));
}catch (Exception $e){
echo 'There were problems during db-migration.'."\n".$e->getMessage()."\n\n";
}
}
Hope it helps another developer to quick start his prototype.
I tried to be detailed about the code, so people do not waste time into figuring out every single dependency.
Asuming you are using Symfony's DoctrineMigrationsBundle
To migrate to the latest available version use:doctrine:migrations:migrate command.
Here are more available commands.
I am working on google datastore. I need to create a Log kind of entity having user entity as its parent. I am using Google-api-php-client library to integrate the api in php. I am succeed in creating entites. To insert an entity I'm using following functions.
/*
*Function to insert the entity into the google datastore.
*/
function google_set_insert($data) {
$field_set = $data['field_set'];
$entity_kind = $data['entity_kind'];
$entity_name = $data['entity_name'];
$entity = google_create_entity($field_set, $entity_kind, $entity_name);
$mutation = new Google_Service_Datastore_Mutation();
$mutation->setInsert($entity);
$req = new Google_Service_Datastore_CommitRequest();
$req->setMode('NON_TRANSACTIONAL');
$req->setMutations($mutation);
return $req;
}
But I am unable to create the ancestor of an entity. Can you please tell me what I am missing?
We recommend using the Google Cloud PHP client library (as long as you are not on GAE Standard).
You need to add the ancestor when you first create the entity, since it cannot be changed once initially written.
use Google\Cloud\Datastore\DatastoreClient;
$datastore = new DatastoreClient();
$key = $datastore->key('Person', 'Bob');
$key->ancestor('Parents', 'Joe');
$entity = $datastore->entity($key, [
'firstName' => 'Bob',
'lastName' => 'Testguy'
]);
echo $entity['firstName']; // 'Bob'
$entity['location'] = 'Detroit, MI';
See more in the documentation for keys.
I have a return object coming from instagram.
I am trying to skate the entire build DB table structure process, I understand Mongo is the ideal DB to use for this task.
I am using the regular instagram libraries https://github.com/cosenary/Instagram-PHP-API
and my test code runs without error.
I don have the PhP PECL mongo libraries installed, I should be good to go.
session_start();
require 'vendor/autoload.php';
use MetzWeb\Instagram\Instagram;
$instagram = new Instagram(array(
'apiKey' => 'xxx',
'apiSecret' => 'xxx',
'apiCallback' => 'http://103.238.173.97/success.php'
));
$accessToken = $instagram->getAccessToken();
$_SESSION['InstagramAccessToken'] = $accessToken;
$instagram->setAccessToken($_SESSION['InstagramAccessToken']);
$popular = $instagram->getPopularMedia();
// After getting the response, let's iterate the payload
var_dump($popular);
added just now:
$conn = new MongoClient('mongodb://localhost/?w=1');
$db = $conn->instagram;
// access collection
$collection = $db->instagram1;
$collection->insert($popular);
How would I construct a PDO query to 'autobuild' the table structure just like the JSON object at reply from my request?
instagram JSON object
Repaste of object. Most got cut off due to size
Update:
I tried to insert straight into a collection, I get no error but the DB is still the same size
show dbs
Data 0.078GB
admin (empty)
instagram 0.078GB
local 0.078GB
test 0.078GB
week1 (empty)
I use a file based cache to cache a paginator:
$table = $this->getDbTable();
$ret = $table ->select()
->from($table,array('id',
'UNIX_TIMESTAMP(`date`) as date',
'categoryId',
'title',
'teaser'))
->where('`categoryId`=?',$cat)
->order('date desc');
$adapter = new Zend_Paginator_Adapter_DbTableSelect($ret);
$paginator = new Zend_Paginator($adapter);
$fO = array('lifetime' => 3600, 'automatic_serialization' => true);
$bO = array('cache_dir'=>APPLICATION_PATH . '/cache');
$cache = Zend_cache::factory('Core', 'File', $fO, $bO);
Zend_Paginator::setCache($cache);
$paginator->setItemCountPerPage(5);
$paginator->setCurrentPageNumber($page);
$this->view->paginator = $paginator;
Now every request, the paginator creates a neew cache entry and ignors the old one created? Any ideas?
I had some similar problems with Zend_Paginator. These problems only come with Zend_Paginator_Adapter_DbTableSelect (I had no problems with Zend_Paginator_Adapter_Array).
The bolded part of the cache filename zend_cache---Zend_Paginator_3_2b49905a9282f742e1cefafc53892794 is made by _getCacheId function (check Zend_Paginator) based on the adapter passed to the constructor. On each request, the paginator creates a new code because the adapter is never the same at the $_cache->load moment and $_cache->save moment.
The md5 serialized value of the adapter used as filename when data is saved into cache is different from the one used when data is read from cache if you have DB profiler enabled. You must not use DB profiler in order for the Zend_Paginator cache to work (use it only in development stage).
Another failure reason that I have found is determined by these two lines of code:
$offset = ($pageNumber - 1) * $this->getItemCountPerPage();
$items = $this->_adapter->getItems($offset, $this->getItemCountPerPage());
They are called between $_cache->load and $_cache->save and they add a limitcount value and a limitoffset value to adapter. This values aren't set when $_cache->load is called so the filename based on the md5 serialized value of the adapter will be different in this case too.
They must be placed before $_cache->load. You can make a paginator class that extends Zend_Paginator and modify getItemsByPage function. Add the two lines at the beggining, after $pageNumber = $this->normalizePageNumber($pageNumber).
This worked for me. I hope it will help others too.
I need to update an application which is built on Zend Framework.
Most of the text is hard-coded in views scripts, forms, etc.
The application will be available in say, 3 languages AND is language specific (the content is not the same for all) and will have one domain per language (ie: mygreatsite.com, monsupersite.com, ilmiosupersite.com, etc.)
First question:
What is the best way to "handle" this kind of application?
I can imagine several solution like:
One copy per language, using different db, etc... (probably not the best way for maintenance)
Only one application, handling different content, db, etc, depending on the locale (based on the route)
Second question:
What should I need to know about the existing code to start the "migration"?
What about any best practice when building a i18n website?
What are the best adapter? (I already used gettext() and I think it's the best)
I am by no means an expert but this is what I do.
I use array as my translation adapter because it’s easier for my clients to update as they are just regular Joes. And I use translation keys instead of sentences. For example
Some people would use
$this->translate(‘Some sentence to translate’);
I use
$this->translate(‘default-index-dashboard-title’);
This makes it far easier for me to know where the text I’m looking for is to change. I don’t know if there are any advantages other than that though.
You will need to setup your translation adapter and translation cache (if you want) in your bootstrap. I do mine like this:
protected function _initLocale()
{
$locale = new Zend_Locale(Zend_Locale::BROWSER);
$config = Zend_Registry::get('config');
Zend_Registry::set('Zend_Locale', $locale->toString());
return $locale;
}
protected function _initTranslation()
{
try{
$translate = new Zend_Translate(array('adapter' => 'array', 'content' => ROOT . '/callmanagement/languages/' . strtolower(Zend_Registry::get('Zend_Locale')) . '.php'));
}catch(Exception $e){
$translate = new Zend_Translate(array('adapter' => 'array', 'content' => ROOT . '/callmanagement/languages/en_gb.php'));
}
Zend_Registry::set('Zend_Translate', $translate);
return $translate;
}
I would use a single code base unless the sites are completely different and store the shared data in one database and have other databases for the site specific stuff.
You can setup multiple db adapters either in the bootstrap or in the congfig.
$dbLocal = new Zend_Db_Adapter_Pdo_Mysql(array(
'host' => 'localhost',
'username' => $result['user'],
'password' => $result['password'],
'dbname' => $result['database']
));
Zend_Db_Table_Abstract::setDefaultAdapter($dbLocal);
$dbShared = new Zend_Db_Adapter_Pdo_Mysql(array(
'host' => 'localhost',
'username' => ‘root’,
'password' => 'pass',
'dbname' => 'dbname'
));
Zend_Registry::set('db_local', $dbLocal);
Zend_Registry::set('db_shared', $dbShared);
return $dbLocal;
You can get Zend Form to translate for you just put your translation key into the label field.
$this->addElement(‘text’, ‘test’, array(‘label’ => ‘translation-key’, ‘required’ => true)); etc.
Then if you are using Zend_Db_Table_Abstract classes you can change the default schema and database connection like this:
class Default_Model_Table_Topics extends Zend_Db_Table_Abstract
{
protected $_name = 'topics';
protected $_id = 'topic_id';
protected $_rowClass = 'Default_Model_Topic';
protected $_schema = 'dbname';
protected $_adapter = 'db_shared';
}
If you need any more examples I’ll try and help.