Currently I am writing a website using Kohana framework 3.3. Today, I wanted to create subpage where user would be able to browse news, however I encountered a small problem with Kohana ORM.
I would like to retrieve only a dozen / several dozen characters from a text field, because loading the entire field would be a significant waste of server resources.
Does anyone know how I can achieve the same effect as in those cases?
↓ MySQL/SQL retrieve first 40 characters of a text field?
(preffered) http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_left
How to select only some characters from MySQL field?
Thanks in advance for your answers.
This isn't possible with the ORM class. You can build your own query with Kohana's own query builder and the object can be returned as an ORM-model, therefore you fill in your ORM model name (e.g. 'my_orm_model') in the as_object function.
Combining one of your suggested links with Kohana's own Query builder you would get something like this.
DB::Query(Database::SELECT,"SELECT LEFT(field, 40) AS excerpt FROM table(s) WHERE ...")->as_object('my_orm_class')->execute();
Looking at the code behind ORM, it seems it's not possible to load a partial model. You may have to use the Database_Query_Builder class, combined with DB::expr to achieve this.
ORM was designed for working with a whole records (queries like SELECT * FROM ...). You can store fulltext values in separated (MyISAM) table, so your ORM models will skip that field.
Related
I have an old db under my application where not all relations are actually SQL relations, but some of them are stored in a string column.
Ex.
Tables: Tags, Articles
Table Articles has 'tags_ids' column where I have '33;44;82;' (the tag ids)
I would like to know if I can use the Laravel Backpack relationships UI with this kind of data.
I surely will have to "mutate" the data during the get and the set, but I can't find a way to do it.
I dont think laravel supports something like that directly as a relationship.
You could certainly write a custom column template in backpack that would explode $entry->tags_ids on ;, query Tags for those ids and then display them in a loop.
That said, IMHO, you'd be much better of adding an intermediate table like article_has_tag to map your tags and articles properly, then you could use all the built in features of laravel and backpack normally. If you still need the old application to work with the original data structure, you could write an "after insert/update" trigger for the articles and article_has_tag tables to keep them in sync (being careful to not cause an infinite loop of course).
I am currently working on a huge refactoring project. We have taken over a classic PHP/MySQL project, where most code is procedural, duplicated, and there is very little hint of an architecture.
I am planning on using Doctrine to handle our Data Access, and have all of my tables mapped to entities. However, our MySQL tables are largely messed up.
The table I am currently working with has over 40 columns, and is not normalized by any means. A quick example of what we have:
Brand
id
name
poNumber
orderConfirmationEmail <---- these should go into a BrandConfirmations entity
shippingConfirmationEmail <-----
bill_address <---- these should go into a BrandAddress entity
bill_address2 <-----
city <------
.
.
.
Ideally, what I would like to have is for Doctrine to pull out the fields that reference different Entities, and actually put them into those Entities. So for instance id, name, and poNumber would get pulled out into a Brand entity. orderConfirmationEmail and shippingConfirmationEmail would get pulled out into a BrandNotification entity. Next, bill_address, and the rest of the address fields would get pulled out into a BrandBillAddress entity. Is there a way to configure Doctrine to split the table into these models for me, or do I have to custom write code myself that would do that?
If I do have to write the code to split this table myself, do you have any resources or advice that tackle a similar issue? I haven't been able to find many yet.
The latest version of Doctrine 2 supports what they call embeddables: http://doctrine-orm.readthedocs.org/en/latest/tutorials/embeddables.html. It may solve some of your problems. However, it requires D2.5+. Currently, S2 uses Doctrine 2.4. You could experiment with using the very latest doctrine.
What you can do is make your domain models (entities) act as though you had value objects. So $brand->getOrderConfirmation() would actually return an order confirmation object. You have to do some messing around to keep everything mapped to one table and you might be limited on some of your queries but it's not that hard. The advantage is that the rest of your new applications deals with proper normalized objects. It's only the internal persistence code that needs to get messy.
There are quite a few links on this approach. Here is one: http://russellscottwalker.blogspot.com/2013/11/entities-vs-value-objects-and-doctrine-2.html
Your best bet of course is to refactor your database schema. I like to do kind of a raw dump of the original database into a yaml file with the desired object nesting. I then load the yaml file into the new schema. If you are really lucky then you might even be able to create new views for your existing application which will allow it to keep working in parallel with your new application.
Symfony ACL allows me to grant access to an entity, and then check it:
if (false === $securityContext->isGranted('EDIT', $comment)) {
throw new AccessDeniedException();
}
However, if I have thousands of entities in the database and the user has access only to 10 of them, I don't want to load all the entities in memory and hydrate them.
How can I do a simple "SELECT * FROM X" while filtering only on the entities the user has access (at SQL level)?
Well there it is: it's not possible.
In the last year I've been working on an alternative ACL system that would allow to filter directly in database queries.
My company recently agreed to open source it, so here it is: http://myclabs.github.io/ACL/
As pointed out by #gregor in the previous discussion,
In your first query, get a list (with a custom query) of all the object_identity_ids (for a specific entity/class X) a user has access to.
Then, when querying a list of objects for entity/class X, add "IN (object_identity_ids)" to your query.
Matthieu, I wasn't satisfied by replying with more of conjectures (since my conjectures don't add anything valuable to the conversation). So I did some bench-marking on this approach (Digital Ocean 5$/mo VPS).
As expected, table size doesn't matter when using the IN array approach. But a big array size indeed makes things get out of control.
So, Join approach vs IN array approach?
JOIN is indeed better when the array size is huge. BUT, this is assuming that we shouldn't consider the table size. Turns out, in practice IN array is faster - except when there's a large table of objects and the acl entries cover almost every object (see the linked question).
I've expanded on my reasoning on a separate question. Please see When using Symfony's ACL, is it better to use a JOIN query or an IN array query?
You could have a look into the Doctrine filters. That way you could extend all queries. I have not done this yet and there are some limitations documented. But maybe it helps you. You'll find a description of the ACL database tables here.
UPDATE
Each filter will return a string and all those strings will be added to the SQL queries like so:
SELECT ... FROM ... WHERE ... AND (<result of filter 1> AND <result of filter 2> ...)
Also the table alias is passed to the filter method. So I think you can add Subqueries here to filter your entities.
Is there a best practice in getting data from multiple database tables using Zend? I would like to know rather than end up wanting to refactor the code I write in the near future. I was reading the Zend documentation and it said that:
"You can not specify columns from a
JOINed tabled to be returned in a
row/rowset. Doing so will trigger a
PHP error. This was done to ensure
the integrity of the Zend_Db_Table is
retained. i.e. A Zend_Db_Table_Row
should only reference columns derived
from its parent table."
I assume I therefore need to use multiple models -- is that correct? If, for example, I want to get out all orders for a particular user id where the date is in between two dates what would I do?
I know that it would be possible to access the two different models from a controller and then combine their respective data in the action but I would not feel happy doing this since I have been reading survivethedeepend.com and it tells me that I shouldn't do this...
Where, why, and how? :)
Thanks!
If you're reading ZFSTDE, in chapter 9 (http://www.survivethedeepend.com/zendframeworkbook/en/1.0/implementing.the.domain.model.entries.and.authors) this problem is addressed by using a data mapper.
Also, you can join 2 tables, just be sure to first call on the select object the setIntegrityCheck(false) method. The docs say that a row should reference a parent table, doesn't mean it can not :)
Stop thinking about Zend_Db_Table as your "model".
You should write your own, rich, domain-centric model classes to sit between your controllers (and views), and your persistence logic (anything that uses Zend_Db/Zend_Db_Table/Zend_Db_Select) to load/store data from the database.
Sure, you can query several db tables at the same time. Take a look at the official ZF docs here http://framework.zend.com/manual/en/zend.db.select.html#zend.db.select.building.join
As for your example with getting all orders of a single user, table relationships are the answer http://framework.zend.com/manual/en/zend.db.table.relationships.html
I have 3 database tables:
article
article_has_tag (2 FK's to the other tables)
tag
I currently show a list of articles with the article's tags shown underneath but the number of queries grows as the list gets longer.
I want to loop over all the articles and get the tag objects from each one in turn.
Can it be done in 1 propel query?
I believe you are using symfony 1.0 and thus Propel 1.2... Whilst the methods already described in the comments talk about alternative methods, there is a direct way to at least solve your problem: add this function to your ArticlePeer class:
public static function getTaggedArticles()
{
$c = new Criteria();
//some filters here, e.g. LIMIT or Criteria::IN array
$ahts = ArticleHasTagPeer::doSelectJoinAll($c);
$articles = array();
foreach($ahts as $aht)
{
if(!isset($articles[$aht->getArticleId()]))
{
$articles[$aht->getArticleId()] = $aht->getArticle();
}
$articles[$aht->getArticleId()]->addTag($aht->getTag());
}
return $articles;
}
where $ahts is short for $article_has_tags. Create a simple array of tags in your Article class (protected array $collTags) along with the addTag() method, if they don't already exist to facilitate this.
This then only executes one SQL query, but consider seriously that without the filter I mention you are potentially hydrating hundreds of objects unnecessarily, and that is a significant performance hit. You may want to research how to hydrate based only on a doSelectRS() call - inspect your BlahPeer classes for how their JOIN methods work, and then this link for how to write custom JOIN methods.
Either way, the method builds a unique array of articles with the ArticleId as the key - if you need a different sort order, you can either sort this array again or use a different array key to organise the collection as you build it.
Unless I'm misunderstanding your question, don't loop over anything as you'll generate bloat of a different kind.
Do a single query where "article" is joined to "article_has_tag" is joined to "tag". The single query should return the specified articles and tag names for the tags they have.
I use Doctrine myself so can't help you with the exact query but Googling brings up stuff like this: http://www.tech-recipes.com/rx/2924/symfony_propel_how_to_left_join/.
Also, the symfony definitive guide (which was written for Propel) should be able to help you.
I assume you are using Propel 1.3 or 1.4, and not yet Propel 1.5 (which is still in beta), as the latter has a very natural support for these multiple joins (inspired, in part, by the Doctrine syntax).
If you defined your foreign keys in the database schema, you should have a static doSelectJoinByAll method in the ArticleHasTagPeer class. If you use this method, the related Article and Tag objects will be hydrated with the same query. You can still pass in a Criteria object that modifies the Article and Tag selection criteria. I know this is a bit strange, since you probably want to start from the Article objects, and this was one of the driving factors for the change in Propel 1.5. In Symfony you can also use the DbFinderPlugin, this will already give you this capability in Propel 1.3 (it needs a small patch for Propel 1.4). In fact, Propel 1.5 is mostly written by François Zaniotto, the author of the DbFinderPlugin.
Short answer is no.
But with some efforts you still can do that. Here's list of options:
Use dbFinderPlugin plugin
Write your own peer method (say, doSelectPostWithUsersAndComments).
Migrate to Propel 1.5
Migrate to Doctrine